diff --git a/.changeset/angry-badgers-beg.md b/.changeset/angry-badgers-beg.md new file mode 100644 index 0000000000..38952aef98 --- /dev/null +++ b/.changeset/angry-badgers-beg.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-app-api': patch +--- + +Internal update for removal of experimental plugin configuration API. diff --git a/.changeset/angry-clocks-exercise.md b/.changeset/angry-clocks-exercise.md new file mode 100644 index 0000000000..e7eb6ae1d9 --- /dev/null +++ b/.changeset/angry-clocks-exercise.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-nomad-backend': patch +--- + +Added support for the [new backend system](https://backstage.io/docs/backend-system/) diff --git a/.changeset/big-spies-beam.md b/.changeset/big-spies-beam.md new file mode 100644 index 0000000000..e5f0ad3eff --- /dev/null +++ b/.changeset/big-spies-beam.md @@ -0,0 +1,5 @@ +--- +'@backstage/create-app': patch +--- + +Removed duplicate `apple-touch-icon` link from `packages/app/public/index.html` that linked to nonexistent icon. diff --git a/.changeset/breezy-dryers-thank.md b/.changeset/breezy-dryers-thank.md new file mode 100644 index 0000000000..7a742db1bf --- /dev/null +++ b/.changeset/breezy-dryers-thank.md @@ -0,0 +1,10 @@ +--- +'@backstage/backend-tasks': patch +--- + +Instrument `backend-tasks` with some counters and histograms for duration. + +`backend_tasks.task.runs.count`: Counter with the total number of times a task has been run. +`backend_tasks.task.runs.duration`: Histogram with the run durations for each task. + +Both these metrics have come with `result` `taskId` and `scope` labels for finer grained grouping. diff --git a/.changeset/calm-carpets-kiss.md b/.changeset/calm-carpets-kiss.md new file mode 100644 index 0000000000..b946e4d9c6 --- /dev/null +++ b/.changeset/calm-carpets-kiss.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-common': patch +--- + +The `HostDiscovery` export has been deprecated, import it from `@backstage/backend-app-api` instead. diff --git a/.changeset/calm-scissors-rescue.md b/.changeset/calm-scissors-rescue.md new file mode 100644 index 0000000000..4a5318d240 --- /dev/null +++ b/.changeset/calm-scissors-rescue.md @@ -0,0 +1,5 @@ +--- +'@backstage/create-app': patch +--- + +Create unique temp directory for each `create-app` execution. diff --git a/.changeset/clean-forks-love.md b/.changeset/clean-forks-love.md new file mode 100644 index 0000000000..f81fe3066b --- /dev/null +++ b/.changeset/clean-forks-love.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-sonarqube-backend': patch +--- + +Added support for the [new backend system](https://backstage.io/docs/backend-system/) diff --git a/.changeset/cold-bees-jam.md b/.changeset/cold-bees-jam.md new file mode 100644 index 0000000000..3c6e652d2b --- /dev/null +++ b/.changeset/cold-bees-jam.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-org': patch +--- + +Fixed the display of OwnershipCard with aggregated relations by loading relations when getting children of entity. +This allows the already existing recursive method to work properly when children of entity have children themselves. diff --git a/.changeset/cold-seas-repeat.md b/.changeset/cold-seas-repeat.md new file mode 100644 index 0000000000..0072c4327d --- /dev/null +++ b/.changeset/cold-seas-repeat.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-code-coverage': patch +--- + +Fixed the coverage history statistics to compare newest with oldest record diff --git a/.changeset/dull-dolls-explode.md b/.changeset/dull-dolls-explode.md new file mode 100644 index 0000000000..10088e0818 --- /dev/null +++ b/.changeset/dull-dolls-explode.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-playlist-backend': patch +--- + +Added support to the playlist plugin for the new backend diff --git a/.changeset/dull-laws-camp.md b/.changeset/dull-laws-camp.md new file mode 100644 index 0000000000..9a9c7436c5 --- /dev/null +++ b/.changeset/dull-laws-camp.md @@ -0,0 +1,7 @@ +--- +'@backstage/create-app': patch +--- + +Change base node image from node:18-bullseye-slim to node:18-bookworm-slim due to Docker build error on bullseye. + +You can apply these change to your own `Dockerfile` by replacing `node:18-bullseye-slim` with `node:18-bookworm-slim` diff --git a/.changeset/eight-melons-cough.md b/.changeset/eight-melons-cough.md new file mode 100644 index 0000000000..23d7b901f1 --- /dev/null +++ b/.changeset/eight-melons-cough.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog': patch +--- + +Create an experimental `CatalogSearchResultItemExtension` for declarative integration with Backstage; it can be accessed via the `/alpha` import. diff --git a/.changeset/eighty-actors-type.md b/.changeset/eighty-actors-type.md new file mode 100644 index 0000000000..5c55a7b0c6 --- /dev/null +++ b/.changeset/eighty-actors-type.md @@ -0,0 +1,5 @@ +--- +'@backstage/test-utils': patch +--- + +Removed the alpha `MockPluginProvider` export since the plugin configuration API has been removed. diff --git a/.changeset/fair-frogs-enjoy.md b/.changeset/fair-frogs-enjoy.md new file mode 100644 index 0000000000..12eb57489e --- /dev/null +++ b/.changeset/fair-frogs-enjoy.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs': patch +--- + +Create an experimental `TechDocsSearchResultItemExtension` for declarative integration with Backstage; it can be accessed via the `/alpha` import. diff --git a/.changeset/flat-pandas-tan.md b/.changeset/flat-pandas-tan.md new file mode 100644 index 0000000000..dfe7965bec --- /dev/null +++ b/.changeset/flat-pandas-tan.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-test-utils': patch +--- + +Added `createMockDirectory()` to help out with file system mocking in tests. diff --git a/.changeset/four-onions-clap.md b/.changeset/four-onions-clap.md new file mode 100644 index 0000000000..44d0cf9ae7 --- /dev/null +++ b/.changeset/four-onions-clap.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Fix for the new backend `start` command to make it work on Windows. diff --git a/.changeset/four-pans-sin.md b/.changeset/four-pans-sin.md new file mode 100644 index 0000000000..46d31c242c --- /dev/null +++ b/.changeset/four-pans-sin.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +Marked the `LocationEntityProcessor` as deprecated, as it is no longer used internally since way back and can even be harmful at this point. diff --git a/.changeset/fresh-badgers-study.md b/.changeset/fresh-badgers-study.md new file mode 100644 index 0000000000..4c9e7ee627 --- /dev/null +++ b/.changeset/fresh-badgers-study.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-app-api': patch +--- + +Wrap entire app in ``, enabling support for using translations outside plugins. diff --git a/.changeset/fresh-kangaroos-tap.md b/.changeset/fresh-kangaroos-tap.md new file mode 100644 index 0000000000..5ac4d184eb --- /dev/null +++ b/.changeset/fresh-kangaroos-tap.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-plugin-api': minor +--- + +Removed the exprimental plugin configuration API. The `__experimentalReconfigure()` from the plugin options as well as the `__experimentalConfigure()` method on plugin instances have both been removed. diff --git a/.changeset/gentle-elephants-fold.md b/.changeset/gentle-elephants-fold.md new file mode 100644 index 0000000000..480ee41e7a --- /dev/null +++ b/.changeset/gentle-elephants-fold.md @@ -0,0 +1,20 @@ +--- +'@backstage/plugin-catalog': minor +--- + +The catalog plugin no longer implements the experimental reconfiguration API. The create button title can now instead be configured using the new experimental internationalization API, via the `catalogTranslationRef` exported at `/alpha`. For example: + +```ts +import { catalogTranslationRef } from '@backstage/plugin-catalog/alpha'; + +const app = createApp({ + __experimentalTranslations: { + resources: [ + createTranslationMessages({ + ref: catalogTranslationRef, + catalog_page_create_button_title: 'Create Software', + }), + ], + }, +}); +``` diff --git a/.changeset/gentle-spies-deny.md b/.changeset/gentle-spies-deny.md new file mode 100644 index 0000000000..f2d0ea7d79 --- /dev/null +++ b/.changeset/gentle-spies-deny.md @@ -0,0 +1,14 @@ +--- +'@backstage/plugin-catalog-backend-module-bitbucket-server': patch +'@backstage/plugin-catalog-backend-module-bitbucket-cloud': patch +'@backstage/plugin-catalog-backend-module-puppetdb': patch +'@backstage/plugin-catalog-backend-module-msgraph': 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-azure': patch +'@backstage/plugin-catalog-backend-module-ldap': patch +'@backstage/plugin-catalog-backend-module-aws': patch +--- + +Make sure to include the error message when ingestion fails diff --git a/.changeset/great-walls-brake.md b/.changeset/great-walls-brake.md new file mode 100644 index 0000000000..dd71c81a07 --- /dev/null +++ b/.changeset/great-walls-brake.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-common': patch +--- + +Properly close write stream when writing temporary archive for processing zip-based `.readTree()` responses. diff --git a/.changeset/happy-books-smoke.md b/.changeset/happy-books-smoke.md new file mode 100644 index 0000000000..68ea19ea5e --- /dev/null +++ b/.changeset/happy-books-smoke.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-home': patch +--- + +Adds Top/Recently Visited components to homepage diff --git a/.changeset/heavy-forks-tie.md b/.changeset/heavy-forks-tie.md new file mode 100644 index 0000000000..f5af5975b7 --- /dev/null +++ b/.changeset/heavy-forks-tie.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-node': patch +--- + +Added docs to `processingResult` diff --git a/.changeset/itchy-bobcats-fly.md b/.changeset/itchy-bobcats-fly.md new file mode 100644 index 0000000000..e91d944478 --- /dev/null +++ b/.changeset/itchy-bobcats-fly.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-common': patch +--- + +Added the ability to fetch git tags through the `Git` class. This is useful for scaffolder actions that want to take action based on tag versions in a cloned repository diff --git a/.changeset/itchy-monkeys-reply.md b/.changeset/itchy-monkeys-reply.md new file mode 100644 index 0000000000..3773fe3ff8 --- /dev/null +++ b/.changeset/itchy-monkeys-reply.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-dev-utils': patch +--- + +Fix an issue where early IPC responses would be lost. diff --git a/.changeset/itchy-rabbits-exist.md b/.changeset/itchy-rabbits-exist.md new file mode 100644 index 0000000000..acac771a97 --- /dev/null +++ b/.changeset/itchy-rabbits-exist.md @@ -0,0 +1,7 @@ +--- +'@backstage/cli': minor +--- + +The new backend start command that used to be enabled by setting `EXPERIMENTAL_BACKEND_START` is now the default. To revert to the old behavior, set `LEGACY_BACKEND_START` instead. + +This new command is no longer based on Webpack, but instead uses Node.js loaders to transpile on the fly. Rather than hot reloading modules the entire backend is now restarted on change, but the SQLite database state is still maintained across restarts via a parent process. diff --git a/.changeset/late-papayas-push.md b/.changeset/late-papayas-push.md new file mode 100644 index 0000000000..07422e1b1b --- /dev/null +++ b/.changeset/late-papayas-push.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-plugin-api': patch +--- + +Add support for `SidebarGroup` on the sidebar item extension. diff --git a/.changeset/lazy-doors-wink.md b/.changeset/lazy-doors-wink.md new file mode 100644 index 0000000000..aafbb3500e --- /dev/null +++ b/.changeset/lazy-doors-wink.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend': minor +--- + +Display meaningful error to the output if Gitlab namespace not found inside `publish:gitlab`. diff --git a/.changeset/lemon-cups-wait.md b/.changeset/lemon-cups-wait.md new file mode 100644 index 0000000000..4dd08c21b0 --- /dev/null +++ b/.changeset/lemon-cups-wait.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog': minor +--- + +include owner chip in catalog search result item diff --git a/.changeset/lemon-masks-greet.md b/.changeset/lemon-masks-greet.md new file mode 100644 index 0000000000..79c7b7e92b --- /dev/null +++ b/.changeset/lemon-masks-greet.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-components': patch +--- + +The `TabbedLayout` component will now also navigate when clicking the active tab, which allows for navigation back from any sub routes. diff --git a/.changeset/lovely-coins-occur.md b/.changeset/lovely-coins-occur.md new file mode 100644 index 0000000000..34a6774388 --- /dev/null +++ b/.changeset/lovely-coins-occur.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +Fixes a bug where eagerly deleted entities did not properly trigger re-stitching of entities that they had relations to. diff --git a/.changeset/lovely-fans-sniff.md b/.changeset/lovely-fans-sniff.md new file mode 100644 index 0000000000..af8aebb89b --- /dev/null +++ b/.changeset/lovely-fans-sniff.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-tech-radar': patch +--- + +Added experimental support for the declarative integration. diff --git a/.changeset/many-swans-eat.md b/.changeset/many-swans-eat.md new file mode 100644 index 0000000000..86580d7cfe --- /dev/null +++ b/.changeset/many-swans-eat.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-badges-backend': patch +--- + +Make sure the default badge factory is used if nothing is defined diff --git a/.changeset/mean-dancers-burn.md b/.changeset/mean-dancers-burn.md new file mode 100644 index 0000000000..a51ca7b8de --- /dev/null +++ b/.changeset/mean-dancers-burn.md @@ -0,0 +1,7 @@ +--- +'@backstage/core-app-api': patch +'@backstage/app-defaults': patch +'@backstage/test-utils': patch +--- + +Add missing resource and template app icons diff --git a/.changeset/metal-peas-beam.md b/.changeset/metal-peas-beam.md new file mode 100644 index 0000000000..a4ebdeb69a --- /dev/null +++ b/.changeset/metal-peas-beam.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': patch +--- + +Display log visibility button on the template panel diff --git a/.changeset/moody-lobsters-rescue.md b/.changeset/moody-lobsters-rescue.md new file mode 100644 index 0000000000..c739e995c5 --- /dev/null +++ b/.changeset/moody-lobsters-rescue.md @@ -0,0 +1,5 @@ +--- +'@backstage/create-app': patch +--- + +Bump `cypress` to fix the end-to-end tests diff --git a/.changeset/nervous-hounds-sleep.md b/.changeset/nervous-hounds-sleep.md new file mode 100644 index 0000000000..530ff348f7 --- /dev/null +++ b/.changeset/nervous-hounds-sleep.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-app-api': patch +--- + +Make themes configurable through extensions, and switched default themes to use extensions instead. diff --git a/.changeset/nice-clocks-smash.md b/.changeset/nice-clocks-smash.md new file mode 100644 index 0000000000..8a289370e5 --- /dev/null +++ b/.changeset/nice-clocks-smash.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-tech-insights-backend': patch +--- + +Increase the maximum allowed length of an entity filter for tech insights fact schemas. diff --git a/.changeset/nice-dancers-explain.md b/.changeset/nice-dancers-explain.md new file mode 100644 index 0000000000..5e54a66c05 --- /dev/null +++ b/.changeset/nice-dancers-explain.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-auth-backend-module-github-provider': patch +--- + +Fixed a bug where the GitHub authenticator did not properly persist granted OAuth scopes. diff --git a/.changeset/nine-garlics-attend.md b/.changeset/nine-garlics-attend.md new file mode 100644 index 0000000000..a9cdac4a32 --- /dev/null +++ b/.changeset/nine-garlics-attend.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-tasks': patch +--- + +Fix bug where backend tasks that are defined with HumanDuration are immediately triggered on application startup diff --git a/.changeset/olive-cars-rescue.md b/.changeset/olive-cars-rescue.md new file mode 100644 index 0000000000..fd6c8fe331 --- /dev/null +++ b/.changeset/olive-cars-rescue.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-search': patch +--- + +Create an experimental search plugin that is compatible with the declarative integration system, it is exported from `/alpha` subpath. diff --git a/.changeset/perfect-pumas-protect.md b/.changeset/perfect-pumas-protect.md new file mode 100644 index 0000000000..7d6bf8d6d7 --- /dev/null +++ b/.changeset/perfect-pumas-protect.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-code-coverage-backend': patch +--- + +Added option to set body size limit diff --git a/.changeset/plenty-llamas-double.md b/.changeset/plenty-llamas-double.md new file mode 100644 index 0000000000..b2691a2f17 --- /dev/null +++ b/.changeset/plenty-llamas-double.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-auth-node': patch +--- + +Fix for persisted scopes not being properly restored on sign-in. diff --git a/.changeset/polite-cooks-perform.md b/.changeset/polite-cooks-perform.md new file mode 100644 index 0000000000..40766c84a3 --- /dev/null +++ b/.changeset/polite-cooks-perform.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-app-api': minor +--- + +The `createApp` config option has been replaced by a new `configLoader` option. There is now also a `pluginLoader` option that can be used to dynamically load plugins into the app. diff --git a/.changeset/polite-donuts-fail.md b/.changeset/polite-donuts-fail.md new file mode 100644 index 0000000000..9c03faaf44 --- /dev/null +++ b/.changeset/polite-donuts-fail.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +Internal refactors, laying the foundation for later introducing deferred stitching (see #18062). diff --git a/.changeset/polite-trainers-grin.md b/.changeset/polite-trainers-grin.md new file mode 100644 index 0000000000..878596702d --- /dev/null +++ b/.changeset/polite-trainers-grin.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend-module-github': patch +--- + +Make `defaultUserTransformer` resolve to `UserEntity` instead of `Entity` diff --git a/.changeset/popular-dots-design.md b/.changeset/popular-dots-design.md new file mode 100644 index 0000000000..c333ce0105 --- /dev/null +++ b/.changeset/popular-dots-design.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-components': patch +--- + +Changed SupportButton menuitems to support text wrap diff --git a/.changeset/pre.json b/.changeset/pre.json index 63e218f886..d767fe77f0 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -244,7 +244,88 @@ "@backstage/plugin-user-settings-backend": "0.2.1", "@backstage/plugin-vault": "0.1.19", "@backstage/plugin-vault-backend": "0.3.8", - "@backstage/plugin-xcmetrics": "0.2.43" + "@backstage/plugin-xcmetrics": "0.2.43", + "@backstage/e2e-test-utils": "0.0.0", + "@backstage/plugin-kubernetes-react": "0.0.0" }, - "changesets": [] + "changesets": [ + "angry-badgers-beg", + "big-spies-beam", + "breezy-dryers-thank", + "calm-scissors-rescue", + "chatty-papayas-care", + "clean-forks-love", + "cold-bees-jam", + "cold-seas-repeat", + "dull-bugs-build", + "dull-dolls-explode", + "dull-experts-kiss", + "dull-laws-camp", + "eight-melons-cough", + "eighty-actors-type", + "fair-frogs-enjoy", + "four-jars-protect", + "four-onions-clap", + "four-pans-sin", + "fresh-kangaroos-tap", + "gentle-elephants-fold", + "gentle-spies-deny", + "happy-books-smoke", + "heavy-forks-tie", + "itchy-bobcats-fly", + "itchy-monkeys-reply", + "itchy-rabbits-exist", + "large-comics-knock", + "late-papayas-push", + "lazy-doors-wink", + "lemon-cups-wait", + "lemon-masks-greet", + "lovely-coins-occur", + "lovely-fans-sniff", + "many-swans-eat", + "mean-dancers-burn", + "moody-lobsters-rescue", + "nervous-hounds-sleep", + "nice-clocks-smash", + "nice-dancers-explain", + "nine-garlics-attend", + "olive-cars-rescue", + "perfect-pumas-protect", + "plenty-llamas-double", + "polite-cooks-perform", + "polite-donuts-fail", + "polite-trainers-grin", + "popular-dots-design", + "pretty-apes-sneeze", + "pretty-steaks-serve", + "purple-chefs-wait", + "purple-forks-fetch", + "quick-weeks-explode", + "red-bees-try", + "renovate-a1c52e8", + "shy-clouds-reflect", + "shy-seas-sip", + "silent-years-bake", + "silly-swans-invent", + "small-pugs-build", + "spicy-chairs-film", + "spotty-badgers-wash", + "strong-falcons-tickle", + "stupid-drinks-trade", + "stupid-eagles-shave", + "tasty-avocados-hope", + "tasty-doors-switch", + "ten-seals-wait", + "thirty-coins-sneeze", + "tiny-garlics-cheer", + "twelve-clouds-design", + "violet-beers-cross", + "warm-drinks-argue", + "wet-olives-wave", + "wet-timers-chew", + "wicked-rings-flash", + "wild-jobs-greet", + "yellow-numbers-own", + "yellow-rings-invent" + ] } diff --git a/.changeset/pretty-apes-sneeze.md b/.changeset/pretty-apes-sneeze.md new file mode 100644 index 0000000000..a1008dc951 --- /dev/null +++ b/.changeset/pretty-apes-sneeze.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-user-settings': patch +--- + +Fixed a bug where the theme icons would not be colored according to their active state. diff --git a/.changeset/purple-chefs-wait.md b/.changeset/purple-chefs-wait.md new file mode 100644 index 0000000000..9a8b1f9799 --- /dev/null +++ b/.changeset/purple-chefs-wait.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-api-docs': patch +--- + +Adding `requestInterceptor` option to `api-docs` and pass it to SwaggerUI. This will enable to configure a proxy or headers to be sent to all the request made through the `Try it out` button on SwaggerUI. diff --git a/.changeset/purple-forks-fetch.md b/.changeset/purple-forks-fetch.md new file mode 100644 index 0000000000..022fc32e71 --- /dev/null +++ b/.changeset/purple-forks-fetch.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-app-api': patch +--- + +Register default api implementations when creating declarative integrated apps. diff --git a/.changeset/red-bees-try.md b/.changeset/red-bees-try.md new file mode 100644 index 0000000000..de7eacfe14 --- /dev/null +++ b/.changeset/red-bees-try.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Fixed an issue where the new backend start command would not gracefully shut down the backend process on Windows. diff --git a/.changeset/red-geese-clean.md b/.changeset/red-geese-clean.md new file mode 100644 index 0000000000..b4fc9c0808 --- /dev/null +++ b/.changeset/red-geese-clean.md @@ -0,0 +1,8 @@ +--- +'@backstage/backend-openapi-utils': patch +--- + +Adds new public utility types for common OpenAPI values, like request and response shapes and parameters available on an endpoint. + +**deprecated** `internal` namespace +The internal namespace will continue to be exported but now uses OpenAPI format for path parameters. You should use the new utility types. diff --git a/.changeset/renovate-a1c52e8.md b/.changeset/renovate-a1c52e8.md new file mode 100644 index 0000000000..c11c866b68 --- /dev/null +++ b/.changeset/renovate-a1c52e8.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-cost-insights': patch +--- + +Updated dependency `@types/pluralize` to `^0.0.31`. diff --git a/.changeset/serious-penguins-tease.md b/.changeset/serious-penguins-tease.md new file mode 100644 index 0000000000..aa6aba7208 --- /dev/null +++ b/.changeset/serious-penguins-tease.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-test-utils': patch +--- + +Updated to import `HostDiscovery` from `@backstage/backend-app-api`. diff --git a/.changeset/short-terms-check.md b/.changeset/short-terms-check.md new file mode 100644 index 0000000000..69d85fcb9c --- /dev/null +++ b/.changeset/short-terms-check.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-common': patch +--- + +Removed `mock-fs` dev dependency. diff --git a/.changeset/shy-clouds-reflect.md b/.changeset/shy-clouds-reflect.md new file mode 100644 index 0000000000..2861bad9f3 --- /dev/null +++ b/.changeset/shy-clouds-reflect.md @@ -0,0 +1,5 @@ +--- +'@backstage/config-loader': patch +--- + +The `FileConfigSource` will now retry file reading after a short delay if it reads an empty file. This is to avoid flakiness during watch mode where change events can trigger before the file content has been written. diff --git a/.changeset/shy-seas-sip.md b/.changeset/shy-seas-sip.md new file mode 100644 index 0000000000..dfbc4ff0e0 --- /dev/null +++ b/.changeset/shy-seas-sip.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend-module-gitlab': patch +--- + +Make sure the archived projects are skipped with the Gitlab API diff --git a/.changeset/silly-swans-invent.md b/.changeset/silly-swans-invent.md new file mode 100644 index 0000000000..68b094aba7 --- /dev/null +++ b/.changeset/silly-swans-invent.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-plugin-api': patch +--- + +Added `createThemeExtension` and `coreExtensionData.theme`. diff --git a/.changeset/six-weeks-raise.md b/.changeset/six-weeks-raise.md new file mode 100644 index 0000000000..319555afa4 --- /dev/null +++ b/.changeset/six-weeks-raise.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-app-api': patch +--- + +Moved `HostDiscovery` from `@backstage/backend-common`. diff --git a/.changeset/slow-dodos-remember.md b/.changeset/slow-dodos-remember.md new file mode 100644 index 0000000000..fcc49e3f45 --- /dev/null +++ b/.changeset/slow-dodos-remember.md @@ -0,0 +1,8 @@ +--- +'@backstage/plugin-kubernetes-backend': patch +'@backstage/plugin-kubernetes-cluster': patch +'@backstage/plugin-kubernetes-react': patch +'@backstage/plugin-kubernetes': patch +--- + +Add Kubernetes cluster plugin. Viewing Kubernetes clusters as an Admin from Backstage diff --git a/.changeset/small-pugs-build.md b/.changeset/small-pugs-build.md index d1640340ba..68e11cd967 100644 --- a/.changeset/small-pugs-build.md +++ b/.changeset/small-pugs-build.md @@ -2,6 +2,6 @@ '@backstage/create-app': patch --- -Bump Docker base images to `node:18-bullseye-slim` to fix compatibility issues raised during image build. +Bump Docker base images to `node:18-bookworm-slim` to fix node compatibility issues raised during image build. -You can apply these change to your own `Dockerfile` by replacing `node:16-bullseye-slim` with `node:18-bullseye-slim` +You can apply these change to your own `Dockerfile` by replacing `node:16-bullseye-slim` with `node:18-bookworm-slim` diff --git a/.changeset/spicy-chairs-film.md b/.changeset/spicy-chairs-film.md new file mode 100644 index 0000000000..475d786330 --- /dev/null +++ b/.changeset/spicy-chairs-film.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-kubernetes-common': minor +'@backstage/plugin-kubernetes-react': minor +'@backstage/plugin-kubernetes': minor +--- + +Refactor Kubernetes plugins in line with ADR 11, no breaking changes yet diff --git a/.changeset/spotty-badgers-wash.md b/.changeset/spotty-badgers-wash.md new file mode 100644 index 0000000000..1ce9c66aee --- /dev/null +++ b/.changeset/spotty-badgers-wash.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': minor +--- + +Instrumenting some missing metrics with `OpenTelemetry` diff --git a/.changeset/stale-stingrays-explode.md b/.changeset/stale-stingrays-explode.md new file mode 100644 index 0000000000..b8b66b8398 --- /dev/null +++ b/.changeset/stale-stingrays-explode.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-auth-node': patch +--- + +Fixed cookie persisted scope not returned in OAuth refresh handler response. diff --git a/.changeset/strong-falcons-tickle.md b/.changeset/strong-falcons-tickle.md new file mode 100644 index 0000000000..d6fa0eb565 --- /dev/null +++ b/.changeset/strong-falcons-tickle.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-adr': patch +--- + +Create an experimental `AdrSearchResultItemExtension` for declarative integration with Backstage; it can be accessed via the `/alpha` import. diff --git a/.changeset/stupid-drinks-trade.md b/.changeset/stupid-drinks-trade.md new file mode 100644 index 0000000000..a9eeacec8a --- /dev/null +++ b/.changeset/stupid-drinks-trade.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs': patch +--- + +Add kind column by default to TechDocsTable diff --git a/.changeset/stupid-eagles-shave.md b/.changeset/stupid-eagles-shave.md new file mode 100644 index 0000000000..9bd88290ee --- /dev/null +++ b/.changeset/stupid-eagles-shave.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-code-coverage': patch +--- + +Updated layout to improve contrasts and consistency with other plugins diff --git a/.changeset/tasty-avocados-hope.md b/.changeset/tasty-avocados-hope.md new file mode 100644 index 0000000000..0772b55683 --- /dev/null +++ b/.changeset/tasty-avocados-hope.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog': patch +--- + +Migrate catalog api to declarative integration system, it is exported from `/alpha` subpath. diff --git a/.changeset/ten-seals-wait.md b/.changeset/ten-seals-wait.md new file mode 100644 index 0000000000..780422449c --- /dev/null +++ b/.changeset/ten-seals-wait.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-cost-insights': patch +--- + +The experimental plugin configuration has been removed. The trend line can now instead be hidden by setting `costInsights.hideTrendLine` to `true` in the configuration. diff --git a/.changeset/thirty-coins-sneeze.md b/.changeset/thirty-coins-sneeze.md new file mode 100644 index 0000000000..58a93065b8 --- /dev/null +++ b/.changeset/thirty-coins-sneeze.md @@ -0,0 +1,5 @@ +--- +'@backstage/e2e-test-utils': minor +--- + +Initial release. diff --git a/.changeset/tiny-garlics-cheer.md b/.changeset/tiny-garlics-cheer.md new file mode 100644 index 0000000000..992ed7f007 --- /dev/null +++ b/.changeset/tiny-garlics-cheer.md @@ -0,0 +1,5 @@ +--- +'@techdocs/cli': patch +--- + +Restructured tests. diff --git a/.changeset/twelve-clouds-design.md b/.changeset/twelve-clouds-design.md new file mode 100644 index 0000000000..d71d6caec0 --- /dev/null +++ b/.changeset/twelve-clouds-design.md @@ -0,0 +1,9 @@ +--- +'@backstage/create-app': patch +--- + +The E2E test setup based on Cypress has been replaced with one based on [Playwright](https://playwright.dev/). Migrating existing apps is not required as this is a standalone setup, only do so if you also want to switch from Cypress to Playwright. + +The scripts to run the E2E tests have been removed from `packages/app/package.json`, as they are now instead run from the root. Instead, a new script has been added to the root `package.json`, `yarn test:e2e`, which runs the E2E tests in development mode, unless `CI` is set in the environment. + +The Playwright setup uses utilities from the new `@backstage/e2e-test-utils` package to find and include all packages in the monorepo that have an `e2e-tests` folder. diff --git a/.changeset/twelve-days-walk.md b/.changeset/twelve-days-walk.md new file mode 100644 index 0000000000..0b2d261c1a --- /dev/null +++ b/.changeset/twelve-days-walk.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-app-api': minor +--- + +URL encode some well known unsafe characters in `RouteResolver` (and therefore `useRouteRef`) diff --git a/.changeset/two-dingos-dream.md b/.changeset/two-dingos-dream.md new file mode 100644 index 0000000000..9ebefacc69 --- /dev/null +++ b/.changeset/two-dingos-dream.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-kubernetes-backend': patch +'@backstage/plugin-kubernetes-react': patch +'@backstage/plugin-kubernetes-common': patch +--- + +The kubernetes APIs invokes Authentication Strategies when Backstage-Kubernetes-Authorization-X-X headers are provided, this enable the possibility to invoke strategies that executes additional steps to get a kubernetes token like on pinniped or custom strategies diff --git a/.changeset/violet-beers-cross.md b/.changeset/violet-beers-cross.md new file mode 100644 index 0000000000..bdbb9da64e --- /dev/null +++ b/.changeset/violet-beers-cross.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-components': patch +--- + +Change overlay header colors in the mobile menu to use navigation color from the theme diff --git a/.changeset/warm-drinks-argue.md b/.changeset/warm-drinks-argue.md new file mode 100644 index 0000000000..5bd4fa63f1 --- /dev/null +++ b/.changeset/warm-drinks-argue.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-explore': patch +--- + +Create an experimental `ExploreSearchResultItemExtension` for declarative integration with Backstage; it can be accessed via the `/alpha` import. diff --git a/.changeset/wet-olives-wave.md b/.changeset/wet-olives-wave.md new file mode 100644 index 0000000000..5b35e0ad90 --- /dev/null +++ b/.changeset/wet-olives-wave.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-api-docs': patch +--- + +added aria-label on api definition button for better a11y. diff --git a/.changeset/wet-timers-chew.md b/.changeset/wet-timers-chew.md new file mode 100644 index 0000000000..3be6368331 --- /dev/null +++ b/.changeset/wet-timers-chew.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-common': patch +--- + +The `useHotCleanup` and `useHotMemoize` helpers are now deprecated, since hot module reloads for backend are being phased out. diff --git a/.changeset/wicked-rings-flash.md b/.changeset/wicked-rings-flash.md new file mode 100644 index 0000000000..b872c0c71f --- /dev/null +++ b/.changeset/wicked-rings-flash.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-search-react': patch +--- + +Create `createSearchResultListItem` alpha version that only supports declarative integration. diff --git a/.changeset/wild-jobs-greet.md b/.changeset/wild-jobs-greet.md new file mode 100644 index 0000000000..fdbe6d56ac --- /dev/null +++ b/.changeset/wild-jobs-greet.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-app-api': patch +--- + +Prevents root extension override and duplicated plugin extensions. diff --git a/.changeset/yellow-numbers-own.md b/.changeset/yellow-numbers-own.md new file mode 100644 index 0000000000..3a6e8937eb --- /dev/null +++ b/.changeset/yellow-numbers-own.md @@ -0,0 +1,11 @@ +--- +'@backstage/create-app': patch +--- + +Added missing `.eslintignore` file + +To apply this change to an existing app, create a new `.eslintignore` file at the root of your project with the following content: + +```diff ++ playwright.config.ts +``` diff --git a/.changeset/yellow-rings-invent.md b/.changeset/yellow-rings-invent.md new file mode 100644 index 0000000000..f0335ff492 --- /dev/null +++ b/.changeset/yellow-rings-invent.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-components': patch +--- + +MissingAnnotationEmptyState component can now dynamically generate a YAML example based off the current entity being used. diff --git a/.dockerignore b/.dockerignore index e43b5fab1e..78aa97942d 100644 --- a/.dockerignore +++ b/.dockerignore @@ -2,7 +2,6 @@ .yarn/cache .yarn/install-state.gz docs -cypress microsite node_modules packages/*/src diff --git a/.eslintignore b/.eslintignore index 46bb1ad2b2..5ccd2d1ba0 100644 --- a/.eslintignore +++ b/.eslintignore @@ -9,3 +9,4 @@ **/microsite/** **/templates/** **/sample-templates/** +playwright.config.ts diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 922f7588a5..cb8101e1b1 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -5,10 +5,9 @@ # https://help.github.com/articles/about-codeowners/ * @backstage/maintainers @backstage/reviewers -yarn.lock @backstage/maintainers @backstage/reviewers @backstage-service -*/yarn.lock @backstage/maintainers @backstage/reviewers @backstage-service +yarn.lock @backstage/maintainers @backstage-service +*/yarn.lock @backstage/maintainers @backstage-service /.changeset/*.md -/cypress/src/integration/plugins/techdocs.spec.ts @backstage/techdocs-maintainers /docs/assets/search @backstage/discoverability-maintainers /docs/features/search @backstage/discoverability-maintainers /docs/features/techdocs @backstage/techdocs-maintainers @@ -22,6 +21,7 @@ yarn.lock @backstage/maintainers @backst /plugins/azure-devops @backstage/maintainers @backstage/reviewers @awanlin /plugins/azure-devops-backend @backstage/maintainers @backstage/reviewers @awanlin /plugins/azure-devops-common @backstage/maintainers @backstage/reviewers @awanlin +/plugins/analytics-module-newrelic-browser @backstage/maintainers @backstage/reviewers @jmezach /plugins/bitbucket-cloud-common @backstage/maintainers @backstage/reviewers @pjungermann /plugins/bitrise @backstage/maintainers @backstage/reviewers @backstage/sda-se-reviewers /plugins/catalog @backstage/maintainers @backstage/reviewers @backstage/catalog-maintainers @@ -63,6 +63,7 @@ yarn.lock @backstage/maintainers @backst /plugins/linguist @backstage/maintainers @backstage/reviewers @awanlin /plugins/linguist-backend @backstage/maintainers @backstage/reviewers @awanlin /plugins/linguist-common @backstage/maintainers @backstage/reviewers @awanlin +/plugins/octopus-deploy @backstage/maintainers @backstage/reviewers @jmezach /plugins/permission-* @backstage/permission-maintainers /plugins/playlist @backstage/maintainers @backstage/reviewers @kuangp /plugins/playlist-* @backstage/maintainers @backstage/reviewers @kuangp diff --git a/.github/vale/Vocab/Backstage/accept.txt b/.github/vale/Vocab/Backstage/accept.txt index e120198ba9..aadbaa3985 100644 --- a/.github/vale/Vocab/Backstage/accept.txt +++ b/.github/vale/Vocab/Backstage/accept.txt @@ -268,12 +268,14 @@ parseable Patrik pattison Peloton +PEP performant Performant periskop Periskop permissioned permissioning +pipx plantuml Platformize Podman @@ -399,6 +401,7 @@ tooltip tooltips touchpoint transpilation +transpile transpiled transpiler transpilers diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 12c19075a6..dbf2dc6705 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: strategy: fail-fast: false matrix: - node-version: [18.x, 20.x] + node-version: [18.x] env: CI: true @@ -49,7 +49,7 @@ jobs: strategy: fail-fast: false matrix: - node-version: [18.x, 20.x] + node-version: [18.x] env: CI: true @@ -139,7 +139,7 @@ jobs: strategy: fail-fast: false matrix: - node-version: [18.x, 20.x] + node-version: [18.x] name: Test ${{ matrix.node-version }} services: diff --git a/.github/workflows/deploy_packages.yml b/.github/workflows/deploy_packages.yml index 2329101eb0..91b25fb323 100644 --- a/.github/workflows/deploy_packages.yml +++ b/.github/workflows/deploy_packages.yml @@ -14,7 +14,7 @@ jobs: strategy: fail-fast: false matrix: - node-version: [18.x, 20.x] + node-version: [18.x] services: postgres13: diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 4f48fa83b4..6fe4ab0f9e 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -61,6 +61,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: 'Upload to code-scanning' - uses: github/codeql-action/upload-sarif@6a28655e3dcb49cb0840ea372fd6d17733edd8a4 # v2.21.8 + uses: github/codeql-action/upload-sarif@ddccb873888234080b77e9bc2d4764d5ccaaccf9 # v2.21.9 with: sarif_file: results.sarif diff --git a/.github/workflows/verify_e2e-windows.yml b/.github/workflows/verify_e2e-windows.yml index 4413312597..b1decefd10 100644 --- a/.github/workflows/verify_e2e-windows.yml +++ b/.github/workflows/verify_e2e-windows.yml @@ -48,6 +48,7 @@ jobs: uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} + registry-url: https://registry.npmjs.org/ # Needed for auth - name: setup python uses: actions/setup-python@v4 @@ -72,7 +73,9 @@ jobs: uses: browser-actions/setup-chrome@latest - name: yarn install - run: yarn install --immutable + uses: backstage/actions/yarn-install@v0.6.4 + with: + cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} - run: yarn tsc - run: yarn backstage-cli repo build diff --git a/.github/workflows/verify_windows.yml b/.github/workflows/verify_windows.yml index e5d3adf013..312c662b5a 100644 --- a/.github/workflows/verify_windows.yml +++ b/.github/workflows/verify_windows.yml @@ -9,9 +9,10 @@ on: jobs: build: - runs-on: windows-2019 + runs-on: windows-2022 strategy: + fail-fast: false matrix: node-version: [18.x, 20.x] diff --git a/.gitignore b/.gitignore index c0bf195947..7149dbabc1 100644 --- a/.gitignore +++ b/.gitignore @@ -144,15 +144,15 @@ site # Sensitive credentials *-credentials.yaml -# e2e tests -cypress/cypress/* - # Possible leftover from build:api-reports tsconfig.tmp.json # vscode database functionality support files *.session.sql +# E2E test reports +e2e-test-report/ + # Lighthouse CI Reports **/.lighthouseci/* !**/.lighthouseci/scripts diff --git a/.yarn/patches/jest-haste-map-npm-29.4.3-19b03fcef3.patch b/.yarn/patches/jest-haste-map-npm-29.4.3-19b03fcef3.patch new file mode 100644 index 0000000000..e0dd8bfa8c --- /dev/null +++ b/.yarn/patches/jest-haste-map-npm-29.4.3-19b03fcef3.patch @@ -0,0 +1,13 @@ +diff --git a/build/watchers/FSEventsWatcher.js b/build/watchers/FSEventsWatcher.js +index 2273a6cbd2110ddbbd1525820289c3d93ab46cac..d637a644239ae4a7db407ce779f43b4dec9a44ed 100644 +--- a/build/watchers/FSEventsWatcher.js ++++ b/build/watchers/FSEventsWatcher.js +@@ -103,7 +103,7 @@ function _interopRequireWildcard(obj, nodeInterop) { + // @ts-ignore: this is for CI which runs linux and might not have this + let fsevents = null; + try { +- fsevents = require('fsevents'); ++ // fsevents = require('fsevents'); + } catch { + // Optional dependency, only supported on Darwin. + } diff --git a/ADOPTERS.md b/ADOPTERS.md index 0d5b9fba59..ba96296610 100644 --- a/ADOPTERS.md +++ b/ADOPTERS.md @@ -5,7 +5,7 @@ _You can do this by using the [Adopter form](https://info.backstage.spotify.com/ | 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. | +| [Spotify](https://www.spotify.com) | [@helengreul](https://github.com/helengreul) | Main interface towards all of Spotify's infrastructure and technical documentation. | | [bol.com](https://www.bol.com) | [@acierto](https://github.com/acierto), [@clanghout](https://github.com/clanghout) | Initial work being done to unify platform tooling. | | [DFDS](https://www.dfds.com) | [@carlsendk](https://github.com/carlsendk) | V2 self-service platform. | | [Roadie](https://roadie.io) | [@dtuite](https://github.com/dtuite) | Hosted, managed Backstage with easy set-up | @@ -123,7 +123,7 @@ _You can do this by using the [Adopter form](https://info.backstage.spotify.com/ | [Contentful](https://www.contentful.com) | [James Bourne](https://github.com/jamesmbourne) | Centralized documentation of service ownership, APIs, and documentation, and new service creation with a custom scaffolder - [full case study with Roadie](https://roadie.io/case-studies/maintaining-velocity-through-hypergrowth-contentful/). | | [Back Market](https://www.backmarket.com) | [Sami Farhat](https://github.com/skfarhat) | Internal Developer Portal featuring catalog, tech-radar, ownership management, component creation (scaffolder) and centralized infrastructure management -- probably more to come. | | [Avalia Systems](https://avalia.io) | [Olivier Liechti](https://github.com/wasadigi), [Fabio Velloso](https://github.com/fabiovelloso) | Innersource, software analytics, knowledge base for 360 software assessments, collaborative applications, hub for tracking and sharing IP assets. | -| [Albert Heijn](https://ah.technology) | [Joost Hofman](https://github.com/joosthofman), [Reindrich Geerman](https://github.com/reinst) | Single point of entry for all our engineers (Developer portal), Tech radar, catalog, templates (paved roads) and tech documentation. | +| [Albert Heijn](https://ah.technology) | [Reindrich Geerman](https://github.com/reinst) | Single point of entry for all our engineers (Developer portal), Tech radar, catalog, templates (paved roads) and tech documentation. | | [Wise, formerly TransferWise](https://wise.com) | [Andrew Beveridge](https://github.com/beveradb) | It's early days for us, we're trying to start small with catalog, tech docs and unified search. Future ambitious vision includes scaffolder for one-click component addition, building out integrations with CI/CD tooling, kubernetes clusters, monitoring/alerting tooling etc. and aiming for a frictionless "golden path" for engineers! 🚀 | | [Happy Money](http://happymoney.com/) | [Akshit Lomash](mailto:alomash@happymoney.com) | We are moving from a monolith to microservices-based architecture. We are developing a developer portal based on Backstage to create a service catalog for our new services. All the services created are onboarded Backstage and engineering teams are using a cookie-cutter-based template from backstage to initiate a new service. | | [Lightspeed](http://lightspeedhq.com/) | [Marcus Crane](mailto:marcus.crane@lightspeedhq.com) | We use it within our X-Series division (https://vendhq.com) to catalog ~100+ systems and ~350 components! | @@ -260,3 +260,4 @@ _You can do this by using the [Adopter form](https://info.backstage.spotify.com/ | [Localiza&Co](https://www.localiza.com/) | [Augusto Amormino](https://github.com/augustoamormino), [Jonas Soares](https://github.com/jonaopower), [Alexandre Amormino](https://github.com/alexandreamormino), [Greg Almeida](https://github.com/sephh) | We're excited to announce our adoption of Backstage as our Internal Developer Portal! Our mission is to elevate the Developer Experience by streaming information access. Backstage will serve as the ultimate hub for developer resources, including documentation, tools, software insights, and metrics. Through Backstage, we're simplifying processes, offering software templates to empowered and efficient development journey, enhancing self-service capabilities with the embedded all best practices. | | [V2 Digital](https://v2.digital) | [Joe Patterson](https://github.com/jrwpatterson)| We will be using it to be a corporate dashboard plus our software catalog. | | [AppsFlyer](https://www.appsflyer.com/) | [Shahar Shmaram](https://github.com/shmaram) | Internal Developer Portal, a catalog of all company resources, custom providers and processors, scaffolder for generating new resources. +| [Cielo](https://www.cielo.com.br) | [@Alex Silva](https://github.com/narokwq) | We are using as our Internal Developer Portal, it provides developers with the resources, information, and tools they need to build high-quality applications and adhere to organizational standards and security practices. | diff --git a/OWNERS.md b/OWNERS.md index 6c26078f8c..135d617203 100644 --- a/OWNERS.md +++ b/OWNERS.md @@ -73,16 +73,18 @@ Team: @backstage/permission-maintainers Scope: The Permission Framework and plugins integrating with the permission framework -| Name | Organization | Team | GitHub | Discord | -| -------------------- | ------------ | --------------- | ---------------------------------------------- | ---------------- | -| Ainhoa Larumbe | Spotify | Imaginary Goats | [ainhoaL](http://github.com/ainhoaL) | ainhoa#8085 | -| Claire Casey | Spotify | Imaginary Goats | [clairelcasey](http://github.com/clairelcasey) | clairecasey#2710 | -| Eric Peterson | Spotify | Imaginary Goats | [iamEAP](http://github.com/iamEAP) | iamEAP#3058 | -| Harry Hogg | Spotify | Imaginary Goats | [HHogg](http://github.com/HHogg) | simplex#3451 | -| Joon Park | Spotify | Imaginary Goats | [Joonpark13](http://github.com/Joonpark13) | Sixpool#5060 | -| Mike Lewis | Spotify | Imaginary Goats | [mtlewis](http://github.com/mtlewis) | mtlewis#3658 | -| Tim Hansen | Spotify | Imaginary Goats | [timbonicus](http://github.com/timbonicus) | timbonicus#6871 | -| Vincenzo Scamporlino | Spotify | Imaginary Goats | [vinzscam](http://github.com/vinzscam) | vinzscam#6944 | +| Name | Organization | Team | GitHub | Discord | +| -------------------- | ------------ | --------------- | ----------------------------------------------- | ---------------- | +| Ainhoa Larumbe | Spotify | Imaginary Goats | [ainhoaL](http://github.com/ainhoaL) | ainhoa#8085 | +| Aramis Sennyey | Spotify | Imaginary Goats | [sennyeya](https://github.com/sennyeya) | Aramis#7984 | +| Claire Casey | Spotify | Imaginary Goats | [clairelcasey](http://github.com/clairelcasey) | clairecasey#2710 | +| Eric Peterson | Spotify | Imaginary Goats | [iamEAP](http://github.com/iamEAP) | iamEAP#3058 | +| Harry Hogg | Spotify | Imaginary Goats | [HHogg](http://github.com/HHogg) | simplex#3451 | +| Joon Park | Spotify | Imaginary Goats | [Joonpark13](http://github.com/Joonpark13) | Sixpool#5060 | +| Lynette Lopez | Spotify | Imaginary Goats | [lynettelopez](https://github.com/lynettelopez) | lynettelopez | +| Mike Lewis | Spotify | Imaginary Goats | [mtlewis](http://github.com/mtlewis) | mtlewis#3658 | +| Tim Hansen | Spotify | Imaginary Goats | [timbonicus](http://github.com/timbonicus) | timbonicus#6871 | +| Vincenzo Scamporlino | Spotify | Imaginary Goats | [vinzscam](http://github.com/vinzscam) | vinzscam#6944 | ### TechDocs @@ -114,15 +116,15 @@ Scope: Tooling for frontend and backend schema-first OpenAPI development. | Name | Organization | GitHub | Discord | | -------------- | ------------ | --------------------------------------- | ------------- | -| Aramis Sennyey | | [sennyeya](https://github.com/sennyeya) | `Aramis#7984` | +| Aramis Sennyey | Spotify | [sennyeya](https://github.com/sennyeya) | `Aramis#7984` | ## Sponsors -| Name | Organization | GitHub | Email | -| ----------------- | ------------ | ------------------------------------------- | ----------------- | -| Niklas Gustavsson | Spotify | [protocol7](https://github.com/protocol7) | ngn@spotify.com | -| Dave Zolotusky | Spotify | [dzolotusky](https://github.com/dzolotusky) | dzolo@spotify.com | -| Lee Mills | Spotify | [leemills83](https://github.com/leemills83) | leem@spotify.com | +| Name | Organization | GitHub | Email | +| ----------------- | ------------ | ------------------------------------------- | ------------------ | +| Niklas Gustavsson | Spotify | [protocol7](https://github.com/protocol7) | ngn@spotify.com | +| Dave Zolotusky | Spotify | [dzolotusky](https://github.com/dzolotusky) | dzolo@spotify.com | +| Helen Greul | Spotify | [helengreul](https://github.com/helengreul) | heleng@spotify.com | ## Organization Members @@ -132,7 +134,7 @@ Scope: Tooling for frontend and backend schema-first OpenAPI development. | Alex Crome | | [afscrome](https://github.com/afscrome) | `afscrome` | | Andre Wanlin | Keyloop | [awanlin](https://github.com/awanlin) | `ahhhndre` | | Andrew Thauer | Wealthsimple | [andrewthauer](https://github.com/andrewthauer) | `andrewthauer#3060` | -| Aramis Sennyey | | [sennyeya](https://github.com/sennyeya) | `Aramis#7984` | +| Aramis Sennyey | Spotify | [sennyeya](https://github.com/sennyeya) | `Aramis#7984` | | Brian Fletcher | Roadie.io | [punkle](https://github.com/punkle) | `Brian Fletcher#7051` | | Carlos Esteban Lopez Jaramillo | VMWare | [luchillo17](https://github.com/luchillo17) | `luchillo17#8777` | | David Tuite | Roadie.io | [dtuite](https://github.com/dtuite) | `David Tuite (roadie.io)#1010` | @@ -152,3 +154,9 @@ Scope: Tooling for frontend and backend schema-first OpenAPI development. | Maintainer | Organization | GitHub | Discord | | ------------ | ------------ | --------------------------------------------- | -------------- | | Stefan Ålund | Spotify | [stefanalund](https://github.com/stefanalund) | `stalund#9602` | + +## Emeritus End User Sponsors + +| Name | Organization | GitHub | Discord | +| --------- | ------------ | ------------------------------------------- | -------------- | +| Lee Mills | Spotify | [leemills83](https://github.com/leemills83) | `.binarypoint` | diff --git a/app-config.yaml b/app-config.yaml index 9e153e5763..a2ee232516 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -291,9 +291,6 @@ catalog: target: ../../plugins/scaffolder-backend/sample-templates/all-templates.yaml rules: - allow: [Template] - # Backstage end-to-end tests of TechDocs - - type: file - target: ../../cypress/e2e-fixture.catalog.info.yaml scaffolder: # Use to customize default commit author info used when new components are created # defaultAuthor: diff --git a/cypress/.eslintrc.js b/cypress/.eslintrc.js deleted file mode 100644 index 07f264452d..0000000000 --- a/cypress/.eslintrc.js +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = { - extends: [require.resolve('@backstage/cli/config/eslint.backend')], - rules: { - 'no-console': 0, - 'jest/valid-expect': 'off', - 'jest/expect-expect': 'off', - 'no-restricted-syntax': 'off', - }, -}; diff --git a/cypress/.npmrc b/cypress/.npmrc deleted file mode 100644 index c3c66347fd..0000000000 --- a/cypress/.npmrc +++ /dev/null @@ -1,2 +0,0 @@ -registry=https://registry.npmjs.org/ -engine-strict=true diff --git a/cypress/.yarnrc b/cypress/.yarnrc deleted file mode 100644 index a2c82b2833..0000000000 --- a/cypress/.yarnrc +++ /dev/null @@ -1,5 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - -registry "https://registry.npmjs.org/" -network-timeout 300000 diff --git a/cypress/README.md b/cypress/README.md deleted file mode 100644 index be2960e63c..0000000000 --- a/cypress/README.md +++ /dev/null @@ -1,34 +0,0 @@ -# Cypress Tests for Backstage - -Hey 👋 Welcome to the Cypress tests for Backstage. They're designed to be run against the `packages/app` folder in the main repo, and be some form of smoke tests to make sure that we don't break any core functionality. - -### Running Locally - -In order to make typescript happy, this `cypress` package is separate from all the Jest dependencies in the monorepo workspaces setup. - -You can run the e2e tests locally pointing at your local running version like so: - -```sh -cd cypress -yarn install -yarn cypress run -``` - -Note that the tests expect to run against a built application, so you'll want to -run a Docker image and either create an `app-config.cypress.yaml` or pass the -necessary environment variables: - -```sh -yarn tsc -yarn build:backend -yarn workspace example-backend build-image -docker run -p 7007:7007 example-backend -``` - -You can open up the `cypress` console by using `yarn cypress open`. - -You can also run towards any Backstage installation by using the Cypress Environment Variable overrides. - -```sh -CYPRESS_baseUrl="http://demo.backstage.io" yarn cypress run -``` diff --git a/cypress/cypress.json b/cypress/cypress.json deleted file mode 100644 index 7335d0f62a..0000000000 --- a/cypress/cypress.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "baseUrl": "http://localhost:7007", - "integrationFolder": "./src/integration", - "supportFile": "./src/support", - "fixturesFolder": "./src/fixtures", - "pluginsFile": "./src/plugins", - "defaultCommandTimeout": 10000, - "viewportHeight": 900, - "viewportWidth": 1440 -} diff --git a/cypress/e2e-fixture.catalog.info.yaml b/cypress/e2e-fixture.catalog.info.yaml deleted file mode 100644 index 31502e415d..0000000000 --- a/cypress/e2e-fixture.catalog.info.yaml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: backstage.io/v1alpha1 -kind: Component -metadata: - name: techdocs-e2e-fixture - description: Used for end-to-end tests of TechDocs in Backstage. - annotations: - backstage.io/techdocs-ref: dir:./fixtures -spec: - type: service - lifecycle: experimental - owner: user:guest diff --git a/cypress/fixtures/docs/index.md b/cypress/fixtures/docs/index.md deleted file mode 100644 index d7ff14b46d..0000000000 --- a/cypress/fixtures/docs/index.md +++ /dev/null @@ -1,3 +0,0 @@ -# Home page - -This is a basic documentation used for end-to-end tests. diff --git a/cypress/fixtures/docs/sub-page-one.md b/cypress/fixtures/docs/sub-page-one.md deleted file mode 100644 index 7c451efeb5..0000000000 --- a/cypress/fixtures/docs/sub-page-one.md +++ /dev/null @@ -1,109 +0,0 @@ -# Sub-page 1 - -## Section 1.1 - -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! - -## Section 1.2 - -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! - -## Section 1.3 - -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! diff --git a/cypress/fixtures/docs/sub-page-three.md b/cypress/fixtures/docs/sub-page-three.md deleted file mode 100644 index e9a439ed98..0000000000 --- a/cypress/fixtures/docs/sub-page-three.md +++ /dev/null @@ -1,121 +0,0 @@ -# Sub-page 3 - -## Section 3.1 - -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! - -## Section 3.2 - -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! - -### Sub-Section 3.2.1 - -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! - -### Sub-Section 3.2.2 - -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! - -## Section 3.3 - -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! diff --git a/cypress/fixtures/docs/sub-page-two.md b/cypress/fixtures/docs/sub-page-two.md deleted file mode 100644 index eb2344e9c3..0000000000 --- a/cypress/fixtures/docs/sub-page-two.md +++ /dev/null @@ -1,146 +0,0 @@ -# Sub-page 2 - -## Section 2.1 - -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! - -## Section 2.2 - -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! - -### Sub-Section 2.2.1 - -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! - -### Sub-Section 2.2.2 - -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! - -## Section 2.3 - -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! -To next page! - -[Link to Section 1.1](sub-page-one.md#section-11) diff --git a/cypress/fixtures/mkdocs.yml b/cypress/fixtures/mkdocs.yml deleted file mode 100644 index 071d147509..0000000000 --- a/cypress/fixtures/mkdocs.yml +++ /dev/null @@ -1,13 +0,0 @@ -site_name: e2e Fixture Documentation -site_description: Documentation used for end-to-end tests of TechDocs in Backstage. -repo_url: https://github.com/backstage/backstage -edit_uri: edit/master/cypress/fixtures/docs - -nav: - - Home: index.md - - Sub-page 1: sub-page-one.md - - Sub-page 2: sub-page-two.md - - Nested Sub-pages: - - Sub-page 3: sub-page-three.md -plugins: - - techdocs-core diff --git a/cypress/package.json b/cypress/package.json deleted file mode 100644 index cc66949d28..0000000000 --- a/cypress/package.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "name": "@backstage/cypress-tests", - "version": "1.0.0", - "main": "index.js", - "license": "MIT", - "private": true, - "dependencies": { - "cypress": "^10.0.0", - "typescript": "^4.1.3" - } -} diff --git a/cypress/src/fixtures/.gitkeep b/cypress/src/fixtures/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/cypress/src/integration/integrations.spec.ts b/cypress/src/integration/integrations.spec.ts deleted file mode 100644 index 4703c18881..0000000000 --- a/cypress/src/integration/integrations.spec.ts +++ /dev/null @@ -1,82 +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 'os'; - -describe('Integrations', () => { - describe('ReadTree', () => { - it('should work for github', () => { - cy.loginAsGuest(); - - cy.request('POST', '/api/catalog/locations', { - target: - 'https://github.com/backstage-verification/test-repo/blob/main/**/*', - type: 'url', - }); - - cy.wait(5000); - - cy.visit('/catalog'); - cy.get('[data-testid="user-picker-all"]').click(); - cy.get('table').should('contain', 'github-repo'); - cy.get('table').should('contain', 'github-repo-nested'); - }); - - // it('should work for azure', () => { - // cy.loginAsGuest(); - - // cy.request('POST', '/api/catalog/locations', { - // target: - // 'https://dev.azure.com/backstage-verification/_git/test-repo?path=*', - // type: 'url', - // }); - // }); - - it('should work for gitlab', () => { - cy.loginAsGuest(); - - cy.request('POST', '/api/catalog/locations', { - target: - 'https://gitlab.com/backstage-verification/test-repo/-/tree/master/**/*', - type: 'url', - }); - - cy.wait(5000); - - cy.visit('/catalog'); - cy.get('[data-testid="user-picker-all"]').click(); - cy.get('table').should('contain', 'gitlab-repo'); - cy.get('table').should('contain', 'gitlab-repo-nested'); - }); - - it('should work for bitbucket', () => { - cy.loginAsGuest(); - - cy.request('POST', '/api/catalog/locations', { - target: - 'https://bitbucket.org/backstage-verification/test-repo/src/master/**/*', - type: 'url', - }); - - cy.wait(5000); - - cy.visit('/catalog'); - cy.get('[data-testid="user-picker-all"]').click(); - cy.get('table').should('contain', 'bitbucket-repo'); - cy.get('table').should('contain', 'bitbucket-repo-nested'); - }); - }); -}); diff --git a/cypress/src/integration/plugins/catalog.spec.ts b/cypress/src/integration/plugins/catalog.spec.ts deleted file mode 100644 index 50ef3145e5..0000000000 --- a/cypress/src/integration/plugins/catalog.spec.ts +++ /dev/null @@ -1,199 +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 'os'; - -describe('Catalog', () => { - describe('default entities', () => { - it('displays the correct amount of entities from default config', () => { - cy.loginAsGuest(); - - cy.visit('/catalog'); - - cy.contains('Owned (10)').should('be.visible'); - }); - - it('Should navigate to a docs tab', () => { - cy.loginAsGuest(); - - cy.visit('/catalog'); - - cy.contains('techdocs-e2e-fixture').click(); - - cy.location().should(loc => { - expect(loc.pathname).to.eq( - '/catalog/default/component/techdocs-e2e-fixture', - ); - }); - - cy.getCatalogDocsTab().click(); - - cy.getTechDocsShadowRoot() - .find('h1') - .contains('Home page') - .should('be.visible'); - }); - - it('Should navigate to a sub-route in docs tab', () => { - cy.loginAsGuest(); - - cy.visit('/catalog'); - - cy.contains('techdocs-e2e-fixture').click(); - - cy.location().should(loc => { - expect(loc.pathname).to.eq( - '/catalog/default/component/techdocs-e2e-fixture', - ); - }); - - cy.getCatalogDocsTab().click(); - - cy.getTechDocsShadowRoot() - .find('h1') - .contains('Home page') - .should('be.visible'); - - cy.getTechDocsShadowRoot().within(() => { - cy.getTechDocsNavigation().find('a').contains('Sub-page 1').click(); - }); - - cy.location().should(loc => { - expect(loc.pathname).to.eq( - '/catalog/default/component/techdocs-e2e-fixture/docs/sub-page-one/', - ); - }); - - cy.getTechDocsShadowRoot() - .find('h1') - .contains('Sub-page 1') - .should('be.visible'); - }); - - it('Should render addons on docs tab homepage', () => { - cy.loginAsGuest(); - - cy.visit('/catalog'); - - cy.contains('techdocs-e2e-fixture').click(); - - cy.location().should(loc => { - expect(loc.pathname).to.eq( - '/catalog/default/component/techdocs-e2e-fixture', - ); - }); - - cy.getCatalogDocsTab().click(); - - cy.wait(300); - - cy.getTechDocsShadowRoot() - .find('h1') - .contains('Home page') - .should('be.visible'); - - // highlight a snippet of text - cy.getTechDocsShadowRoot() - .find('article > p') - .then($el => { - const el = $el[0]; - const document = el.ownerDocument; - const range = document.createRange(); - range.selectNodeContents(el); - document?.getSelection()?.removeAllRanges(); - document?.getSelection()?.addRange(range); - }); - - cy.document().trigger('selectionchange'); - - // wait for new issue default debounce time - cy.wait(600); - - // assert that the new issue button has a right url - cy.getTechDocsShadowRoot() - .contains('Open new Github issue') - .should( - 'have.attr', - 'href', - 'https://github.com/backstage/backstage/issues/new?title=Documentation%20feedback%3A%20This%20is%20a%20basic%20documentation%20used%20for%20end-to-end%20tests.&body=%23%23%20Documentation%20Feedback%20%F0%9F%93%9D%0A%0A%20%23%23%23%23%20The%20highlighted%20text%3A%20%0A%0A%20%3E%20This%20is%20a%20basic%20documentation%20used%20for%20end-to-end%20tests.%0A%0A%20%23%23%23%23%20The%20comment%20on%20the%20text%3A%20%0A%20_%3Ereplace%20this%20line%20with%20your%20comment%3C_%0A%0A%20___%0ABackstage%20URL%3A%20%3Chttp%3A%2F%2Flocalhost%3A7007%2Fcatalog%2Fdefault%2Fcomponent%2Ftechdocs-e2e-fixture%2Fdocs%3E%20%0AMarkdown%20URL%3A%20%3Chttps%3A%2F%2Fgithub.com%2Fbackstage%2Fbackstage%2Fblob%2Fmaster%2Fcypress%2Ffixtures%2Fdocs%2Findex.md%3E', - ); - }); - - it('Should render addons on docs tab sup-page', () => { - cy.loginAsGuest(); - - cy.visit('/catalog'); - - cy.contains('techdocs-e2e-fixture').click(); - - cy.location().should(loc => { - expect(loc.pathname).to.eq( - '/catalog/default/component/techdocs-e2e-fixture', - ); - }); - - cy.getCatalogDocsTab().click(); - - cy.wait(300); - - cy.getTechDocsShadowRoot() - .find('h1') - .contains('Home page') - .should('be.visible'); - - cy.getTechDocsShadowRoot().within(() => { - cy.getTechDocsNavigation().find('a').contains('Sub-page 1').click(); - }); - - cy.location().should(loc => { - expect(loc.pathname).to.eq( - '/catalog/default/component/techdocs-e2e-fixture/docs/sub-page-one/', - ); - }); - - cy.getTechDocsShadowRoot() - .find('h1') - .contains('Sub-page 1') - .should('be.visible'); - - // highlight a snippet of text - cy.getTechDocsShadowRoot() - .find('#section-11') - .then($el => { - const el = $el[0]; - const document = el.ownerDocument; - const range = document.createRange(); - range.selectNodeContents(el); - document?.getSelection()?.removeAllRanges(); - document?.getSelection()?.addRange(range); - }); - - cy.document().trigger('selectionchange'); - - // wait for new issue default debounce time - cy.wait(600); - - // assert that the new issue button has a right url - cy.getTechDocsShadowRoot() - .contains('Open new Github issue') - .should( - 'have.attr', - 'href', - 'https://github.com/backstage/backstage/issues/new?title=Documentation%20feedback%3A%20Section%201.1%C2%B6&body=%23%23%20Documentation%20Feedback%20%F0%9F%93%9D%0A%0A%20%23%23%23%23%20The%20highlighted%20text%3A%20%0A%0A%20%3E%20Section%201.1%C2%B6%0A%0A%20%23%23%23%23%20The%20comment%20on%20the%20text%3A%20%0A%20_%3Ereplace%20this%20line%20with%20your%20comment%3C_%0A%0A%20___%0ABackstage%20URL%3A%20%3Chttp%3A%2F%2Flocalhost%3A7007%2Fcatalog%2Fdefault%2Fcomponent%2Ftechdocs-e2e-fixture%2Fdocs%2Fsub-page-one%2F%3E%20%0AMarkdown%20URL%3A%20%3Chttps%3A%2F%2Fgithub.com%2Fbackstage%2Fbackstage%2Fblob%2Fmaster%2Fcypress%2Ffixtures%2Fdocs%2Fsub-page-one.md%3E', - ); - }); - }); -}); diff --git a/cypress/src/integration/plugins/score-card.spec.ts b/cypress/src/integration/plugins/score-card.spec.ts deleted file mode 100644 index 5871a094e1..0000000000 --- a/cypress/src/integration/plugins/score-card.spec.ts +++ /dev/null @@ -1,83 +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 'os'; - -describe('score-card', () => { - describe('Score board', () => { - it('displays the score board based on sample data', () => { - cy.loginAsGuest(); - - cy.visit('/score-board'); - cy.screenshot({ capture: 'viewport' }); - - cy.contains('System scores overview').should('be.visible'); - cy.checkForErrors(); - cy.get('span:contains("1-2 of 2")').should('be.visible'); // beware, there is also a hidden

element - cy.contains('audio-playback').should('be.visible'); - cy.contains('team-c').should('be.visible'); - cy.contains('non-valid-system').should('be.visible'); - cy.contains('Name').should('be.visible'); - cy.contains('Date').should('be.visible'); - cy.contains('Code').should('be.visible'); - cy.contains('Documentation').should('be.visible'); - cy.contains('Operations').should('be.visible'); - cy.contains('Quality').should('be.visible'); - cy.contains('Security').should('be.visible'); - cy.contains('Total').should('be.visible'); - cy.contains('50 %').should('be.visible'); - cy.contains('75 %').should('be.visible'); - cy.log('navigating to score card detail for audio-playback'); - cy.get('a[data-id="audio-playback"]').should('be.visible').click(); - cy.screenshot({ capture: 'viewport' }); - - cy.url().should( - 'include', - '/catalog/default/System/audio-playback/score', - ); - cy.contains('Scoring').should('be.visible'); - cy.contains('Total score: 57 %').should('be.visible'); - cy.contains('Code').should('be.visible'); - cy.contains('90 %').should('be.visible'); - cy.contains('Documentation').should('be.visible'); - cy.contains('75 %').should('be.visible'); - cy.contains('Operations').should('be.visible'); - cy.contains('50 %').should('be.visible'); - cy.contains('Quality').should('be.visible'); - cy.contains('25 %').should('be.visible'); - cy.contains('Security'); - cy.contains('10 %').should('be.visible'); - cy.checkForErrors(); - - cy.log( - 'Clicking on button [>] that is first child of the element (td) with value=Code', - ); - cy.get('[value="Code"] > button:first-child').click(); - cy.checkForErrors(); - cy.screenshot({ capture: 'viewport' }); - - cy.log('Clicking on link for Code'); - cy.contains('hints: Gitflow: 100%').should('be.visible'); - cy.get('a[data-id="2157"]') - .should('be.visible') - .should( - 'have.attr', - 'href', - 'https://TBD/XXX/_wiki/wikis/XXX.wiki/2157', - ); - }); - }); -}); diff --git a/cypress/src/integration/plugins/techdocs.spec.ts b/cypress/src/integration/plugins/techdocs.spec.ts deleted file mode 100644 index 31094cb128..0000000000 --- a/cypress/src/integration/plugins/techdocs.spec.ts +++ /dev/null @@ -1,259 +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'; - -describe('TechDocs', () => { - beforeEach(() => { - cy.loginAsGuest(); - cy.mockSockJSNode(); - cy.interceptTechDocsAPICalls(); - }); - - describe('Navigating to TechDocs', () => { - it('should navigate to the TechDocs home page via the primary navigation bar', () => { - cy.visit('/'); - cy.wait(500); - - cy.get('[data-testid="sidebar-root"]') - .get('div') - .get('a[href="/docs"]') - .click(); - - cy.contains('Documentation'); - }); - - it('should navigate to the TechDocs home page from the URL', () => { - cy.visit('/docs'); - - cy.wait(500); - - cy.contains('Documentation'); - }); - - it('should navigate to a specific TechDocs entity from the "Overview" tab', () => { - cy.visit('/docs'); - - cy.contains('techdocs-e2e-fixture').click(); - - cy.location().should(loc => { - expect(loc.pathname).to.eq( - '/docs/default/component/techdocs-e2e-fixture', - ); - }); - }); - - it('should navigate to a specific TechDocs entity page from a URL', () => { - cy.visit('/docs/default/Component/techdocs-e2e-fixture'); - cy.waitHomePage(); - - cy.contains('e2e Fixture Documentation'); - cy.contains( - 'Documentation used for end-to-end tests of TechDocs in Backstage.', - ); - cy.getTechDocsShadowRoot().contains('Home page'); - }); - - it('should navigate to a specific TechDocs section from a URL', () => { - cy.visit('/docs/default/Component/techdocs-e2e-fixture/sub-page-two'); - cy.waitSectionTwoPage(); - - cy.window().its('scrollY').should('equal', 0); - - cy.getTechDocsShadowRoot().within(() => { - cy.contains('Sub-page 2'); - }); - }); - - it('should navigate to a specific TechDocs fragment from a URL', () => { - cy.visit( - '/docs/default/Component/techdocs-e2e-fixture/sub-page-two#section-23', - ); - - // This is used to test the post-render behavior of the techdocs Reader - cy.wait(500); - - cy.getTechDocsShadowRoot().within(() => { - cy.isInViewport('#section-23'); - }); - }); - - it('should navigate to a wrong TechDocs entity page from a URL', () => { - cy.visit('/docs/default/Component/wrong-component'); - - cy.get('[data-testid=error]').should('be.visible'); - }); - }); - - describe('Rendering TechDocs Addons', () => { - it('should render a content addon in homepage', () => { - cy.visit('/docs/default/Component/techdocs-e2e-fixture'); - - cy.contains('e2e Fixture Documentation'); - - // highlight a snippet of text - cy.getTechDocsShadowRoot() - .find('article > p') - .then($el => { - const el = $el[0]; - const document = el.ownerDocument; - const range = document.createRange(); - range.selectNodeContents(el); - document?.getSelection()?.removeAllRanges(); - document?.getSelection()?.addRange(range); - }); - - cy.document().trigger('selectionchange'); - - // wait for new issue default debounce time - cy.wait(600); - - // assert that the new issue button has a right url - cy.getTechDocsShadowRoot() - .contains('Open new Github issue') - .should( - 'have.attr', - 'href', - 'https://github.com/backstage/backstage/issues/new?title=Documentation%20feedback%3A%20This%20is%20a%20basic%20documentation%20used%20for%20end-to-end%20tests.&body=%23%23%20Documentation%20Feedback%20%F0%9F%93%9D%0A%0A%20%23%23%23%23%20The%20highlighted%20text%3A%20%0A%0A%20%3E%20This%20is%20a%20basic%20documentation%20used%20for%20end-to-end%20tests.%0A%0A%20%23%23%23%23%20The%20comment%20on%20the%20text%3A%20%0A%20_%3Ereplace%20this%20line%20with%20your%20comment%3C_%0A%0A%20___%0ABackstage%20URL%3A%20%3Chttp%3A%2F%2Flocalhost%3A7007%2Fdocs%2Fdefault%2FComponent%2Ftechdocs-e2e-fixture%3E%20%0AMarkdown%20URL%3A%20%3Chttps%3A%2F%2Fgithub.com%2Fbackstage%2Fbackstage%2Fblob%2Fmaster%2Fcypress%2Ffixtures%2Fdocs%2Findex.md%3E', - ); - }); - - it('should render a content addon in sub-pages', () => { - cy.visit('/docs/default/Component/techdocs-e2e-fixture'); - - cy.contains('e2e Fixture Documentation'); - - // open sub-page - cy.getTechDocsShadowRoot().within(() => { - cy.getTechDocsNavigation().find('a').contains('Sub-page 1').click(); - }); - - // highlight a snippet of text - cy.getTechDocsShadowRoot() - .find('#section-11') - .then($el => { - const el = $el[0]; - const document = el.ownerDocument; - const range = document.createRange(); - range.selectNodeContents(el); - document?.getSelection()?.removeAllRanges(); - document?.getSelection()?.addRange(range); - }); - - cy.document().trigger('selectionchange'); - - // wait for new issue default debounce time - cy.wait(600); - - // assert that the new issue button has a right url - cy.getTechDocsShadowRoot() - .contains('Open new Github issue') - .should( - 'have.attr', - 'href', - 'https://github.com/backstage/backstage/issues/new?title=Documentation%20feedback%3A%20Section%201.1%C2%B6&body=%23%23%20Documentation%20Feedback%20%F0%9F%93%9D%0A%0A%20%23%23%23%23%20The%20highlighted%20text%3A%20%0A%0A%20%3E%20Section%201.1%C2%B6%0A%0A%20%23%23%23%23%20The%20comment%20on%20the%20text%3A%20%0A%20_%3Ereplace%20this%20line%20with%20your%20comment%3C_%0A%0A%20___%0ABackstage%20URL%3A%20%3Chttp%3A%2F%2Flocalhost%3A7007%2Fdocs%2Fdefault%2FComponent%2Ftechdocs-e2e-fixture%2Fsub-page-one%2F%3E%20%0AMarkdown%20URL%3A%20%3Chttps%3A%2F%2Fgithub.com%2Fbackstage%2Fbackstage%2Fblob%2Fmaster%2Fcypress%2Ffixtures%2Fdocs%2Fsub-page-one.md%3E', - ); - }); - }); - - describe('Navigating within TechDocs', () => { - it('should navigate to a specific TechDocs page via the navigation bar', () => { - cy.visit('/docs/default/Component/techdocs-e2e-fixture'); - - cy.getTechDocsShadowRoot().within(() => { - cy.getTechDocsNavigation() - .find('> div > div > [data-md-level="0"] > ul > li:nth-child(2) > a') - .click(); - cy.contains('Sub-page 1'); - cy.window().its('scrollY').should('eq', 0); - }); - }); - - describe('Navigating within a TechDocs page', () => { - beforeEach(() => { - cy.visit('/docs/default/Component/techdocs-e2e-fixture/sub-page-two'); - }); - - it('should navigate to a specific fragment within the page via the table of contents - Level 1', () => { - return cy.getTechDocsShadowRoot().within(() => { - // Section 3 - cy.getTechDocsTableOfContents() - .find('a') - .contains('Section 2.3') - .click(); - - // wait scroll timeout - cy.wait(500); - - cy.isInViewport('#section-23'); - }); - }); - - it('should navigate to a specific fragment within the page via the table of contents - Level 2', () => { - return cy.getTechDocsShadowRoot().within(() => { - cy.isNotInViewport('#sub-section-222'); - // Section 2.2 - cy.getTechDocsTableOfContents() - .find('a') - .contains('Section 2.2.2') - .click(); - - // wait scroll timeout - cy.wait(500); - - cy.isInViewport('#sub-section-222'); - }); - }); - - it('should navigate to a specific TechDocs page fragment from a link', () => { - return cy.getTechDocsShadowRoot().within(() => { - cy.get('article').contains('Link to Section 1.1').click(); - - cy.location().should(loc => { - expect(loc.pathname).to.eq( - '/docs/default/Component/techdocs-e2e-fixture/sub-page-one/', - ); - expect(loc.hash).to.eq('#section-11'); - }); - }); - }); - - it('should navigate to the next page within a TechDocs entity', () => { - return cy.getTechDocsShadowRoot().within(() => { - cy.get('footer a').contains('Sub-page 3').click(); - - cy.location().should(loc => { - expect(loc.pathname).to.eq( - '/docs/default/Component/techdocs-e2e-fixture/sub-page-three/', - ); - }); - }); - }); - - it('should navigate to the previous page within a TechDocs entity', () => { - return cy.getTechDocsShadowRoot().within(() => { - cy.get('footer a').contains('Sub-page 1').click(); - - cy.location().should(loc => { - expect(loc.pathname).to.eq( - '/docs/default/Component/techdocs-e2e-fixture/sub-page-one/', - ); - }); - }); - }); - }); - }); -}); diff --git a/cypress/src/support/commands.ts b/cypress/src/support/commands.ts deleted file mode 100644 index 62e21a5bef..0000000000 --- a/cypress/src/support/commands.ts +++ /dev/null @@ -1,125 +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. - */ -/* eslint-disable jest/no-standalone-expect */ -/// -import 'os'; - -Cypress.Commands.add('loginAsGuest', () => { - cy.visit('/', { - onLoad: (win: Window) => - win.localStorage.setItem('@backstage/core:SignInPage:provider', 'guest'), - }); -}); - -Cypress.Commands.add('getTechDocsShadowRoot', () => { - cy.get('[data-testid="techdocs-native-shadowroot"]').shadow(); -}); - -Cypress.Commands.add('isNotInViewport', element => { - cy.get(element).then($el => { - const bottom = Cypress.config(`viewportHeight`); - const rect = $el[0].getBoundingClientRect(); - - if (bottom) { - expect(rect.top).to.be.greaterThan(bottom); - expect(rect.bottom).to.be.greaterThan(bottom); - expect(rect.top).to.be.greaterThan(bottom); - expect(rect.bottom).to.be.greaterThan(bottom); - } - }); -}); - -Cypress.Commands.add('isInViewport', element => { - cy.get(element).then($el => { - const bottom = Cypress.config(`viewportHeight`); - const rect = $el[0].getBoundingClientRect(); - - if (bottom) { - expect(rect.top).not.to.be.greaterThan(bottom); - expect(rect.bottom).not.to.be.greaterThan(bottom); - expect(rect.top).not.to.be.greaterThan(bottom); - expect(rect.bottom).not.to.be.greaterThan(bottom); - } - }); -}); - -Cypress.Commands.add('getTechDocsTableOfContents', () => { - cy.get('[data-md-type="toc"]'); -}); - -Cypress.Commands.add('getTechDocsNavigation', () => { - cy.get('[data-md-type="navigation"]'); -}); - -Cypress.Commands.add('getCatalogDocsTab', () => { - cy.get('button[role="tab"]').contains('Docs'); -}); - -Cypress.Commands.add('mockSockJSNode', () => { - cy.intercept('GET', '**/sockjs-node/info**', { - body: { - websocket: true, - origins: ['*:*'], - cookie_needed: false, - entropy: 2882389500, - }, - }); -}); - -Cypress.Commands.add('interceptTechDocsAPICalls', () => { - cy.intercept( - 'GET', - '**/techdocs/metadata/entity/default/Component/techdocs-e2e-fixture', - ).as('entityMetadata'); - - cy.intercept( - 'GET', - '**/techdocs/metadata/techdocs/default/Component/techdocs-e2e-fixture', - ).as('techdocsMetadata'); - - cy.intercept( - 'GET', - '**/techdocs/sync/default/Component/techdocs-e2e-fixture', - ).as('syncEntity'); - - cy.intercept( - 'GET', - '**/techdocs/static/docs/default/Component/techdocs-e2e-fixture/sub-page-two/index.html', - ).as('sectionTwoHTML'); - - cy.intercept( - 'GET', - '**/techdocs/static/docs/default/Component/techdocs-e2e-fixture/index.html', - ).as('homeHTML'); -}); - -Cypress.Commands.add('waitSectionTwoPage', () => { - cy.wait([ - '@entityMetadata', - '@syncEntity', - '@techdocsMetadata', - '@sectionTwoHTML', - ]); -}); - -Cypress.Commands.add('waitHomePage', () => { - cy.wait(['@entityMetadata', '@syncEntity', '@techdocsMetadata', '@homeHTML']); -}); - -Cypress.Commands.add('checkForErrors', () => { - // when an error occurs there is a

with an "alert" role attribute. This can change ofc => we shall add also some positive ("when error occurs") test - cy.get('div[role="alert"]').should('not.exist'); -}); diff --git a/cypress/src/support/index.ts b/cypress/src/support/index.ts deleted file mode 100644 index 6d1051a793..0000000000 --- a/cypress/src/support/index.ts +++ /dev/null @@ -1,17 +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 './commands'; diff --git a/cypress/src/types.d.ts b/cypress/src/types.d.ts deleted file mode 100644 index dca22112e9..0000000000 --- a/cypress/src/types.d.ts +++ /dev/null @@ -1,86 +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. - */ -declare module 'zombie'; -declare module 'pgtools'; -declare namespace Cypress { - interface Chainable { - /** - * Login as guest - * @example cy.loginAsGuests - */ - loginAsGuest(): Chainable; - /** - * Get the TechDocs shadow root element - * @example cy.getTechDocsShadowRoot - */ - getTechDocsShadowRoot(): Chainable; - /** - * Mock TechDocs backend API - * @example cy.mockTechDocs - */ - mockTechDocs(): void; - /** - * Get the TechDocs table of contents element - * @example cy.getTechDocsShadowRoot - */ - getTechDocsTableOfContents(): Chainable; - /** - * Get the TechDocs navigation element - * @example cy.getTechDocsNavigation - */ - getTechDocsNavigation(): Chainable; - /** - * Get the Catalog docs tab - * @example cy.getCatalogDocsTab - */ - getCatalogDocsTab(): Chainable; - /** - * Intercept the TechDocs API calls - * @example cy.interceptTechDocsAPICalls - */ - interceptTechDocsAPICalls(): Chainable; - /** - * Mock SockJS-Node call - * @example cy.mockSockJSNode - */ - mockSockJSNode(): Chainable; - /** - * Wait TechDocs API response for home page - * @example cy.waitHomePage - */ - waitHomePage(): Chainable; - /** - * Wait TechDocs API response for Section 2 page - * @example cy.waitSectionTwoPage - */ - waitSectionTwoPage(): Chainable; - /** - * Check if the element is in viewport - * @example cy.isInViewport - */ - isInViewport(element: string): Chainable; - /** - * Check if the element is not in viewport - * @example cy.isNotInViewport - */ - isNotInViewport(element: string): Chainable; - /** - * Check if we have not caused error by our last action - * @example cy.checkForErrors - */ - checkForErrors(): Chainable; - } -} diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts deleted file mode 100644 index fd4db77d61..0000000000 --- a/cypress/support/commands.ts +++ /dev/null @@ -1,52 +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. - */ - -// *********************************************** -// This example commands.ts shows you how to -// create various custom commands and overwrite -// existing commands. -// -// For more comprehensive examples of custom -// commands please read more here: -// https://on.cypress.io/custom-commands -// *********************************************** -// -// -// -- This is a parent command -- -// Cypress.Commands.add('login', (email, password) => { ... }) -// -// -// -- This is a child command -- -// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... }) -// -// -// -- This is a dual command -- -// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... }) -// -// -// -- This will overwrite an existing command -- -// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) -// -// declare global { -// namespace Cypress { -// interface Chainable { -// login(email: string, password: string): Chainable -// drag(subject: string, options?: Partial): Chainable -// dismiss(subject: string, options?: Partial): Chainable -// visit(originalFn: CommandOriginalFn, url: string, options: Partial): Chainable -// } -// } -// } diff --git a/cypress/support/e2e.ts b/cypress/support/e2e.ts deleted file mode 100644 index c71790471e..0000000000 --- a/cypress/support/e2e.ts +++ /dev/null @@ -1,35 +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. - */ - -// This example support/e2e.ts is processed and -// loaded automatically before your test files. -// -// This is a great place to put global configuration and -// behavior that modifies Cypress. -// -// You can change the location of this file or turn off -// automatically serving support files with the -// 'supportFile' configuration option. -// -// You can read more here: -// https://on.cypress.io/configuration -// *********************************************************** - -// Import commands.js using ES2015 syntax: -import './commands'; - -// Alternatively you can use CommonJS syntax: -// require('./commands') diff --git a/cypress/tsconfig.json b/cypress/tsconfig.json deleted file mode 100644 index 9c4a63b76c..0000000000 --- a/cypress/tsconfig.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "compilerOptions": { - "allowJs": true, - "declaration": true, - "declarationMap": false, - "esModuleInterop": true, - "experimentalDecorators": false, - "forceConsistentCasingInFileNames": true, - "importHelpers": false, - "incremental": true, - "isolatedModules": true, - "jsx": "react", - "lib": ["DOM", "DOM.Iterable", "ScriptHost", "ES2021", "ESNext.Promise"], - "module": "ESNext", - "moduleResolution": "node", - "noEmit": true, - "noFallthroughCasesInSwitch": true, - "noImplicitAny": true, - "noImplicitReturns": true, - "noImplicitThis": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "pretty": true, - "removeComments": false, - "resolveJsonModule": true, - "sourceMap": false, - "skipLibCheck": false, - "strict": true, - "strictBindCallApply": true, - "strictFunctionTypes": true, - "strictNullChecks": true, - "strictPropertyInitialization": true, - "stripInternal": true, - "target": "ES2021", - "types": ["node", "cypress"] - } -} diff --git a/cypress/yarn.lock b/cypress/yarn.lock deleted file mode 100644 index 290f441c4c..0000000000 --- a/cypress/yarn.lock +++ /dev/null @@ -1,1526 +0,0 @@ -# This file is generated by running "yarn install" inside your project. -# Manual changes might be lost - proceed with caution! - -__metadata: - version: 6 - cacheKey: 8 - -"@backstage/cypress-tests@workspace:.": - version: 0.0.0-use.local - resolution: "@backstage/cypress-tests@workspace:." - dependencies: - cypress: ^10.0.0 - typescript: ^4.1.3 - languageName: unknown - linkType: soft - -"@colors/colors@npm:1.5.0": - version: 1.5.0 - resolution: "@colors/colors@npm:1.5.0" - checksum: d64d5260bed1d5012ae3fc617d38d1afc0329fec05342f4e6b838f46998855ba56e0a73833f4a80fa8378c84810da254f76a8a19c39d038260dc06dc4e007425 - languageName: node - linkType: hard - -"@cypress/request@npm:^2.88.10": - version: 2.88.10 - resolution: "@cypress/request@npm:2.88.10" - dependencies: - aws-sign2: ~0.7.0 - aws4: ^1.8.0 - caseless: ~0.12.0 - combined-stream: ~1.0.6 - extend: ~3.0.2 - forever-agent: ~0.6.1 - form-data: ~2.3.2 - http-signature: ~1.3.6 - is-typedarray: ~1.0.0 - isstream: ~0.1.2 - json-stringify-safe: ~5.0.1 - mime-types: ~2.1.19 - performance-now: ^2.1.0 - qs: ~6.5.2 - safe-buffer: ^5.1.2 - tough-cookie: ~2.5.0 - tunnel-agent: ^0.6.0 - uuid: ^8.3.2 - checksum: 69c3e3b332e9be4866a900f6bcca5d274d8cea6c99707fbcce061de8dbab11c9b1e39f4c017f6e83e6e682717781d4f6106fd6b7cf9546580fcfac353b6676cf - languageName: node - linkType: hard - -"@cypress/xvfb@npm:^1.2.4": - version: 1.2.4 - resolution: "@cypress/xvfb@npm:1.2.4" - dependencies: - debug: ^3.1.0 - lodash.once: ^4.1.1 - checksum: 7bdcdaeb1bb692ec9d9bf8ec52538aa0bead6764753f4a067a171a511807a43fab016f7285a56bef6a606c2467ff3f1365e1ad2d2d583b81beed849ee1573fd1 - languageName: node - linkType: hard - -"@types/node@npm:*": - version: 18.7.14 - resolution: "@types/node@npm:18.7.14" - checksum: 99cf28ff854100158de875cca23c7acc3cc01dfee526a52b90b7f36767c821bcbaf2be0a98a70f06f3b78f3c60639168ff949d725b61e2e124f9f71f1fb8043d - languageName: node - linkType: hard - -"@types/node@npm:^14.14.31": - version: 14.18.26 - resolution: "@types/node@npm:14.18.26" - checksum: c6ac3f9d4f6f77c0fa5ac17757779ad4d9835abfe3af5708b7552597cb5c7c1103e83499ccaf767a1cfa70040990bcf3f58761c547051dc8d5077f3c419091b1 - languageName: node - linkType: hard - -"@types/sinonjs__fake-timers@npm:8.1.1": - version: 8.1.1 - resolution: "@types/sinonjs__fake-timers@npm:8.1.1" - checksum: ca09d54d47091d87020824a73f026300fa06b17cd9f2f9b9387f28b549364b141ef194ee28db762f6588de71d8febcd17f753163cb7ea116b8387c18e80ebd5c - languageName: node - linkType: hard - -"@types/sizzle@npm:^2.3.2": - version: 2.3.3 - resolution: "@types/sizzle@npm:2.3.3" - checksum: 586a9fb1f6ff3e325e0f2cc1596a460615f0bc8a28f6e276ac9b509401039dd242fa8b34496d3a30c52f5b495873922d09a9e76c50c2ab2bcc70ba3fb9c4e160 - languageName: node - linkType: hard - -"@types/yauzl@npm:^2.9.1": - version: 2.10.0 - resolution: "@types/yauzl@npm:2.10.0" - dependencies: - "@types/node": "*" - checksum: 55d27ae5d346ea260e40121675c24e112ef0247649073848e5d4e03182713ae4ec8142b98f61a1c6cbe7d3b72fa99bbadb65d8b01873e5e605cdc30f1ff70ef2 - languageName: node - linkType: hard - -"aggregate-error@npm:^3.0.0": - version: 3.1.0 - resolution: "aggregate-error@npm:3.1.0" - dependencies: - clean-stack: ^2.0.0 - indent-string: ^4.0.0 - checksum: 1101a33f21baa27a2fa8e04b698271e64616b886795fd43c31068c07533c7b3facfcaf4e9e0cab3624bd88f729a592f1c901a1a229c9e490eafce411a8644b79 - languageName: node - linkType: hard - -"ansi-colors@npm:^4.1.1": - version: 4.1.3 - resolution: "ansi-colors@npm:4.1.3" - checksum: a9c2ec842038a1fabc7db9ece7d3177e2fe1c5dc6f0c51ecfbf5f39911427b89c00b5dc6b8bd95f82a26e9b16aaae2e83d45f060e98070ce4d1333038edceb0e - languageName: node - linkType: hard - -"ansi-escapes@npm:^4.3.0": - version: 4.3.2 - resolution: "ansi-escapes@npm:4.3.2" - dependencies: - type-fest: ^0.21.3 - checksum: 93111c42189c0a6bed9cdb4d7f2829548e943827ee8479c74d6e0b22ee127b2a21d3f8b5ca57723b8ef78ce011fbfc2784350eb2bde3ccfccf2f575fa8489815 - languageName: node - linkType: hard - -"ansi-regex@npm:^5.0.1": - version: 5.0.1 - resolution: "ansi-regex@npm:5.0.1" - checksum: 2aa4bb54caf2d622f1afdad09441695af2a83aa3fe8b8afa581d205e57ed4261c183c4d3877cee25794443fde5876417d859c108078ab788d6af7e4fe52eb66b - languageName: node - linkType: hard - -"ansi-styles@npm:^4.0.0, ansi-styles@npm:^4.1.0": - version: 4.3.0 - resolution: "ansi-styles@npm:4.3.0" - dependencies: - color-convert: ^2.0.1 - checksum: 513b44c3b2105dd14cc42a19271e80f386466c4be574bccf60b627432f9198571ebf4ab1e4c3ba17347658f4ee1711c163d574248c0c1cdc2d5917a0ad582ec4 - languageName: node - linkType: hard - -"arch@npm:^2.2.0": - version: 2.2.0 - resolution: "arch@npm:2.2.0" - checksum: e21b7635029fe8e9cdd5a026f9a6c659103e63fff423834323cdf836a1bb240a72d0c39ca8c470f84643385cf581bd8eda2cad8bf493e27e54bd9783abe9101f - languageName: node - linkType: hard - -"asn1@npm:~0.2.3": - version: 0.2.6 - resolution: "asn1@npm:0.2.6" - dependencies: - safer-buffer: ~2.1.0 - checksum: 39f2ae343b03c15ad4f238ba561e626602a3de8d94ae536c46a4a93e69578826305366dc09fbb9b56aec39b4982a463682f259c38e59f6fa380cd72cd61e493d - languageName: node - linkType: hard - -"assert-plus@npm:1.0.0, assert-plus@npm:^1.0.0": - version: 1.0.0 - resolution: "assert-plus@npm:1.0.0" - checksum: 19b4340cb8f0e6a981c07225eacac0e9d52c2644c080198765d63398f0075f83bbc0c8e95474d54224e297555ad0d631c1dcd058adb1ddc2437b41a6b424ac64 - languageName: node - linkType: hard - -"astral-regex@npm:^2.0.0": - version: 2.0.0 - resolution: "astral-regex@npm:2.0.0" - checksum: 876231688c66400473ba505731df37ea436e574dd524520294cc3bbc54ea40334865e01fa0d074d74d036ee874ee7e62f486ea38bc421ee8e6a871c06f011766 - languageName: node - linkType: hard - -"async@npm:^3.2.0": - version: 3.2.4 - resolution: "async@npm:3.2.4" - checksum: 43d07459a4e1d09b84a20772414aa684ff4de085cbcaec6eea3c7a8f8150e8c62aa6cd4e699fe8ee93c3a5b324e777d34642531875a0817a35697522c1b02e89 - languageName: node - linkType: hard - -"asynckit@npm:^0.4.0": - version: 0.4.0 - resolution: "asynckit@npm:0.4.0" - checksum: 7b78c451df768adba04e2d02e63e2d0bf3b07adcd6e42b4cf665cb7ce899bedd344c69a1dcbce355b5f972d597b25aaa1c1742b52cffd9caccb22f348114f6be - languageName: node - linkType: hard - -"at-least-node@npm:^1.0.0": - version: 1.0.0 - resolution: "at-least-node@npm:1.0.0" - checksum: 463e2f8e43384f1afb54bc68485c436d7622acec08b6fad269b421cb1d29cebb5af751426793d0961ed243146fe4dc983402f6d5a51b720b277818dbf6f2e49e - languageName: node - linkType: hard - -"aws-sign2@npm:~0.7.0": - version: 0.7.0 - resolution: "aws-sign2@npm:0.7.0" - checksum: b148b0bb0778098ad8cf7e5fc619768bcb51236707ca1d3e5b49e41b171166d8be9fdc2ea2ae43d7decf02989d0aaa3a9c4caa6f320af95d684de9b548a71525 - languageName: node - linkType: hard - -"aws4@npm:^1.8.0": - version: 1.11.0 - resolution: "aws4@npm:1.11.0" - checksum: 5a00d045fd0385926d20ebebcfba5ec79d4482fe706f63c27b324d489a04c68edb0db99ed991e19eda09cb8c97dc2452059a34d97545cebf591d7a2b5a10999f - languageName: node - linkType: hard - -"balanced-match@npm:^1.0.0": - version: 1.0.2 - resolution: "balanced-match@npm:1.0.2" - checksum: 9706c088a283058a8a99e0bf91b0a2f75497f185980d9ffa8b304de1d9e58ebda7c72c07ebf01dadedaac5b2907b2c6f566f660d62bd336c3468e960403b9d65 - languageName: node - linkType: hard - -"base64-js@npm:^1.3.1": - version: 1.5.1 - resolution: "base64-js@npm:1.5.1" - checksum: 669632eb3745404c2f822a18fc3a0122d2f9a7a13f7fb8b5823ee19d1d2ff9ee5b52c53367176ea4ad093c332fd5ab4bd0ebae5a8e27917a4105a4cfc86b1005 - languageName: node - linkType: hard - -"bcrypt-pbkdf@npm:^1.0.0": - version: 1.0.2 - resolution: "bcrypt-pbkdf@npm:1.0.2" - dependencies: - tweetnacl: ^0.14.3 - checksum: 4edfc9fe7d07019609ccf797a2af28351736e9d012c8402a07120c4453a3b789a15f2ee1530dc49eee8f7eb9379331a8dd4b3766042b9e502f74a68e7f662291 - languageName: node - linkType: hard - -"blob-util@npm:^2.0.2": - version: 2.0.2 - resolution: "blob-util@npm:2.0.2" - checksum: d543e6b92e4ca715ca33c78e89a07a2290d43e5b2bc897d7ec588c5c7bbf59df93e45225ac0c9258aa6ce4320358990f99c9288f1c48280f8ec5d7a2e088d19b - languageName: node - linkType: hard - -"bluebird@npm:^3.7.2": - version: 3.7.2 - resolution: "bluebird@npm:3.7.2" - checksum: 869417503c722e7dc54ca46715f70e15f4d9c602a423a02c825570862d12935be59ed9c7ba34a9b31f186c017c23cac6b54e35446f8353059c101da73eac22ef - languageName: node - linkType: hard - -"brace-expansion@npm:^1.1.7": - version: 1.1.11 - resolution: "brace-expansion@npm:1.1.11" - dependencies: - balanced-match: ^1.0.0 - concat-map: 0.0.1 - checksum: faf34a7bb0c3fcf4b59c7808bc5d2a96a40988addf2e7e09dfbb67a2251800e0d14cd2bfc1aa79174f2f5095c54ff27f46fb1289fe2d77dac755b5eb3434cc07 - languageName: node - linkType: hard - -"buffer-crc32@npm:~0.2.3": - version: 0.2.13 - resolution: "buffer-crc32@npm:0.2.13" - checksum: 06252347ae6daca3453b94e4b2f1d3754a3b146a111d81c68924c22d91889a40623264e95e67955b1cb4a68cbedf317abeabb5140a9766ed248973096db5ce1c - languageName: node - linkType: hard - -"buffer@npm:^5.6.0": - version: 5.7.1 - resolution: "buffer@npm:5.7.1" - dependencies: - base64-js: ^1.3.1 - ieee754: ^1.1.13 - checksum: e2cf8429e1c4c7b8cbd30834ac09bd61da46ce35f5c22a78e6c2f04497d6d25541b16881e30a019c6fd3154150650ccee27a308eff3e26229d788bbdeb08ab84 - languageName: node - linkType: hard - -"cachedir@npm:^2.3.0": - version: 2.3.0 - resolution: "cachedir@npm:2.3.0" - checksum: ec90cb0f2e6336e266aa748dbadf3da9e0b20e843e43f1591acab7a3f1451337dc2f26cb9dd833ae8cfefeffeeb43ef5b5ff62782a685f4e3c2305dd98482fcb - languageName: node - linkType: hard - -"caseless@npm:~0.12.0": - version: 0.12.0 - resolution: "caseless@npm:0.12.0" - checksum: b43bd4c440aa1e8ee6baefee8063b4850fd0d7b378f6aabc796c9ec8cb26d27fb30b46885350777d9bd079c5256c0e1329ad0dc7c2817e0bb466810ebb353751 - languageName: node - linkType: hard - -"chalk@npm:^4.1.0": - version: 4.1.2 - resolution: "chalk@npm:4.1.2" - dependencies: - ansi-styles: ^4.1.0 - supports-color: ^7.1.0 - checksum: fe75c9d5c76a7a98d45495b91b2172fa3b7a09e0cc9370e5c8feb1c567b85c4288e2b3fded7cfdd7359ac28d6b3844feb8b82b8686842e93d23c827c417e83fc - languageName: node - linkType: hard - -"check-more-types@npm:^2.24.0": - version: 2.24.0 - resolution: "check-more-types@npm:2.24.0" - checksum: b09080ec3404d20a4b0ead828994b2e5913236ef44ed3033a27062af0004cf7d2091fbde4b396bf13b7ce02fb018bc9960b48305e6ab2304cd82d73ed7a51ef4 - languageName: node - linkType: hard - -"ci-info@npm:^3.2.0": - version: 3.3.2 - resolution: "ci-info@npm:3.3.2" - checksum: fd81f1edd2d3b0f6cb077b2e84365136d87b9db8c055928c1ad69da8a76c2c2f19cba8ea51b90238302157ca927f91f92b653e933f2398dde4867500f08d6e62 - languageName: node - linkType: hard - -"clean-stack@npm:^2.0.0": - version: 2.2.0 - resolution: "clean-stack@npm:2.2.0" - checksum: 2ac8cd2b2f5ec986a3c743935ec85b07bc174d5421a5efc8017e1f146a1cf5f781ae962618f416352103b32c9cd7e203276e8c28241bbe946160cab16149fb68 - languageName: node - linkType: hard - -"cli-cursor@npm:^3.1.0": - version: 3.1.0 - resolution: "cli-cursor@npm:3.1.0" - dependencies: - restore-cursor: ^3.1.0 - checksum: 2692784c6cd2fd85cfdbd11f53aea73a463a6d64a77c3e098b2b4697a20443f430c220629e1ca3b195ea5ac4a97a74c2ee411f3807abf6df2b66211fec0c0a29 - languageName: node - linkType: hard - -"cli-table3@npm:~0.6.1": - version: 0.6.2 - resolution: "cli-table3@npm:0.6.2" - dependencies: - "@colors/colors": 1.5.0 - string-width: ^4.2.0 - dependenciesMeta: - "@colors/colors": - optional: true - checksum: 2f82391698b8a2a2a5e45d2adcfea5d93e557207f90455a8d4c1aac688e9b18a204d9eb4ba1d322fa123b17d64ea3dc5e11de8b005529f3c3e7dbeb27cb4d9be - languageName: node - linkType: hard - -"cli-truncate@npm:^2.1.0": - version: 2.1.0 - resolution: "cli-truncate@npm:2.1.0" - dependencies: - slice-ansi: ^3.0.0 - string-width: ^4.2.0 - checksum: bf1e4e6195392dc718bf9cd71f317b6300dc4a9191d052f31046b8773230ece4fa09458813bf0e3455a5e68c0690d2ea2c197d14a8b85a7b5e01c97f4b5feb5d - languageName: node - linkType: hard - -"color-convert@npm:^2.0.1": - version: 2.0.1 - resolution: "color-convert@npm:2.0.1" - dependencies: - color-name: ~1.1.4 - checksum: 79e6bdb9fd479a205c71d89574fccfb22bd9053bd98c6c4d870d65c132e5e904e6034978e55b43d69fcaa7433af2016ee203ce76eeba9cfa554b373e7f7db336 - languageName: node - linkType: hard - -"color-name@npm:~1.1.4": - version: 1.1.4 - resolution: "color-name@npm:1.1.4" - checksum: b0445859521eb4021cd0fb0cc1a75cecf67fceecae89b63f62b201cca8d345baf8b952c966862a9d9a2632987d4f6581f0ec8d957dfacece86f0a7919316f610 - languageName: node - linkType: hard - -"colorette@npm:^2.0.16": - version: 2.0.19 - resolution: "colorette@npm:2.0.19" - checksum: 888cf5493f781e5fcf54ce4d49e9d7d698f96ea2b2ef67906834bb319a392c667f9ec69f4a10e268d2946d13a9503d2d19b3abaaaf174e3451bfe91fb9d82427 - languageName: node - linkType: hard - -"combined-stream@npm:^1.0.6, combined-stream@npm:~1.0.6": - version: 1.0.8 - resolution: "combined-stream@npm:1.0.8" - dependencies: - delayed-stream: ~1.0.0 - checksum: 49fa4aeb4916567e33ea81d088f6584749fc90c7abec76fd516bf1c5aa5c79f3584b5ba3de6b86d26ddd64bae5329c4c7479343250cfe71c75bb366eae53bb7c - languageName: node - linkType: hard - -"commander@npm:^5.1.0": - version: 5.1.0 - resolution: "commander@npm:5.1.0" - checksum: 0b7fec1712fbcc6230fcb161d8d73b4730fa91a21dc089515489402ad78810547683f058e2a9835929c212fead1d6a6ade70db28bbb03edbc2829a9ab7d69447 - languageName: node - linkType: hard - -"common-tags@npm:^1.8.0": - version: 1.8.2 - resolution: "common-tags@npm:1.8.2" - checksum: 767a6255a84bbc47df49a60ab583053bb29a7d9687066a18500a516188a062c4e4cd52de341f22de0b07062e699b1b8fe3cfa1cb55b241cb9301aeb4f45b4dff - languageName: node - linkType: hard - -"concat-map@npm:0.0.1": - version: 0.0.1 - resolution: "concat-map@npm:0.0.1" - checksum: 902a9f5d8967a3e2faf138d5cb784b9979bad2e6db5357c5b21c568df4ebe62bcb15108af1b2253744844eb964fc023fbd9afbbbb6ddd0bcc204c6fb5b7bf3af - languageName: node - linkType: hard - -"core-util-is@npm:1.0.2": - version: 1.0.2 - resolution: "core-util-is@npm:1.0.2" - checksum: 7a4c925b497a2c91421e25bf76d6d8190f0b2359a9200dbeed136e63b2931d6294d3b1893eda378883ed363cd950f44a12a401384c609839ea616befb7927dab - languageName: node - linkType: hard - -"cross-spawn@npm:^7.0.0": - version: 7.0.3 - resolution: "cross-spawn@npm:7.0.3" - dependencies: - path-key: ^3.1.0 - shebang-command: ^2.0.0 - which: ^2.0.1 - checksum: 671cc7c7288c3a8406f3c69a3ae2fc85555c04169e9d611def9a675635472614f1c0ed0ef80955d5b6d4e724f6ced67f0ad1bb006c2ea643488fcfef994d7f52 - languageName: node - linkType: hard - -"cypress@npm:^10.0.0": - version: 10.11.0 - resolution: "cypress@npm:10.11.0" - dependencies: - "@cypress/request": ^2.88.10 - "@cypress/xvfb": ^1.2.4 - "@types/node": ^14.14.31 - "@types/sinonjs__fake-timers": 8.1.1 - "@types/sizzle": ^2.3.2 - arch: ^2.2.0 - blob-util: ^2.0.2 - bluebird: ^3.7.2 - buffer: ^5.6.0 - cachedir: ^2.3.0 - chalk: ^4.1.0 - check-more-types: ^2.24.0 - cli-cursor: ^3.1.0 - cli-table3: ~0.6.1 - commander: ^5.1.0 - common-tags: ^1.8.0 - dayjs: ^1.10.4 - debug: ^4.3.2 - enquirer: ^2.3.6 - eventemitter2: 6.4.7 - execa: 4.1.0 - executable: ^4.1.1 - extract-zip: 2.0.1 - figures: ^3.2.0 - fs-extra: ^9.1.0 - getos: ^3.2.1 - is-ci: ^3.0.0 - is-installed-globally: ~0.4.0 - lazy-ass: ^1.6.0 - listr2: ^3.8.3 - lodash: ^4.17.21 - log-symbols: ^4.0.0 - minimist: ^1.2.6 - ospath: ^1.2.2 - pretty-bytes: ^5.6.0 - proxy-from-env: 1.0.0 - request-progress: ^3.0.0 - semver: ^7.3.2 - supports-color: ^8.1.1 - tmp: ~0.2.1 - untildify: ^4.0.0 - yauzl: ^2.10.0 - bin: - cypress: bin/cypress - checksum: 938cc6a20f7eeace5c8e850d234904ee1651cbb36d94666fe600cf17ce964e73d4f7d8d944aab677491702a57364e6aceeb4fe8bcbd96147ff5e2b575a956fb2 - languageName: node - linkType: hard - -"dashdash@npm:^1.12.0": - version: 1.14.1 - resolution: "dashdash@npm:1.14.1" - dependencies: - assert-plus: ^1.0.0 - checksum: 3634c249570f7f34e3d34f866c93f866c5b417f0dd616275decae08147dcdf8fccfaa5947380ccfb0473998ea3a8057c0b4cd90c875740ee685d0624b2983598 - languageName: node - linkType: hard - -"dayjs@npm:^1.10.4": - version: 1.11.5 - resolution: "dayjs@npm:1.11.5" - checksum: e3bbaa7b4883b31be4bf75a181f1447fbb19800c29b332852125aab96baeff3ac232dcba8b88c4ea17d3b636c99dac5fb9d1af4bb6ae26615698bbc4a852dffb - languageName: node - linkType: hard - -"debug@npm:^3.1.0": - version: 3.2.7 - resolution: "debug@npm:3.2.7" - dependencies: - ms: ^2.1.1 - checksum: b3d8c5940799914d30314b7c3304a43305fd0715581a919dacb8b3176d024a782062368405b47491516d2091d6462d4d11f2f4974a405048094f8bfebfa3071c - languageName: node - linkType: hard - -"debug@npm:^4.1.1, debug@npm:^4.3.2": - version: 4.3.4 - resolution: "debug@npm:4.3.4" - dependencies: - ms: 2.1.2 - peerDependenciesMeta: - supports-color: - optional: true - checksum: 3dbad3f94ea64f34431a9cbf0bafb61853eda57bff2880036153438f50fb5a84f27683ba0d8e5426bf41a8c6ff03879488120cf5b3a761e77953169c0600a708 - languageName: node - linkType: hard - -"delayed-stream@npm:~1.0.0": - version: 1.0.0 - resolution: "delayed-stream@npm:1.0.0" - checksum: 46fe6e83e2cb1d85ba50bd52803c68be9bd953282fa7096f51fc29edd5d67ff84ff753c51966061e5ba7cb5e47ef6d36a91924eddb7f3f3483b1c560f77a0020 - languageName: node - linkType: hard - -"ecc-jsbn@npm:~0.1.1": - version: 0.1.2 - resolution: "ecc-jsbn@npm:0.1.2" - dependencies: - jsbn: ~0.1.0 - safer-buffer: ^2.1.0 - checksum: 22fef4b6203e5f31d425f5b711eb389e4c6c2723402e389af394f8411b76a488fa414d309d866e2b577ce3e8462d344205545c88a8143cc21752a5172818888a - languageName: node - linkType: hard - -"emoji-regex@npm:^8.0.0": - version: 8.0.0 - resolution: "emoji-regex@npm:8.0.0" - checksum: d4c5c39d5a9868b5fa152f00cada8a936868fd3367f33f71be515ecee4c803132d11b31a6222b2571b1e5f7e13890156a94880345594d0ce7e3c9895f560f192 - languageName: node - linkType: hard - -"end-of-stream@npm:^1.1.0": - version: 1.4.4 - resolution: "end-of-stream@npm:1.4.4" - dependencies: - once: ^1.4.0 - checksum: 530a5a5a1e517e962854a31693dbb5c0b2fc40b46dad2a56a2deec656ca040631124f4795823acc68238147805f8b021abbe221f4afed5ef3c8e8efc2024908b - languageName: node - linkType: hard - -"enquirer@npm:^2.3.6": - version: 2.3.6 - resolution: "enquirer@npm:2.3.6" - dependencies: - ansi-colors: ^4.1.1 - checksum: 1c0911e14a6f8d26721c91e01db06092a5f7675159f0261d69c403396a385afd13dd76825e7678f66daffa930cfaa8d45f506fb35f818a2788463d022af1b884 - languageName: node - linkType: hard - -"escape-string-regexp@npm:^1.0.5": - version: 1.0.5 - resolution: "escape-string-regexp@npm:1.0.5" - checksum: 6092fda75c63b110c706b6a9bfde8a612ad595b628f0bd2147eea1d3406723020810e591effc7db1da91d80a71a737a313567c5abb3813e8d9c71f4aa595b410 - languageName: node - linkType: hard - -"eventemitter2@npm:6.4.7": - version: 6.4.7 - resolution: "eventemitter2@npm:6.4.7" - checksum: 1b36a77e139d6965ebf3a36c01fa00c089ae6b80faa1911e52888f40b3a7057b36a2cc45dcd1ad87cda3798fe7b97a0aabcbb8175a8b96092a23bb7d0f039e66 - languageName: node - linkType: hard - -"execa@npm:4.1.0": - version: 4.1.0 - resolution: "execa@npm:4.1.0" - dependencies: - cross-spawn: ^7.0.0 - get-stream: ^5.0.0 - human-signals: ^1.1.1 - is-stream: ^2.0.0 - merge-stream: ^2.0.0 - npm-run-path: ^4.0.0 - onetime: ^5.1.0 - signal-exit: ^3.0.2 - strip-final-newline: ^2.0.0 - checksum: e30d298934d9c52f90f3847704fd8224e849a081ab2b517bbc02f5f7732c24e56a21f14cb96a08256deffeb2d12b2b7cb7e2b014a12fb36f8d3357e06417ed55 - languageName: node - linkType: hard - -"executable@npm:^4.1.1": - version: 4.1.1 - resolution: "executable@npm:4.1.1" - dependencies: - pify: ^2.2.0 - checksum: f01927ce59bccec804e171bf859a26e362c1f50aa9ebc69f7cafdcce3859d29d4b6267fd47237c18b0a1830614bd3f0ee14b7380d9bad18a4e7af9b5f0b6984f - languageName: node - linkType: hard - -"extend@npm:~3.0.2": - version: 3.0.2 - resolution: "extend@npm:3.0.2" - checksum: a50a8309ca65ea5d426382ff09f33586527882cf532931cb08ca786ea3146c0553310bda688710ff61d7668eba9f96b923fe1420cdf56a2c3eaf30fcab87b515 - languageName: node - linkType: hard - -"extract-zip@npm:2.0.1": - version: 2.0.1 - resolution: "extract-zip@npm:2.0.1" - dependencies: - "@types/yauzl": ^2.9.1 - debug: ^4.1.1 - get-stream: ^5.1.0 - yauzl: ^2.10.0 - dependenciesMeta: - "@types/yauzl": - optional: true - bin: - extract-zip: cli.js - checksum: 8cbda9debdd6d6980819cc69734d874ddd71051c9fe5bde1ef307ebcedfe949ba57b004894b585f758b7c9eeeea0e3d87f2dda89b7d25320459c2c9643ebb635 - languageName: node - linkType: hard - -"extsprintf@npm:1.3.0": - version: 1.3.0 - resolution: "extsprintf@npm:1.3.0" - checksum: cee7a4a1e34cffeeec18559109de92c27517e5641991ec6bab849aa64e3081022903dd53084f2080d0d2530803aa5ee84f1e9de642c365452f9e67be8f958ce2 - languageName: node - linkType: hard - -"extsprintf@npm:^1.2.0": - version: 1.4.1 - resolution: "extsprintf@npm:1.4.1" - checksum: a2f29b241914a8d2bad64363de684821b6b1609d06ae68d5b539e4de6b28659715b5bea94a7265201603713b7027d35399d10b0548f09071c5513e65e8323d33 - languageName: node - linkType: hard - -"fd-slicer@npm:~1.1.0": - version: 1.1.0 - resolution: "fd-slicer@npm:1.1.0" - dependencies: - pend: ~1.2.0 - checksum: c8585fd5713f4476eb8261150900d2cb7f6ff2d87f8feb306ccc8a1122efd152f1783bdb2b8dc891395744583436bfd8081d8e63ece0ec8687eeefea394d4ff2 - languageName: node - linkType: hard - -"figures@npm:^3.2.0": - version: 3.2.0 - resolution: "figures@npm:3.2.0" - dependencies: - escape-string-regexp: ^1.0.5 - checksum: 85a6ad29e9aca80b49b817e7c89ecc4716ff14e3779d9835af554db91bac41c0f289c418923519392a1e582b4d10482ad282021330cd045bb7b80c84152f2a2b - languageName: node - linkType: hard - -"forever-agent@npm:~0.6.1": - version: 0.6.1 - resolution: "forever-agent@npm:0.6.1" - checksum: 766ae6e220f5fe23676bb4c6a99387cec5b7b62ceb99e10923376e27bfea72f3c3aeec2ba5f45f3f7ba65d6616965aa7c20b15002b6860833bb6e394dea546a8 - languageName: node - linkType: hard - -"form-data@npm:~2.3.2": - version: 2.3.3 - resolution: "form-data@npm:2.3.3" - dependencies: - asynckit: ^0.4.0 - combined-stream: ^1.0.6 - mime-types: ^2.1.12 - checksum: 10c1780fa13dbe1ff3100114c2ce1f9307f8be10b14bf16e103815356ff567b6be39d70fc4a40f8990b9660012dc24b0f5e1dde1b6426166eb23a445ba068ca3 - languageName: node - linkType: hard - -"fs-extra@npm:^9.1.0": - version: 9.1.0 - resolution: "fs-extra@npm:9.1.0" - dependencies: - at-least-node: ^1.0.0 - graceful-fs: ^4.2.0 - jsonfile: ^6.0.1 - universalify: ^2.0.0 - checksum: ba71ba32e0faa74ab931b7a0031d1523c66a73e225de7426e275e238e312d07313d2da2d33e34a52aa406c8763ade5712eb3ec9ba4d9edce652bcacdc29e6b20 - languageName: node - linkType: hard - -"fs.realpath@npm:^1.0.0": - version: 1.0.0 - resolution: "fs.realpath@npm:1.0.0" - checksum: 99ddea01a7e75aa276c250a04eedeffe5662bce66c65c07164ad6264f9de18fb21be9433ead460e54cff20e31721c811f4fb5d70591799df5f85dce6d6746fd0 - languageName: node - linkType: hard - -"get-stream@npm:^5.0.0, get-stream@npm:^5.1.0": - version: 5.2.0 - resolution: "get-stream@npm:5.2.0" - dependencies: - pump: ^3.0.0 - checksum: 8bc1a23174a06b2b4ce600df38d6c98d2ef6d84e020c1ddad632ad75bac4e092eeb40e4c09e0761c35fc2dbc5e7fff5dab5e763a383582c4a167dd69a905bd12 - languageName: node - linkType: hard - -"getos@npm:^3.2.1": - version: 3.2.1 - resolution: "getos@npm:3.2.1" - dependencies: - async: ^3.2.0 - checksum: 42fd78a66d47cebd3e09de5566cc0044e034b08f4a000a310dbd89a77b02c65d8f4002554bfa495ea5bdc4fa9d515f5ac785a7cc474ba45383cc697f865eeaf1 - languageName: node - linkType: hard - -"getpass@npm:^0.1.1": - version: 0.1.7 - resolution: "getpass@npm:0.1.7" - dependencies: - assert-plus: ^1.0.0 - checksum: ab18d55661db264e3eac6012c2d3daeafaab7a501c035ae0ccb193c3c23e9849c6e29b6ac762b9c2adae460266f925d55a3a2a3a3c8b94be2f222df94d70c046 - languageName: node - linkType: hard - -"glob@npm:^7.1.3": - version: 7.2.3 - resolution: "glob@npm:7.2.3" - dependencies: - fs.realpath: ^1.0.0 - inflight: ^1.0.4 - inherits: 2 - minimatch: ^3.1.1 - once: ^1.3.0 - path-is-absolute: ^1.0.0 - checksum: 29452e97b38fa704dabb1d1045350fb2467cf0277e155aa9ff7077e90ad81d1ea9d53d3ee63bd37c05b09a065e90f16aec4a65f5b8de401d1dac40bc5605d133 - languageName: node - linkType: hard - -"global-dirs@npm:^3.0.0": - version: 3.0.0 - resolution: "global-dirs@npm:3.0.0" - dependencies: - ini: 2.0.0 - checksum: 953c17cf14bf6ee0e2100ae82a0d779934eed8a3ec5c94a7a4f37c5b3b592c31ea015fb9a15cf32484de13c79f4a814f3015152f3e1d65976cfbe47c1bfe4a88 - languageName: node - linkType: hard - -"graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0": - version: 4.2.10 - resolution: "graceful-fs@npm:4.2.10" - checksum: 3f109d70ae123951905d85032ebeae3c2a5a7a997430df00ea30df0e3a6c60cf6689b109654d6fdacd28810a053348c4d14642da1d075049e6be1ba5216218da - languageName: node - linkType: hard - -"has-flag@npm:^4.0.0": - version: 4.0.0 - resolution: "has-flag@npm:4.0.0" - checksum: 261a1357037ead75e338156b1f9452c016a37dcd3283a972a30d9e4a87441ba372c8b81f818cd0fbcd9c0354b4ae7e18b9e1afa1971164aef6d18c2b6095a8ad - languageName: node - linkType: hard - -"http-signature@npm:~1.3.6": - version: 1.3.6 - resolution: "http-signature@npm:1.3.6" - dependencies: - assert-plus: ^1.0.0 - jsprim: ^2.0.2 - sshpk: ^1.14.1 - checksum: 10be2af4764e71fee0281392937050201ee576ac755c543f570d6d87134ce5e858663fe999a7adb3e4e368e1e356d0d7fec6b9542295b875726ff615188e7a0c - languageName: node - linkType: hard - -"human-signals@npm:^1.1.1": - version: 1.1.1 - resolution: "human-signals@npm:1.1.1" - checksum: d587647c9e8ec24e02821b6be7de5a0fc37f591f6c4e319b3054b43fd4c35a70a94c46fc74d8c1a43c47fde157d23acd7421f375e1c1365b09a16835b8300205 - languageName: node - linkType: hard - -"ieee754@npm:^1.1.13": - version: 1.2.1 - resolution: "ieee754@npm:1.2.1" - checksum: 5144c0c9815e54ada181d80a0b810221a253562422e7c6c3a60b1901154184f49326ec239d618c416c1c5945a2e197107aee8d986a3dd836b53dffefd99b5e7e - languageName: node - linkType: hard - -"indent-string@npm:^4.0.0": - version: 4.0.0 - resolution: "indent-string@npm:4.0.0" - checksum: 824cfb9929d031dabf059bebfe08cf3137365e112019086ed3dcff6a0a7b698cb80cf67ccccde0e25b9e2d7527aa6cc1fed1ac490c752162496caba3e6699612 - languageName: node - linkType: hard - -"inflight@npm:^1.0.4": - version: 1.0.6 - resolution: "inflight@npm:1.0.6" - dependencies: - once: ^1.3.0 - wrappy: 1 - checksum: f4f76aa072ce19fae87ce1ef7d221e709afb59d445e05d47fba710e85470923a75de35bfae47da6de1b18afc3ce83d70facf44cfb0aff89f0a3f45c0a0244dfd - languageName: node - linkType: hard - -"inherits@npm:2": - version: 2.0.4 - resolution: "inherits@npm:2.0.4" - checksum: 4a48a733847879d6cf6691860a6b1e3f0f4754176e4d71494c41f3475553768b10f84b5ce1d40fbd0e34e6bfbb864ee35858ad4dd2cf31e02fc4a154b724d7f1 - languageName: node - linkType: hard - -"ini@npm:2.0.0": - version: 2.0.0 - resolution: "ini@npm:2.0.0" - checksum: e7aadc5fb2e4aefc666d74ee2160c073995a4061556b1b5b4241ecb19ad609243b9cceafe91bae49c219519394bbd31512516cb22a3b1ca6e66d869e0447e84e - languageName: node - linkType: hard - -"is-ci@npm:^3.0.0": - version: 3.0.1 - resolution: "is-ci@npm:3.0.1" - dependencies: - ci-info: ^3.2.0 - bin: - is-ci: bin.js - checksum: 192c66dc7826d58f803ecae624860dccf1899fc1f3ac5505284c0a5cf5f889046ffeb958fa651e5725d5705c5bcb14f055b79150ea5fcad7456a9569de60260e - languageName: node - linkType: hard - -"is-fullwidth-code-point@npm:^3.0.0": - version: 3.0.0 - resolution: "is-fullwidth-code-point@npm:3.0.0" - checksum: 44a30c29457c7fb8f00297bce733f0a64cd22eca270f83e58c105e0d015e45c019491a4ab2faef91ab51d4738c670daff901c799f6a700e27f7314029e99e348 - languageName: node - linkType: hard - -"is-installed-globally@npm:~0.4.0": - version: 0.4.0 - resolution: "is-installed-globally@npm:0.4.0" - dependencies: - global-dirs: ^3.0.0 - is-path-inside: ^3.0.2 - checksum: 3359840d5982d22e9b350034237b2cda2a12bac1b48a721912e1ab8e0631dd07d45a2797a120b7b87552759a65ba03e819f1bd63f2d7ab8657ec0b44ee0bf399 - languageName: node - linkType: hard - -"is-path-inside@npm:^3.0.2": - version: 3.0.3 - resolution: "is-path-inside@npm:3.0.3" - checksum: abd50f06186a052b349c15e55b182326f1936c89a78bf6c8f2b707412517c097ce04bc49a0ca221787bc44e1049f51f09a2ffb63d22899051988d3a618ba13e9 - languageName: node - linkType: hard - -"is-stream@npm:^2.0.0": - version: 2.0.1 - resolution: "is-stream@npm:2.0.1" - checksum: b8e05ccdf96ac330ea83c12450304d4a591f9958c11fd17bed240af8d5ffe08aedafa4c0f4cfccd4d28dc9d4d129daca1023633d5c11601a6cbc77521f6fae66 - languageName: node - linkType: hard - -"is-typedarray@npm:~1.0.0": - version: 1.0.0 - resolution: "is-typedarray@npm:1.0.0" - checksum: 3508c6cd0a9ee2e0df2fa2e9baabcdc89e911c7bd5cf64604586697212feec525aa21050e48affb5ffc3df20f0f5d2e2cf79b08caa64e1ccc9578e251763aef7 - languageName: node - linkType: hard - -"is-unicode-supported@npm:^0.1.0": - version: 0.1.0 - resolution: "is-unicode-supported@npm:0.1.0" - checksum: a2aab86ee7712f5c2f999180daaba5f361bdad1efadc9610ff5b8ab5495b86e4f627839d085c6530363c6d6d4ecbde340fb8e54bdb83da4ba8e0865ed5513c52 - languageName: node - linkType: hard - -"isexe@npm:^2.0.0": - version: 2.0.0 - resolution: "isexe@npm:2.0.0" - checksum: 26bf6c5480dda5161c820c5b5c751ae1e766c587b1f951ea3fcfc973bafb7831ae5b54a31a69bd670220e42e99ec154475025a468eae58ea262f813fdc8d1c62 - languageName: node - linkType: hard - -"isstream@npm:~0.1.2": - version: 0.1.2 - resolution: "isstream@npm:0.1.2" - checksum: 1eb2fe63a729f7bdd8a559ab552c69055f4f48eb5c2f03724430587c6f450783c8f1cd936c1c952d0a927925180fcc892ebd5b174236cf1065d4bd5bdb37e963 - languageName: node - linkType: hard - -"jsbn@npm:~0.1.0": - version: 0.1.1 - resolution: "jsbn@npm:0.1.1" - checksum: e5ff29c1b8d965017ef3f9c219dacd6e40ad355c664e277d31246c90545a02e6047018c16c60a00f36d561b3647215c41894f5d869ada6908a2e0ce4200c88f2 - languageName: node - linkType: hard - -"json-schema@npm:0.4.0": - version: 0.4.0 - resolution: "json-schema@npm:0.4.0" - checksum: 66389434c3469e698da0df2e7ac5a3281bcff75e797a5c127db7c5b56270e01ae13d9afa3c03344f76e32e81678337a8c912bdbb75101c62e487dc3778461d72 - languageName: node - linkType: hard - -"json-stringify-safe@npm:~5.0.1": - version: 5.0.1 - resolution: "json-stringify-safe@npm:5.0.1" - checksum: 48ec0adad5280b8a96bb93f4563aa1667fd7a36334f79149abd42446d0989f2ddc58274b479f4819f1f00617957e6344c886c55d05a4e15ebb4ab931e4a6a8ee - languageName: node - linkType: hard - -"jsonfile@npm:^6.0.1": - version: 6.1.0 - resolution: "jsonfile@npm:6.1.0" - dependencies: - graceful-fs: ^4.1.6 - universalify: ^2.0.0 - dependenciesMeta: - graceful-fs: - optional: true - checksum: 7af3b8e1ac8fe7f1eccc6263c6ca14e1966fcbc74b618d3c78a0a2075579487547b94f72b7a1114e844a1e15bb00d440e5d1720bfc4612d790a6f285d5ea8354 - languageName: node - linkType: hard - -"jsprim@npm:^2.0.2": - version: 2.0.2 - resolution: "jsprim@npm:2.0.2" - dependencies: - assert-plus: 1.0.0 - extsprintf: 1.3.0 - json-schema: 0.4.0 - verror: 1.10.0 - checksum: d175f6b1991e160cb0aa39bc857da780e035611986b5492f32395411879fdaf4e513d98677f08f7352dac93a16b66b8361c674b86a3fa406e2e7af6b26321838 - languageName: node - linkType: hard - -"lazy-ass@npm:^1.6.0": - version: 1.6.0 - resolution: "lazy-ass@npm:1.6.0" - checksum: 5a3ebb17915b03452320804466345382a6c25ac782ec4874fecdb2385793896cd459be2f187dc7def8899180c32ee0ab9a1aa7fe52193ac3ff3fe29bb0591729 - languageName: node - linkType: hard - -"listr2@npm:^3.8.3": - version: 3.14.0 - resolution: "listr2@npm:3.14.0" - dependencies: - cli-truncate: ^2.1.0 - colorette: ^2.0.16 - log-update: ^4.0.0 - p-map: ^4.0.0 - rfdc: ^1.3.0 - rxjs: ^7.5.1 - through: ^2.3.8 - wrap-ansi: ^7.0.0 - peerDependencies: - enquirer: ">= 2.3.0 < 3" - peerDependenciesMeta: - enquirer: - optional: true - checksum: fdb8b2d6bdf5df9371ebd5082bee46c6d0ca3d1e5f2b11fbb5a127839855d5f3da9d4968fce94f0a5ec67cac2459766abbb1faeef621065ebb1829b11ef9476d - languageName: node - linkType: hard - -"lodash.once@npm:^4.1.1": - version: 4.1.1 - resolution: "lodash.once@npm:4.1.1" - checksum: d768fa9f9b4e1dc6453be99b753906f58990e0c45e7b2ca5a3b40a33111e5d17f6edf2f768786e2716af90a8e78f8f91431ab8435f761fef00f9b0c256f6d245 - languageName: node - linkType: hard - -"lodash@npm:^4.17.21": - version: 4.17.21 - resolution: "lodash@npm:4.17.21" - checksum: eb835a2e51d381e561e508ce932ea50a8e5a68f4ebdd771ea240d3048244a8d13658acbd502cd4829768c56f2e16bdd4340b9ea141297d472517b83868e677f7 - languageName: node - linkType: hard - -"log-symbols@npm:^4.0.0": - version: 4.1.0 - resolution: "log-symbols@npm:4.1.0" - dependencies: - chalk: ^4.1.0 - is-unicode-supported: ^0.1.0 - checksum: fce1497b3135a0198803f9f07464165e9eb83ed02ceb2273930a6f8a508951178d8cf4f0378e9d28300a2ed2bc49050995d2bd5f53ab716bb15ac84d58c6ef74 - languageName: node - linkType: hard - -"log-update@npm:^4.0.0": - version: 4.0.0 - resolution: "log-update@npm:4.0.0" - dependencies: - ansi-escapes: ^4.3.0 - cli-cursor: ^3.1.0 - slice-ansi: ^4.0.0 - wrap-ansi: ^6.2.0 - checksum: ae2f85bbabc1906034154fb7d4c4477c79b3e703d22d78adee8b3862fa913942772e7fa11713e3d96fb46de4e3cabefbf5d0a544344f03b58d3c4bff52aa9eb2 - languageName: node - linkType: hard - -"lru-cache@npm:^6.0.0": - version: 6.0.0 - resolution: "lru-cache@npm:6.0.0" - dependencies: - yallist: ^4.0.0 - checksum: f97f499f898f23e4585742138a22f22526254fdba6d75d41a1c2526b3b6cc5747ef59c5612ba7375f42aca4f8461950e925ba08c991ead0651b4918b7c978297 - languageName: node - linkType: hard - -"merge-stream@npm:^2.0.0": - version: 2.0.0 - resolution: "merge-stream@npm:2.0.0" - checksum: 6fa4dcc8d86629705cea944a4b88ef4cb0e07656ebf223fa287443256414283dd25d91c1cd84c77987f2aec5927af1a9db6085757cb43d90eb170ebf4b47f4f4 - languageName: node - linkType: hard - -"mime-db@npm:1.52.0": - version: 1.52.0 - resolution: "mime-db@npm:1.52.0" - checksum: 0d99a03585f8b39d68182803b12ac601d9c01abfa28ec56204fa330bc9f3d1c5e14beb049bafadb3dbdf646dfb94b87e24d4ec7b31b7279ef906a8ea9b6a513f - languageName: node - linkType: hard - -"mime-types@npm:^2.1.12, mime-types@npm:~2.1.19": - version: 2.1.35 - resolution: "mime-types@npm:2.1.35" - dependencies: - mime-db: 1.52.0 - checksum: 89a5b7f1def9f3af5dad6496c5ed50191ae4331cc5389d7c521c8ad28d5fdad2d06fd81baf38fed813dc4e46bb55c8145bb0ff406330818c9cf712fb2e9b3836 - languageName: node - linkType: hard - -"mimic-fn@npm:^2.1.0": - version: 2.1.0 - resolution: "mimic-fn@npm:2.1.0" - checksum: d2421a3444848ce7f84bd49115ddacff29c15745db73f54041edc906c14b131a38d05298dae3081667627a59b2eb1ca4b436ff2e1b80f69679522410418b478a - languageName: node - linkType: hard - -"minimatch@npm:^3.1.1": - version: 3.1.2 - resolution: "minimatch@npm:3.1.2" - dependencies: - brace-expansion: ^1.1.7 - checksum: c154e566406683e7bcb746e000b84d74465b3a832c45d59912b9b55cd50dee66e5c4b1e5566dba26154040e51672f9aa450a9aef0c97cfc7336b78b7afb9540a - languageName: node - linkType: hard - -"minimist@npm:^1.2.6": - version: 1.2.6 - resolution: "minimist@npm:1.2.6" - checksum: d15428cd1e11eb14e1233bcfb88ae07ed7a147de251441d61158619dfb32c4d7e9061d09cab4825fdee18ecd6fce323228c8c47b5ba7cd20af378ca4048fb3fb - languageName: node - linkType: hard - -"ms@npm:2.1.2": - version: 2.1.2 - resolution: "ms@npm:2.1.2" - checksum: 673cdb2c3133eb050c745908d8ce632ed2c02d85640e2edb3ace856a2266a813b30c613569bf3354fdf4ea7d1a1494add3bfa95e2713baa27d0c2c71fc44f58f - languageName: node - linkType: hard - -"ms@npm:^2.1.1": - version: 2.1.3 - resolution: "ms@npm:2.1.3" - checksum: aa92de608021b242401676e35cfa5aa42dd70cbdc082b916da7fb925c542173e36bce97ea3e804923fe92c0ad991434e4a38327e15a1b5b5f945d66df615ae6d - languageName: node - linkType: hard - -"npm-run-path@npm:^4.0.0": - version: 4.0.1 - resolution: "npm-run-path@npm:4.0.1" - dependencies: - path-key: ^3.0.0 - checksum: 5374c0cea4b0bbfdfae62da7bbdf1e1558d338335f4cacf2515c282ff358ff27b2ecb91ffa5330a8b14390ac66a1e146e10700440c1ab868208430f56b5f4d23 - languageName: node - linkType: hard - -"once@npm:^1.3.0, once@npm:^1.3.1, once@npm:^1.4.0": - version: 1.4.0 - resolution: "once@npm:1.4.0" - dependencies: - wrappy: 1 - checksum: cd0a88501333edd640d95f0d2700fbde6bff20b3d4d9bdc521bdd31af0656b5706570d6c6afe532045a20bb8dc0849f8332d6f2a416e0ba6d3d3b98806c7db68 - languageName: node - linkType: hard - -"onetime@npm:^5.1.0": - version: 5.1.2 - resolution: "onetime@npm:5.1.2" - dependencies: - mimic-fn: ^2.1.0 - checksum: 2478859ef817fc5d4e9c2f9e5728512ddd1dbc9fb7829ad263765bb6d3b91ce699d6e2332eef6b7dff183c2f490bd3349f1666427eaba4469fba0ac38dfd0d34 - languageName: node - linkType: hard - -"ospath@npm:^1.2.2": - version: 1.2.2 - resolution: "ospath@npm:1.2.2" - checksum: 505f48a4f4f1c557d6c656ec985707726e3714721680139be037613e903aa8c8fa4ddd8d1342006f9b2dc0065e6e20f8b7bea2ee05354f31257044790367b347 - languageName: node - linkType: hard - -"p-map@npm:^4.0.0": - version: 4.0.0 - resolution: "p-map@npm:4.0.0" - dependencies: - aggregate-error: ^3.0.0 - checksum: cb0ab21ec0f32ddffd31dfc250e3afa61e103ef43d957cc45497afe37513634589316de4eb88abdfd969fe6410c22c0b93ab24328833b8eb1ccc087fc0442a1c - languageName: node - linkType: hard - -"path-is-absolute@npm:^1.0.0": - version: 1.0.1 - resolution: "path-is-absolute@npm:1.0.1" - checksum: 060840f92cf8effa293bcc1bea81281bd7d363731d214cbe5c227df207c34cd727430f70c6037b5159c8a870b9157cba65e775446b0ab06fd5ecc7e54615a3b8 - languageName: node - linkType: hard - -"path-key@npm:^3.0.0, path-key@npm:^3.1.0": - version: 3.1.1 - resolution: "path-key@npm:3.1.1" - checksum: 55cd7a9dd4b343412a8386a743f9c746ef196e57c823d90ca3ab917f90ab9f13dd0ded27252ba49dbdfcab2b091d998bc446f6220cd3cea65db407502a740020 - languageName: node - linkType: hard - -"pend@npm:~1.2.0": - version: 1.2.0 - resolution: "pend@npm:1.2.0" - checksum: 6c72f5243303d9c60bd98e6446ba7d30ae29e3d56fdb6fae8767e8ba6386f33ee284c97efe3230a0d0217e2b1723b8ab490b1bbf34fcbb2180dbc8a9de47850d - languageName: node - linkType: hard - -"performance-now@npm:^2.1.0": - version: 2.1.0 - resolution: "performance-now@npm:2.1.0" - checksum: 534e641aa8f7cba160f0afec0599b6cecefbb516a2e837b512be0adbe6c1da5550e89c78059c7fabc5c9ffdf6627edabe23eb7c518c4500067a898fa65c2b550 - languageName: node - linkType: hard - -"pify@npm:^2.2.0": - version: 2.3.0 - resolution: "pify@npm:2.3.0" - checksum: 9503aaeaf4577acc58642ad1d25c45c6d90288596238fb68f82811c08104c800e5a7870398e9f015d82b44ecbcbef3dc3d4251a1cbb582f6e5959fe09884b2ba - languageName: node - linkType: hard - -"pretty-bytes@npm:^5.6.0": - version: 5.6.0 - resolution: "pretty-bytes@npm:5.6.0" - checksum: 9c082500d1e93434b5b291bd651662936b8bd6204ec9fa17d563116a192d6d86b98f6d328526b4e8d783c07d5499e2614a807520249692da9ec81564b2f439cd - languageName: node - linkType: hard - -"proxy-from-env@npm:1.0.0": - version: 1.0.0 - resolution: "proxy-from-env@npm:1.0.0" - checksum: 292e28d1de0c315958d71d8315eb546dd3cd8c8cbc2dab7c54eeb9f5c17f421771964ad0b5e1f77011bab2305bdae42e1757ce33bdb1ccc3e87732322a8efcf1 - languageName: node - linkType: hard - -"psl@npm:^1.1.28": - version: 1.9.0 - resolution: "psl@npm:1.9.0" - checksum: 20c4277f640c93d393130673f392618e9a8044c6c7bf61c53917a0fddb4952790f5f362c6c730a9c32b124813e173733f9895add8d26f566ed0ea0654b2e711d - languageName: node - linkType: hard - -"pump@npm:^3.0.0": - version: 3.0.0 - resolution: "pump@npm:3.0.0" - dependencies: - end-of-stream: ^1.1.0 - once: ^1.3.1 - checksum: e42e9229fba14732593a718b04cb5e1cfef8254544870997e0ecd9732b189a48e1256e4e5478148ecb47c8511dca2b09eae56b4d0aad8009e6fac8072923cfc9 - languageName: node - linkType: hard - -"punycode@npm:^2.1.1": - version: 2.1.1 - resolution: "punycode@npm:2.1.1" - checksum: 823bf443c6dd14f669984dea25757b37993f67e8d94698996064035edd43bed8a5a17a9f12e439c2b35df1078c6bec05a6c86e336209eb1061e8025c481168e8 - languageName: node - linkType: hard - -"qs@npm:~6.5.2": - version: 6.5.3 - resolution: "qs@npm:6.5.3" - checksum: 6f20bf08cabd90c458e50855559539a28d00b2f2e7dddcb66082b16a43188418cb3cb77cbd09268bcef6022935650f0534357b8af9eeb29bf0f27ccb17655692 - languageName: node - linkType: hard - -"request-progress@npm:^3.0.0": - version: 3.0.0 - resolution: "request-progress@npm:3.0.0" - dependencies: - throttleit: ^1.0.0 - checksum: 6ea1761dcc8a8b7b5894afd478c0286aa31bd69438d7050294bd4fd0d0b3e09b5cde417d38deef9c49809039c337d8744e4bb49d8632b0c3e4ffa5e8a687e0fd - languageName: node - linkType: hard - -"restore-cursor@npm:^3.1.0": - version: 3.1.0 - resolution: "restore-cursor@npm:3.1.0" - dependencies: - onetime: ^5.1.0 - signal-exit: ^3.0.2 - checksum: f877dd8741796b909f2a82454ec111afb84eb45890eb49ac947d87991379406b3b83ff9673a46012fca0d7844bb989f45cc5b788254cf1a39b6b5a9659de0630 - languageName: node - linkType: hard - -"rfdc@npm:^1.3.0": - version: 1.3.0 - resolution: "rfdc@npm:1.3.0" - checksum: fb2ba8512e43519983b4c61bd3fa77c0f410eff6bae68b08614437bc3f35f91362215f7b4a73cbda6f67330b5746ce07db5dd9850ad3edc91271ad6deea0df32 - languageName: node - linkType: hard - -"rimraf@npm:^3.0.0": - version: 3.0.2 - resolution: "rimraf@npm:3.0.2" - dependencies: - glob: ^7.1.3 - bin: - rimraf: bin.js - checksum: 87f4164e396f0171b0a3386cc1877a817f572148ee13a7e113b238e48e8a9f2f31d009a92ec38a591ff1567d9662c6b67fd8818a2dbbaed74bc26a87a2a4a9a0 - languageName: node - linkType: hard - -"rxjs@npm:^7.5.1": - version: 7.5.6 - resolution: "rxjs@npm:7.5.6" - dependencies: - tslib: ^2.1.0 - checksum: fc05f01364a74dac57490fb3e07ea63b422af04017fae1db641a009073f902ef69f285c5daac31359620dc8d9aee7d81e42b370ca2a8573d1feae0b04329383b - languageName: node - linkType: hard - -"safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.2": - version: 5.2.1 - resolution: "safe-buffer@npm:5.2.1" - checksum: b99c4b41fdd67a6aaf280fcd05e9ffb0813654894223afb78a31f14a19ad220bba8aba1cb14eddce1fcfb037155fe6de4e861784eb434f7d11ed58d1e70dd491 - languageName: node - linkType: hard - -"safer-buffer@npm:^2.0.2, safer-buffer@npm:^2.1.0, safer-buffer@npm:~2.1.0": - version: 2.1.2 - resolution: "safer-buffer@npm:2.1.2" - checksum: cab8f25ae6f1434abee8d80023d7e72b598cf1327164ddab31003c51215526801e40b66c5e65d658a0af1e9d6478cadcb4c745f4bd6751f97d8644786c0978b0 - languageName: node - linkType: hard - -"semver@npm:^7.3.2": - version: 7.5.3 - resolution: "semver@npm:7.5.3" - dependencies: - lru-cache: ^6.0.0 - bin: - semver: bin/semver.js - checksum: 9d58db16525e9f749ad0a696a1f27deabaa51f66e91d2fa2b0db3de3e9644e8677de3b7d7a03f4c15bc81521e0c3916d7369e0572dbde250d9bedf5194e2a8a7 - languageName: node - linkType: hard - -"shebang-command@npm:^2.0.0": - version: 2.0.0 - resolution: "shebang-command@npm:2.0.0" - dependencies: - shebang-regex: ^3.0.0 - checksum: 6b52fe87271c12968f6a054e60f6bde5f0f3d2db483a1e5c3e12d657c488a15474121a1d55cd958f6df026a54374ec38a4a963988c213b7570e1d51575cea7fa - languageName: node - linkType: hard - -"shebang-regex@npm:^3.0.0": - version: 3.0.0 - resolution: "shebang-regex@npm:3.0.0" - checksum: 1a2bcae50de99034fcd92ad4212d8e01eedf52c7ec7830eedcf886622804fe36884278f2be8be0ea5fde3fd1c23911643a4e0f726c8685b61871c8908af01222 - languageName: node - linkType: hard - -"signal-exit@npm:^3.0.2": - version: 3.0.7 - resolution: "signal-exit@npm:3.0.7" - checksum: a2f098f247adc367dffc27845853e9959b9e88b01cb301658cfe4194352d8d2bb32e18467c786a7fe15f1d44b233ea35633d076d5e737870b7139949d1ab6318 - languageName: node - linkType: hard - -"slice-ansi@npm:^3.0.0": - version: 3.0.0 - resolution: "slice-ansi@npm:3.0.0" - dependencies: - ansi-styles: ^4.0.0 - astral-regex: ^2.0.0 - is-fullwidth-code-point: ^3.0.0 - checksum: 5ec6d022d12e016347e9e3e98a7eb2a592213a43a65f1b61b74d2c78288da0aded781f665807a9f3876b9daa9ad94f64f77d7633a0458876c3a4fdc4eb223f24 - languageName: node - linkType: hard - -"slice-ansi@npm:^4.0.0": - version: 4.0.0 - resolution: "slice-ansi@npm:4.0.0" - dependencies: - ansi-styles: ^4.0.0 - astral-regex: ^2.0.0 - is-fullwidth-code-point: ^3.0.0 - checksum: 4a82d7f085b0e1b070e004941ada3c40d3818563ac44766cca4ceadd2080427d337554f9f99a13aaeb3b4a94d9964d9466c807b3d7b7541d1ec37ee32d308756 - languageName: node - linkType: hard - -"sshpk@npm:^1.14.1": - version: 1.17.0 - resolution: "sshpk@npm:1.17.0" - dependencies: - asn1: ~0.2.3 - assert-plus: ^1.0.0 - bcrypt-pbkdf: ^1.0.0 - dashdash: ^1.12.0 - ecc-jsbn: ~0.1.1 - getpass: ^0.1.1 - jsbn: ~0.1.0 - safer-buffer: ^2.0.2 - tweetnacl: ~0.14.0 - bin: - sshpk-conv: bin/sshpk-conv - sshpk-sign: bin/sshpk-sign - sshpk-verify: bin/sshpk-verify - checksum: ba109f65c8e6c35133b8e6ed5576abeff8aa8d614824b7275ec3ca308f081fef483607c28d97780c1e235818b0f93ed8c8b56d0a5968d5a23fd6af57718c7597 - languageName: node - linkType: hard - -"string-width@npm:^4.1.0, string-width@npm:^4.2.0": - version: 4.2.3 - resolution: "string-width@npm:4.2.3" - dependencies: - emoji-regex: ^8.0.0 - is-fullwidth-code-point: ^3.0.0 - strip-ansi: ^6.0.1 - checksum: e52c10dc3fbfcd6c3a15f159f54a90024241d0f149cf8aed2982a2d801d2e64df0bf1dc351cf8e95c3319323f9f220c16e740b06faecd53e2462df1d2b5443fb - languageName: node - linkType: hard - -"strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": - version: 6.0.1 - resolution: "strip-ansi@npm:6.0.1" - dependencies: - ansi-regex: ^5.0.1 - checksum: f3cd25890aef3ba6e1a74e20896c21a46f482e93df4a06567cebf2b57edabb15133f1f94e57434e0a958d61186087b1008e89c94875d019910a213181a14fc8c - languageName: node - linkType: hard - -"strip-final-newline@npm:^2.0.0": - version: 2.0.0 - resolution: "strip-final-newline@npm:2.0.0" - checksum: 69412b5e25731e1938184b5d489c32e340605bb611d6140344abc3421b7f3c6f9984b21dff296dfcf056681b82caa3bb4cc996a965ce37bcfad663e92eae9c64 - languageName: node - linkType: hard - -"supports-color@npm:^7.1.0": - version: 7.2.0 - resolution: "supports-color@npm:7.2.0" - dependencies: - has-flag: ^4.0.0 - checksum: 3dda818de06ebbe5b9653e07842d9479f3555ebc77e9a0280caf5a14fb877ffee9ed57007c3b78f5a6324b8dbeec648d9e97a24e2ed9fdb81ddc69ea07100f4a - languageName: node - linkType: hard - -"supports-color@npm:^8.1.1": - version: 8.1.1 - resolution: "supports-color@npm:8.1.1" - dependencies: - has-flag: ^4.0.0 - checksum: c052193a7e43c6cdc741eb7f378df605636e01ad434badf7324f17fb60c69a880d8d8fcdcb562cf94c2350e57b937d7425ab5b8326c67c2adc48f7c87c1db406 - languageName: node - linkType: hard - -"throttleit@npm:^1.0.0": - version: 1.0.0 - resolution: "throttleit@npm:1.0.0" - checksum: 1b2db4d2454202d589e8236c07a69d2fab838876d370030ebea237c34c0a7d1d9cf11c29f994531ebb00efd31e9728291042b7754f2798a8352ec4463455b659 - languageName: node - linkType: hard - -"through@npm:^2.3.8": - version: 2.3.8 - resolution: "through@npm:2.3.8" - checksum: a38c3e059853c494af95d50c072b83f8b676a9ba2818dcc5b108ef252230735c54e0185437618596c790bbba8fcdaef5b290405981ffa09dce67b1f1bf190cbd - languageName: node - linkType: hard - -"tmp@npm:~0.2.1": - version: 0.2.1 - resolution: "tmp@npm:0.2.1" - dependencies: - rimraf: ^3.0.0 - checksum: 8b1214654182575124498c87ca986ac53dc76ff36e8f0e0b67139a8d221eaecfdec108c0e6ec54d76f49f1f72ab9325500b246f562b926f85bcdfca8bf35df9e - languageName: node - linkType: hard - -"tough-cookie@npm:~2.5.0": - version: 2.5.0 - resolution: "tough-cookie@npm:2.5.0" - dependencies: - psl: ^1.1.28 - punycode: ^2.1.1 - checksum: 16a8cd090224dd176eee23837cbe7573ca0fa297d7e468ab5e1c02d49a4e9a97bb05fef11320605eac516f91d54c57838a25864e8680e27b069a5231d8264977 - languageName: node - linkType: hard - -"tslib@npm:^2.1.0": - version: 2.4.0 - resolution: "tslib@npm:2.4.0" - checksum: 8c4aa6a3c5a754bf76aefc38026134180c053b7bd2f81338cb5e5ebf96fefa0f417bff221592bf801077f5bf990562f6264fecbc42cd3309b33872cb6fc3b113 - languageName: node - linkType: hard - -"tunnel-agent@npm:^0.6.0": - version: 0.6.0 - resolution: "tunnel-agent@npm:0.6.0" - dependencies: - safe-buffer: ^5.0.1 - checksum: 05f6510358f8afc62a057b8b692f05d70c1782b70db86d6a1e0d5e28a32389e52fa6e7707b6c5ecccacc031462e4bc35af85ecfe4bbc341767917b7cf6965711 - languageName: node - linkType: hard - -"tweetnacl@npm:^0.14.3, tweetnacl@npm:~0.14.0": - version: 0.14.5 - resolution: "tweetnacl@npm:0.14.5" - checksum: 6061daba1724f59473d99a7bb82e13f211cdf6e31315510ae9656fefd4779851cb927adad90f3b488c8ed77c106adc0421ea8055f6f976ff21b27c5c4e918487 - languageName: node - linkType: hard - -"type-fest@npm:^0.21.3": - version: 0.21.3 - resolution: "type-fest@npm:0.21.3" - checksum: e6b32a3b3877f04339bae01c193b273c62ba7bfc9e325b8703c4ee1b32dc8fe4ef5dfa54bf78265e069f7667d058e360ae0f37be5af9f153b22382cd55a9afe0 - languageName: node - linkType: hard - -"typescript@npm:^4.1.3": - version: 4.9.5 - resolution: "typescript@npm:4.9.5" - bin: - tsc: bin/tsc - tsserver: bin/tsserver - checksum: ee000bc26848147ad423b581bd250075662a354d84f0e06eb76d3b892328d8d4440b7487b5a83e851b12b255f55d71835b008a66cbf8f255a11e4400159237db - languageName: node - linkType: hard - -"typescript@patch:typescript@^4.1.3#~builtin": - version: 4.9.5 - resolution: "typescript@patch:typescript@npm%3A4.9.5#~builtin::version=4.9.5&hash=a1c5e5" - bin: - tsc: bin/tsc - tsserver: bin/tsserver - checksum: 2eee5c37cad4390385db5db5a8e81470e42e8f1401b0358d7390095d6f681b410f2c4a0c496c6ff9ebd775423c7785cdace7bcdad76c7bee283df3d9718c0f20 - languageName: node - linkType: hard - -"universalify@npm:^2.0.0": - version: 2.0.0 - resolution: "universalify@npm:2.0.0" - checksum: 2406a4edf4a8830aa6813278bab1f953a8e40f2f63a37873ffa9a3bc8f9745d06cc8e88f3572cb899b7e509013f7f6fcc3e37e8a6d914167a5381d8440518c44 - languageName: node - linkType: hard - -"untildify@npm:^4.0.0": - version: 4.0.0 - resolution: "untildify@npm:4.0.0" - checksum: 39ced9c418a74f73f0a56e1ba4634b4d959422dff61f4c72a8e39f60b99380c1b45ed776fbaa0a4101b157e4310d873ad7d114e8534ca02609b4916bb4187fb9 - languageName: node - linkType: hard - -"uuid@npm:^8.3.2": - version: 8.3.2 - resolution: "uuid@npm:8.3.2" - bin: - uuid: dist/bin/uuid - checksum: 5575a8a75c13120e2f10e6ddc801b2c7ed7d8f3c8ac22c7ed0c7b2ba6383ec0abda88c905085d630e251719e0777045ae3236f04c812184b7c765f63a70e58df - languageName: node - linkType: hard - -"verror@npm:1.10.0": - version: 1.10.0 - resolution: "verror@npm:1.10.0" - dependencies: - assert-plus: ^1.0.0 - core-util-is: 1.0.2 - extsprintf: ^1.2.0 - checksum: c431df0bedf2088b227a4e051e0ff4ca54df2c114096b0c01e1cbaadb021c30a04d7dd5b41ab277bcd51246ca135bf931d4c4c796ecae7a4fef6d744ecef36ea - languageName: node - linkType: hard - -"which@npm:^2.0.1": - version: 2.0.2 - resolution: "which@npm:2.0.2" - dependencies: - isexe: ^2.0.0 - bin: - node-which: ./bin/node-which - checksum: 1a5c563d3c1b52d5f893c8b61afe11abc3bab4afac492e8da5bde69d550de701cf9806235f20a47b5c8fa8a1d6a9135841de2596535e998027a54589000e66d1 - languageName: node - linkType: hard - -"wrap-ansi@npm:^6.2.0": - version: 6.2.0 - resolution: "wrap-ansi@npm:6.2.0" - dependencies: - ansi-styles: ^4.0.0 - string-width: ^4.1.0 - strip-ansi: ^6.0.0 - checksum: 6cd96a410161ff617b63581a08376f0cb9162375adeb7956e10c8cd397821f7eb2a6de24eb22a0b28401300bf228c86e50617cd568209b5f6775b93c97d2fe3a - languageName: node - linkType: hard - -"wrap-ansi@npm:^7.0.0": - version: 7.0.0 - resolution: "wrap-ansi@npm:7.0.0" - dependencies: - ansi-styles: ^4.0.0 - string-width: ^4.1.0 - strip-ansi: ^6.0.0 - checksum: a790b846fd4505de962ba728a21aaeda189b8ee1c7568ca5e817d85930e06ef8d1689d49dbf0e881e8ef84436af3a88bc49115c2e2788d841ff1b8b5b51a608b - languageName: node - linkType: hard - -"wrappy@npm:1": - version: 1.0.2 - resolution: "wrappy@npm:1.0.2" - checksum: 159da4805f7e84a3d003d8841557196034155008f817172d4e986bd591f74aa82aa7db55929a54222309e01079a65a92a9e6414da5a6aa4b01ee44a511ac3ee5 - languageName: node - linkType: hard - -"yallist@npm:^4.0.0": - version: 4.0.0 - resolution: "yallist@npm:4.0.0" - checksum: 343617202af32df2a15a3be36a5a8c0c8545208f3d3dfbc6bb7c3e3b7e8c6f8e7485432e4f3b88da3031a6e20afa7c711eded32ddfb122896ac5d914e75848d5 - languageName: node - linkType: hard - -"yauzl@npm:^2.10.0": - version: 2.10.0 - resolution: "yauzl@npm:2.10.0" - dependencies: - buffer-crc32: ~0.2.3 - fd-slicer: ~1.1.0 - checksum: 7f21fe0bbad6e2cb130044a5d1d0d5a0e5bf3d8d4f8c4e6ee12163ce798fee3de7388d22a7a0907f563ac5f9d40f8699a223d3d5c1718da90b0156da6904022b - languageName: node - linkType: hard diff --git a/docs/assets/search/search-extensions-example.drawio.svg b/docs/assets/search/search-extensions-example.drawio.svg new file mode 100644 index 0000000000..d0b0b4a481 --- /dev/null +++ b/docs/assets/search/search-extensions-example.drawio.svg @@ -0,0 +1,4 @@ + + + +
Core Routes
EXTENSION
Core Routes...

Routes

Routes
Attachment
Point
Attachment...
Route Artifact
Route Artifact
PATH
+
ELEMENT
PATH...
Input
Input
COMPONENT
COMPONENT
Item Artifact
Item Artifact

Search Page
EXTENSION

Search Page...

Items

Items
Attachment
Point
Attachment...
Output
Output
Input
Input

Search Result Item
EXTENSION

Search Result Item...


Output
Output
id: plugin.search.page
id: plugin.search.page
at: plugin.search.page/items
at: plugin.search.page/items
id: core.router
id: core.router
id: plugin.search.result.item
id: plugin.search.result.i...
at: core.router/routes
at: core.router/routes
Target Extension
Identification
Target Extension...
Target Extension
Input Attachment Point
Target Extension...
Text is not SVG - cannot display
\ No newline at end of file diff --git a/docs/auth/index.md b/docs/auth/index.md index ecef22b612..a670e69baa 100644 --- a/docs/auth/index.md +++ b/docs/auth/index.md @@ -140,6 +140,9 @@ const app = createApp({ }); ``` +> NOTE: You can configure sign-in to use a redirect flow with no pop-up by adding +> `enableExperimentalRedirectFlow: true` to the root of your `app-config.yaml` + ## Sign-In with Proxy Providers Some auth providers are so-called "proxy" providers, meaning they're meant to be used diff --git a/docs/backend-system/architecture/01-index.md b/docs/backend-system/architecture/01-index.md index e53d1e4719..0e780039b6 100644 --- a/docs/backend-system/architecture/01-index.md +++ b/docs/backend-system/architecture/01-index.md @@ -6,7 +6,7 @@ sidebar_label: Overview description: The structure and architecture of the new Backend System and its component parts --- -> **DISCLAIMER: The new backend system is in alpha, and still under active development. While we have reviewed the interfaces carefully, they may still be iterated on before the stable release.** +> **NOTE: The new backend system is in alpha, and some plugins do not yet fully implement it.** ## Building Blocks diff --git a/docs/backend-system/architecture/02-backends.md b/docs/backend-system/architecture/02-backends.md index 5d8737bb56..4ba76a5af3 100644 --- a/docs/backend-system/architecture/02-backends.md +++ b/docs/backend-system/architecture/02-backends.md @@ -6,7 +6,7 @@ sidebar_label: Backend description: Backend instances --- -> **DISCLAIMER: The new backend system is in alpha, and still under active development. While we have reviewed the interfaces carefully, they may still be iterated on before the stable release.** +> **NOTE: The new backend system is in alpha, and some plugins do not yet fully implement it.** ## The Backend Instance diff --git a/docs/backend-system/architecture/03-services.md b/docs/backend-system/architecture/03-services.md index ff6474152a..df610f45ab 100644 --- a/docs/backend-system/architecture/03-services.md +++ b/docs/backend-system/architecture/03-services.md @@ -6,7 +6,7 @@ sidebar_label: Services description: Services for backend plugins --- -> **DISCLAIMER: The new backend system is in alpha, and still under active development. While we have reviewed the interfaces carefully, they may still be iterated on before the stable release.** +> **NOTE: The new backend system is in alpha, and some plugins do not yet fully implement it.** Backend services provide shared functionality available to all backend plugins and modules. They are made available through service references that embed a type that represents the service interface, similar to how [Utility APIs](../../api/utility-apis.md) work in the Backstage frontend system. To use a service in your plugin or module you request an implementation of that service using the service reference. diff --git a/docs/backend-system/architecture/04-plugins.md b/docs/backend-system/architecture/04-plugins.md index b42abe7ca4..e93a6a39b2 100644 --- a/docs/backend-system/architecture/04-plugins.md +++ b/docs/backend-system/architecture/04-plugins.md @@ -6,7 +6,7 @@ sidebar_label: Plugins description: Backend plugins --- -> **DISCLAIMER: The new backend system is in alpha, and still under active development. While we have reviewed the interfaces carefully, they may still be iterated on before the stable release.** +> **NOTE: The new backend system is in alpha, and some plugins do not yet fully implement it.** Plugins provide the actual base features of a Backstage backend. Each plugin operates completely independently of all other plugins and they only communicate with each other through network calls. This means that there is a strong degree of isolation between plugins, and that each plugin can be considered a separate microservice. While a default Backstage project has all plugins installed within a single backend, it is also possible to split this setup into multiple backends, with each backend housing one or more plugins. diff --git a/docs/backend-system/architecture/05-extension-points.md b/docs/backend-system/architecture/05-extension-points.md index de63b49a15..d8d993b5bf 100644 --- a/docs/backend-system/architecture/05-extension-points.md +++ b/docs/backend-system/architecture/05-extension-points.md @@ -6,7 +6,7 @@ sidebar_label: Extension Points description: Extension points of backend plugins --- -> **DISCLAIMER: The new backend system is in alpha, and still under active development. While we have reviewed the interfaces carefully, they may still be iterated on before the stable release.** +> **NOTE: The new backend system is in alpha, and some plugins do not yet fully implement it.** While plugins are able to use static configuration for lightweight forms of customization, you can quickly hit a limit where you need something more powerful to allow users to extend your plugin. For this purpose, the backend system provides a mechanism for plugins to provide extension points, which can be used to expose deeper customizations for your plugin. Extension points are used by modules, which are installed in the backend adjacent to plugins. Modules are covered more in-depth in the [next section](./06-modules.md). diff --git a/docs/backend-system/architecture/06-modules.md b/docs/backend-system/architecture/06-modules.md index ec0acef175..e916e4fdf6 100644 --- a/docs/backend-system/architecture/06-modules.md +++ b/docs/backend-system/architecture/06-modules.md @@ -6,7 +6,7 @@ sidebar_label: Modules description: Modules for backend plugins --- -> **DISCLAIMER: The new backend system is in alpha, and still under active development. While we have reviewed the interfaces carefully, they may still be iterated on before the stable release.** +> **NOTE: The new backend system is in alpha, and some plugins do not yet fully implement it.** Backend modules are used to extend [plugins](./04-plugins.md) or sometimes other modules with additional features or change existing behavior. They must always be installed in the same backend instance as the plugin that they extend, and may only extend a single plugin. Modules interact with their target plugin using the [extension points](./05-extension-points.md) registered by the plugin, while also being able to depend on the [services](./03-services.md) of that plugin. diff --git a/docs/backend-system/architecture/07-naming-patterns.md b/docs/backend-system/architecture/07-naming-patterns.md index b541cc09ba..3e57fa6863 100644 --- a/docs/backend-system/architecture/07-naming-patterns.md +++ b/docs/backend-system/architecture/07-naming-patterns.md @@ -6,7 +6,7 @@ sidebar_label: Naming Patterns description: Naming patterns in the backend system --- -> **DISCLAIMER: The new backend system is in alpha, and still under active development. While we have reviewed the interfaces carefully, they may still be iterated on before the stable release.** +> **NOTE: The new backend system is in alpha, and some plugins do not yet fully implement it.** These are the naming patterns to adhere to within the backend system. They help us keep exports consistent across packages and make it easier to understand the usage and intent of exports. diff --git a/docs/backend-system/building-backends/01-index.md b/docs/backend-system/building-backends/01-index.md index 7d222009b9..7d331b4ec3 100644 --- a/docs/backend-system/building-backends/01-index.md +++ b/docs/backend-system/building-backends/01-index.md @@ -6,7 +6,7 @@ sidebar_label: Overview description: Building backends using the new backend system --- -> **DISCLAIMER: The new backend system is in alpha, and still under active development. While we have reviewed the interfaces carefully, they may still be iterated on before the stable release.** +> **NOTE: The new backend system is in alpha, and some plugins do not yet fully implement it.** > NOTE: If you have an existing backend that is not yet using the new backend > system, see [migrating](./08-migrating.md). diff --git a/docs/backend-system/building-backends/08-migrating.md b/docs/backend-system/building-backends/08-migrating.md index e4a37bb17d..1a380421c1 100644 --- a/docs/backend-system/building-backends/08-migrating.md +++ b/docs/backend-system/building-backends/08-migrating.md @@ -6,7 +6,7 @@ sidebar_label: Migration Guide description: How to migrate existing backends to the new backend system --- -> **DISCLAIMER: The new backend system is in alpha, and still under active development. As such, it is not considered stable, and it is not recommended to migrate production backends to the new backend system until it has a stable release.** +> **NOTE: The new backend system is in alpha, and some plugins do not yet fully implement it.** ## Overview @@ -212,8 +212,7 @@ place it in the legacy plugin environment. ## Cleaning Up the Plugins Folder -For plugins that are private and your own, you can follow a [dedicated migration -guide](../building-plugins-and-modules/08-migrating.md) as you see fit, at a +For plugins that are private and your own, you can follow a [dedicated migration guide](../building-plugins-and-modules/08-migrating.md) as you see fit, at a later time. For third party backend plugins, in particular the larger core plugins that are diff --git a/docs/backend-system/building-plugins-and-modules/01-index.md b/docs/backend-system/building-plugins-and-modules/01-index.md index cb9157cd14..fed074b258 100644 --- a/docs/backend-system/building-plugins-and-modules/01-index.md +++ b/docs/backend-system/building-plugins-and-modules/01-index.md @@ -6,7 +6,7 @@ sidebar_label: Overview description: Building backend plugins and modules using the new backend system --- -> **DISCLAIMER: The new backend system is in alpha, and still under active development. While we have reviewed the interfaces carefully, they may still be iterated on before the stable release.** +> **NOTE: The new backend system is in alpha, and some plugins do not yet fully implement it.** > NOTE: If you have an existing backend and/or backend plugins that are not yet > using the new backend system, see [migrating](./08-migrating.md). diff --git a/docs/backend-system/building-plugins-and-modules/02-testing.md b/docs/backend-system/building-plugins-and-modules/02-testing.md index 7d2b6e019d..d14f7de09c 100644 --- a/docs/backend-system/building-plugins-and-modules/02-testing.md +++ b/docs/backend-system/building-plugins-and-modules/02-testing.md @@ -6,7 +6,7 @@ sidebar_label: Testing description: Learn how to test your backend plugins and modules --- -> **DISCLAIMER: The new backend system is in alpha, and still under active development. While we have reviewed the interfaces carefully, they may still be iterated on before the stable release.** +> **NOTE: The new backend system is in alpha, and some plugins do not yet fully implement it.** Utilities for testing backend plugins and modules are available in `@backstage/backend-test-utils`. This section describes those facilities. diff --git a/docs/backend-system/building-plugins-and-modules/08-migrating.md b/docs/backend-system/building-plugins-and-modules/08-migrating.md index 1b57ec5310..067ab02b4d 100644 --- a/docs/backend-system/building-plugins-and-modules/08-migrating.md +++ b/docs/backend-system/building-plugins-and-modules/08-migrating.md @@ -6,7 +6,7 @@ sidebar_label: Migration Guide description: How to migrate existing backend plugins to the new backend system --- -> **DISCLAIMER: The new backend system is in alpha, and still under active development. While we have reviewed the interfaces carefully, they may still be iterated on before the stable release.** +> **NOTE: The new backend system is in alpha, and some plugins do not yet fully implement it.** Migrating an existing backend plugin to the new backend system is fairly straightforward. The process is similar across the majority of plugins which just return a `Router` that is then wired up in the `index.ts` file of your backend. The primary thing that we need to do is to make sure that the dependencies that are required by the plugin are available, and then registering the router with the HTTP router service. diff --git a/docs/backend-system/core-services/01-index.md b/docs/backend-system/core-services/01-index.md index baed9a2cdc..0163d45108 100644 --- a/docs/backend-system/core-services/01-index.md +++ b/docs/backend-system/core-services/01-index.md @@ -6,7 +6,7 @@ sidebar_label: Overview description: Core backend service APIs --- -> **DISCLAIMER: The new backend system is in alpha, and still under active development. While we have reviewed the interfaces carefully, they may still be iterated on before the stable release.** +> **NOTE: The new backend system is in alpha, and some plugins do not yet fully implement it.** The default backend provides several [core services](https://github.com/backstage/backstage/blob/master/packages/backend-plugin-api/src/services/definitions/coreServices.ts) out of the box which includes access to configuration, logging, URL Readers, databases and more. diff --git a/docs/backend-system/index.md b/docs/backend-system/index.md index 87eb008129..5dde66378a 100644 --- a/docs/backend-system/index.md +++ b/docs/backend-system/index.md @@ -6,7 +6,7 @@ sidebar_label: Introduction description: The Backend System --- -> **DISCLAIMER: The new backend system is in alpha, and still under active development. While we have reviewed the interfaces carefully, they may still be iterated on before the stable release.** +> **NOTE: The new backend system is in alpha, and some plugins do not yet fully implement it.** ## Status diff --git a/docs/deployment/docker.md b/docs/deployment/docker.md index a117d39f9a..4b29ef8a0e 100644 --- a/docs/deployment/docker.md +++ b/docs/deployment/docker.md @@ -54,7 +54,7 @@ Once the host build is complete, we are ready to build our image. The following `Dockerfile` is included when creating a new app with `@backstage/create-app`: ```Dockerfile -FROM node:18-bullseye-slim +FROM node:18-bookworm-slim # Install isolate-vm dependencies, these are needed by the @backstage/plugin-scaffolder-backend. RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ @@ -160,7 +160,7 @@ the repo root: ```Dockerfile # Stage 1 - Create yarn install skeleton layer -FROM node:18-bullseye-slim AS packages +FROM node:18-bookworm-slim AS packages WORKDIR /app COPY package.json yarn.lock ./ @@ -173,7 +173,7 @@ COPY plugins plugins RUN find packages \! -name "package.json" -mindepth 2 -maxdepth 2 -exec rm -rf {} \+ # Stage 2 - Install dependencies and build packages -FROM node:18-bullseye-slim AS build +FROM node:18-bookworm-slim AS build # Install isolate-vm dependencies, these are needed by the @backstage/plugin-scaffolder-backend. RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ @@ -211,7 +211,7 @@ RUN mkdir packages/backend/dist/skeleton packages/backend/dist/bundle \ && tar xzf packages/backend/dist/bundle.tar.gz -C packages/backend/dist/bundle # Stage 3 - Build the actual backend image and install production dependencies -FROM node:18-bullseye-slim +FROM node:18-bookworm-slim # Install isolate-vm dependencies, these are needed by the @backstage/plugin-scaffolder-backend. RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ diff --git a/docs/features/search/declarative-integration.md b/docs/features/search/declarative-integration.md new file mode 100644 index 0000000000..f0083e4d4b --- /dev/null +++ b/docs/features/search/declarative-integration.md @@ -0,0 +1,222 @@ +# Declarative Integrated Search Plugin + +> **Disclaimer:** +> Declarative integration is in an experimental stage and is not recommended for production. + +This is a guide for experimenting with `Search` in a declarative integrated Backstage front-end application. + +## Main Concepts + +Using declarative integration, you can customize your Backstage instance without writing code, see this [RFC](https://github.com/backstage/backstage/issues/18372) for more information. + +In the new frontend system, everything that extends Backstage's core features is called an extension, so an extension can be anything from an API to a page component. + +Extensions produces output artifacts and these artifacts are inputs consumed by other extensions: + +![search extensions example](../../assets/search/search-extensions-example.drawio.svg) + +In the image above, a `SearchResultItem` extension outputs a component and this component is injected as input to the `SearchPage` "items" attachment point. The `SearchPage` in turn uses the search result items to compose a search page element and outputs a route path and the page element so they are used as inputs attached to the `CoreRoutes` extension. Finally, the `CoreRoutes` renders the page element when the location matches the search page path. + +The basic concepts briefly mentioned are crucial to understanding how the declarative version of the `Search` plugin works. + +## Search Plugin + +The search plugin is a collection of extensions that implement the search feature in Backstage. + +### Installation + +Only one step is required to start using the `Search` plugin within declarative integration, so all you have to do is to install the `@backstage/plugin-catalog` and `@backstage/plugin-search` packages, (e.g., [app-next](https://github.com/backstage/backstage/tree/master/packages/app-next)): + +```sh +yarn add @backstage/plugin-catalog @backstage/plugin-search +``` + +The `Search` plugin depends on the `Catalog API`, that's the reason we have to install the ` @backstage/plugin-catalog` package too. + +### Extensions + +The `Search` plugin provides the following [extensions preset](https://github.com/backstage/backstage/blob/3f4a44aef39bd8dbf5098e60b6fdf66fd754c6d9/plugins/search/src/alpha.tsx#L246): + +- **SearchApi**: Outputs a concrete implementation for the `Search API` that is attached as an input to the `Core` apis holder; +- **SearchPage**: Outputs a component that represents the advanced `Search` page interface, this extension expects `Search` result items components as inputs to use them for rendering results in a custom way; +- **SearchNavItem**: It is an extension that outputs a data that represents a `Search` item in the main application sidebar, in other words, it inputs a sidebar item to the `Core` nav extension. + +### Configurations + +The `Search` extensions are configurable via `app-config.yaml` file in the `app.extensions` field using the extension id as the configuration key: + +_Example disabling the search page extension_ + +```yaml +# app-config.yaml +app: + extensions: + - plugin.search.page: false # ✨ +``` + +_Example setting the search sidebar item label_ + +```yaml +# app-config.yaml +app: + extensions: + - plugin.search.nav.index: # ✨ + config: + label: 'Search Page' +``` + +> **Known limitations:** +> It is currently not possible to open modals in sidebar items and also configure a different icon via configuration file, but it is already on the maintainers' radar. + +### Customizations + +Plugin developers can use the `createSearchResultItemExtension` factory provided by the `@backstage/plugin-search-react` for building their own custom `Search` result item extensions. + +_Example creating a custom `TechDocsSearchResultItemExtension`_ + +```tsx +// plugins/techdocs/alpha.tsx +import { createSearchResultListItemExtension } from '@backstage/plugin-search-react/alpha'; + +/** @alpha */ +export const TechDocsSearchResultListItemExtension = + createSearchResultListItemExtension({ + id: 'techdocs', + configSchema: createSchemaFromZod(z => + z.object({ + noTrack: z.boolean().default(false), + lineClamp: z.number().default(5), + }), + ), + predicate: result => result.type === 'techdocs', + component: async ({ config }) => { + const { TechDocsSearchResultListItem } = await import( + './components/TechDocsSearchResultListItem' + ); + return props => ; + }, + }); +``` + +In the snippet above, a plugin developer is providing a custom component for rendering search results of type "techdocs". The custom result item extension will be enabled by default once the `@backstage/plugin-techdocs` package is installed, that means adopters don't have to enable the extension manually via configuration file. + +When a Backstage adopter doesn't want to use the custom `TechDocs` search result item after installing the `TechDocs` plugin, they could disable it via Backstage configuration file: + +```yaml +# app-config.yaml +app: + extensions: + - plugin.search.result.item.techdocs: false # ✨ +``` + +Because a configuration schema was provided to the extension factory, Backstage adopters will be able to customize `TechDocs` search results **line clamp** that defaults to 3 and also **disable automatic analytics events tracking**: + +```yaml +# app-config.yaml +app: + extensions: + - plugin.search.result.item.techdocs: + config: # ✨ + noTrack: true + lineClamp: 3 +``` + +[comment]: <> (TODO: Extract this explanation to a more central place in the future) +The `createSearchResultItemExtension` function returns a Backstage's extension representation as follows: + +```ts +{ + "$$type": "@backstage/Extension", // [1] + "id": "plugin.search.result.item.techdocs", // [2] + "at": "plugin.search.page/items", // [3] + "inputs": {} // [4️] + "output": { // [5️] + "item": { + "$$type": "@backstage/ExtensionDataRef", + "id": "plugin.search.result.item.data", + "config": {} + } + }, + "configSchema": { // [6️] + "schema": { + "type": "object", + "properties": { + "noTrack": { + "type": "boolean", + "default": false + }, + "lineClamp": { + "type": "number", + "default": 5 + } + }, + "additionalProperties": false, + "$schema": "http://json-schema.org/draft-07/schema#" + } + }, + "disabled": false, // [7️] +} +``` + +In this object, you can see exactly what will happen once the custom extension is installed: + +- **[1] $$type**: declares that the object represents an extension; +- **[2] id**: Is a unique identification for the extension, the `plugin.search.result.item.techdocs` is the key used to configure the extension in the `app-config.yaml` file; +- **[3] at**: It represents the extension attachment point, so the value `plugin.search.page/items` says that the `TechDocs`'s search result item output will be injected as input on the "items" attachment expected by the search page extension; +- **[4] inputs**: in this case is an empty object because this extension doesn't expect inputs; +- **[5] output**: Object representing the artifact produced by the `TechDocs` result item extension, on the example, it is a react component reference; +- **[6] configSchema**: represents the `TechDocs` search result item configuration definition, this is the same schema that adopters will use for customizing the extension via `app-config.yaml` file; +- **[7] disable**: Says that the result item extension will be enable by default when the `TechDocs` plugin is installed in the app. + +To complete the development cycle for creating a custom search result item extension, we should provide the extension via `TechDocs` plugin: + +```tsx +// plugins/techdocs/alpha.tsx +import { createPlugin } from "@backstage/frontend-plugin-api"; + +// plugins should be always exported as default +export default createPlugin({ + id: 'techdocs' + extensions: [TechDocsSearchResultItemExtension] +}) +``` + +Here is the `plugins/techdocs/alpha.tsx` final version, and you can also take a look at the [actual implementation](https://github.com/backstage/backstage/blob/master/plugins/techdocs/src/alpha.tsx) of a custom `TechDocs` search result item: + +```tsx +// plugins/techdocs/alpha.tsx +import { createPlugin } from '@backstage/frontend-plugin-api'; +import { createSearchResultListItemExtension } from '@backstage/plugin-search-react/alpha'; + +/** @alpha */ +export const TechDocsSearchResultListItemExtension = + createSearchResultListItemExtension({ + id: 'techdocs', + configSchema: createSchemaFromZod(z => + z.object({ + noTrack: z.boolean().default(false), + lineClamp: z.number().default(5), + }), + ), + predicate: result => result.type === 'techdocs', + component: async ({ config }) => { + const { TechDocsSearchResultListItem } = await import( + './components/TechDocsSearchResultListItem' + ); + return props => ; + }, + }); + +/** @alpha */ +export default createPlugin({ + // plugins should be always exported as default + id: 'techdocs', + extensions: [TechDocsSearchResultListItemExtension], +}); +``` + +### Future Enhancement Opportunities + +Backstage maintainers are currently working on the extension replacement feature, and with this release, adopters will also be able to replace extensions provided by plugins, so stay tuned for future updates to this documentation. + +The first version of the `SearchPage` extension makes room for the `Search` plugin maintainers to convert filters into extensions as well in the future, if you also would like to collaborate with them on this idea, don't hesitate to open an issue and submit a pull request, your contribution is more than welcome! diff --git a/docs/features/software-catalog/external-integrations.md b/docs/features/software-catalog/external-integrations.md index 0f2459d6e0..0286b1f580 100644 --- a/docs/features/software-catalog/external-integrations.md +++ b/docs/features/software-catalog/external-integrations.md @@ -66,10 +66,14 @@ have to supply a (unique) name, and accept a connection from the environment through which you can issue writes. The rest is up to the individual provider implementation. -It is up to you where you put the code for this new processor class. For quick +It is up to you where you put the code for this new provider class. For quick experimentation you could place it in your backend package, but we recommend -putting all extensions like this in a backend plugin package of their own in the -`plugins` folder of your Backstage repo. +putting all extensions like this in a backend module package of their own in the +`plugins` folder of your Backstage repo: + +```sh +yarn new --select backend-module --option id=catalog +``` The class will have this basic structure: @@ -495,8 +499,12 @@ subclass that can be added to this catalog builder. It is up to you where you put the code for this new processor class. For quick experimentation you could place it in your backend package, but we recommend -putting all extensions like this in a backend plugin package of their own in the -`plugins` folder of your Backstage repo. +putting all extensions like this in a backend module package of their own in the +`plugins` folder of your Backstage repo: + +```sh +yarn new --select backend-module --option id=catalog +``` The class will have this basic structure: diff --git a/docs/features/techdocs/configuring-ci-cd.md b/docs/features/techdocs/configuring-ci-cd.md index 692128bf7b..20a73798a4 100644 --- a/docs/features/techdocs/configuring-ci-cd.md +++ b/docs/features/techdocs/configuring-ci-cd.md @@ -29,7 +29,7 @@ cd repo # Install @techdocs/cli, mkdocs and mkdocs plugins npm install -g @techdocs/cli -pip install mkdocs-techdocs-core==1.* +pip install "mkdocs-techdocs-core==1.*" # Generate techdocs-cli generate --no-docker diff --git a/docs/features/techdocs/getting-started.md b/docs/features/techdocs/getting-started.md index 0ff5903a85..f798384697 100644 --- a/docs/features/techdocs/getting-started.md +++ b/docs/features/techdocs/getting-started.md @@ -263,22 +263,42 @@ Setting `generator.runIn` to `local` means you will have to make sure your environment is compatible with techdocs. You will have to install the `mkdocs` and `mkdocs-techdocs-core` package from -pip, as well as `graphviz` and `plantuml` from your OS package manager (e.g. +pip, optionally also `graphviz` and `plantuml` from your OS package manager (e.g. apt). You can do so by including the following lines right above `USER node` of your `Dockerfile`: ```Dockerfile -RUN apt-get update && apt-get install -y python3 python3-pip -RUN pip3 install mkdocs-techdocs-core==1.1.7 +RUN apt-get update && apt-get install -y python3 python3-pip python3-venv + +ENV VIRTUAL_ENV=/opt/venv +RUN python3 -m venv $VIRTUAL_ENV +ENV PATH="$VIRTUAL_ENV/bin:$PATH" + +RUN pip3 install mkdocs-techdocs-core ``` Please be aware that the version requirement could change, you need to check our [`Dockerfile`](https://github.com/backstage/techdocs-container/blob/main/Dockerfile) and make sure to match with it. -Note: We recommend Python version 3.7 or higher. +On a Debian-based Docker container, Python packages must be either installed using +the OS package manager or within a virtual environment (see the +[related PEP](https://peps.python.org/pep-0668/)). Alternative is to use e.g. +[pipx](https://pypa.github.io/pipx/) for installing Python packages in an isolated +environment. + +The above Dockerfile snippet installs the latest `mkdocs-techdoc-core` package. +Version numbers can be found in the corresponding +[changelog](https://github.com/backstage/mkdocs-techdocs-core#changelog). In +case you want to pin the version, use the example below: + +```Dockerfile +RUN pip3 install mkdocs-techdocs-core==1.2.3 +``` + +Note: We recommend Python version 3.11 or higher. > Caveat: Please install the `mkdocs-techdocs-core` package after all other > Python packages. The order is important to make sure we get correct version of diff --git a/docs/features/techdocs/how-to-guides.md b/docs/features/techdocs/how-to-guides.md index c64018ab97..8c98ec48d4 100644 --- a/docs/features/techdocs/how-to-guides.md +++ b/docs/features/techdocs/how-to-guides.md @@ -676,6 +676,35 @@ and publish the documentation for them. If the value of the `company.com/techdoc annotation is anything other than `'local'`, the user is responsible for publishing documentation to the appropriate location in the TechDocs external storage. +## How to use other mkdocs plugins? + +The default plugin [mkdocs-techdocs-core](https://github.com/backstage/mkdocs-techdocs-core) provides a set of plugins that can be viewed as the minimum required plugins to enable TechDocs. Your organization might have needs beyond the core set though, here is the recommended way to enable other plugins. + +### Install the plugin + +#### With CI generation + +If you generate the HTML files in CI using `@techdocs/cli`, you need to install the desired mkdocs plugin in the runtime where the cli is being executed. This might be e.g. a docker image or a Jenkins node. Use the `--no-docker` flag with the cli to pick up the plugin you just installed. + +#### With local generation + +Create a new Docker image that extends [spotify/techdocs](https://github.com/backstage/techdocs-container), roughly: + +```Dockerfile +FROM spotify/techdocs: + +pip install +... +``` + +Then publish the image and use it in your config under the `techdocs.generator.dockerImage` [key](https://github.com/backstage/techdocs-container). + +### Specify the plugin in the mkdocs config + +To use the plugin, it has to be listed in the `mkdocs.yaml` file. You can either add the plugin to your applicable files, or specify defaults. + +To make a mkdocs plugin available for all your TechDocs components you can either list it in the `techdocs.generator.mkdocs.defaultPlugins` [config](https://github.com/backstage/backstage/blob/master/plugins/techdocs-backend/config.d.ts#L64C14-L64C14), or use the `--defaultPlugin` [cli option](https://backstage.io/docs/features/techdocs/cli#generate-techdocs-site-from-a-documentation-project) depending on your setup. + ## Reference another components TechDocs In systems where you might have multiple entities for example a System with a Website and an API, when served from a Monorepo you might want to keep the TechDocs in one location in the repository. diff --git a/docs/integrations/github/org.md b/docs/integrations/github/org.md index 39b60c76c5..1404b20559 100644 --- a/docs/integrations/github/org.md +++ b/docs/integrations/github/org.md @@ -130,13 +130,14 @@ export default async function createPlugin( builder.addProcessor(new ScaffolderEntitiesProcessor()); /* highlight-add-start */ const githubOrgProvider = GithubOrgEntityProvider.fromConfig(env.config, { - id: 'production', - orgUrl: 'https://github.com/backstage', - logger: env.logger, - schedule: env.scheduler.createScheduledTaskRunner({ - frequency: { minutes: 60 }, - timeout: { minutes: 15 }, - }), + id: 'production', + orgUrl: 'https://github.com/backstage', + logger: env.logger, + schedule: env.scheduler.createScheduledTaskRunner({ + frequency: { minutes: 60 }, + timeout: { minutes: 15 }, + }), + }); env.eventBroker.subscribe(githubOrgProvider); builder.addEntityProvider(githubOrgProvider); /* highlight-add-end */ @@ -254,23 +255,32 @@ configured such an email in their own account. The API will only return these values when using GitHub App authentication and with the correct app permission allowing access to emails. -You can decorate the `defaultUserTransformer` to replace the org email in the +You can decorate the default `userTransformer` to replace the org email in the returned identity. -```typescript -async (user, ctx): Promise => { - const entity = await defaultUserTransformer(user, ctx); - - if (entity && user.organizationVerifiedDomainEmails?.length) { - entity.spec.profile!.email = user.organizationVerifiedDomainEmails[0]; - } - - return entity; -}, +```ts title="packages/backend/src/plugins/catalog.ts" +const githubOrgProvider = GithubOrgEntityProvider.fromConfig(env.config, { + id: 'production', + orgUrl: 'https://github.com/backstage', + logger: env.logger, + schedule: env.scheduler.createScheduledTaskRunner({ + frequency: { minutes: 60 }, + timeout: { minutes: 15 }, + }), + /* highlight-add-start */ + userTransformer: async (user, ctx) => { + const entity = await defaultUserTransformer(user, ctx); + if (entity && user.organizationVerifiedDomainEmails?.length) { + entity.spec.profile!.email = user.organizationVerifiedDomainEmails[0]; + } + return entity; + }, + /* highlight-add-end */ +}); ``` -Once you have imported the emails you can resolve users in your sign-in in -resolver using the catalog entity search via email +Once you have imported the emails you can resolve users in your [sign-in +resolver](../../auth/github/provider.md) using the catalog entity search via email ```typescript title="packages/backend/src/plugins/auth.ts" ctx.signInWithCatalogUser({ diff --git a/docs/local-dev/cli-build-system.md b/docs/local-dev/cli-build-system.md index 94244de6fa..06aec945b9 100644 --- a/docs/local-dev/cli-build-system.md +++ b/docs/local-dev/cli-build-system.md @@ -418,7 +418,7 @@ The following is an example of a `Dockerfile` that can be used to package the output of building a package with role `'backend'` into an image: ```Dockerfile -FROM node:18-bullseye-slim +FROM node:18-bookworm-slim WORKDIR /app COPY yarn.lock package.json packages/backend/dist/skeleton.tar.gz ./ diff --git a/docs/plugins/customization.md b/docs/plugins/customization.md deleted file mode 100644 index 44ca5147ea..0000000000 --- a/docs/plugins/customization.md +++ /dev/null @@ -1,68 +0,0 @@ ---- -id: customization -title: Customization (Experimental) -description: Documentation on adding a customization logic to the plugin ---- - -## Overview - -The Backstage core logic provides a possibility to make the component customizable in such a way that the application -developer can redefine the labels, icons, elements or even completely replace the component. It's up to each plugin -to decide what can be customized. - -## For a plugin developer - -When you are creating your plugin, you have a possibility to use a metadata field and define there all -customizable elements. For example - -```typescript jsx -const plugin = createPlugin({ - id: 'my-plugin', - __experimentalConfigure( - options?: CatalogInputPluginOptions, - ): CatalogPluginOptions { - const defaultOptions = { - createButtonTitle: 'Create', - }; - return { ...defaultOptions, ...options }; - }, -}); -``` - -And the rendering part of the exposed component can retrieve that metadata as: - -```typescript jsx -export type CatalogPluginOptions = { - createButtonTitle: string; -}; - -export type CatalogInputPluginOptions = { - createButtonTitle: string; -}; - -export const useCatalogPluginOptions = () => - usePluginOptions(); - -export function DefaultMyPluginWelcomePage() { - const { createButtonTitle } = useCatalogPluginOptions(); - - return ( -
- -
- ); -} -``` - -## For an application developer using the plugin - -The way to reconfigure the default values provided by the plugin you can do it via reconfigure method, defined on the -plugin. Example: - -```typescript jsx -import { myPlugin } from '@backstage/my-plugin'; - -myPlugin.__experimentalReconfigure({ - createButtonTitle: 'New', -}); -``` diff --git a/docs/plugins/internationalization.md b/docs/plugins/internationalization.md index 9f816ea52b..78b7de6342 100644 --- a/docs/plugins/internationalization.md +++ b/docs/plugins/internationalization.md @@ -30,7 +30,7 @@ And the using this messages in your components like: ```tsx import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; -const { t } = useTranslationRef(userSettingsTranslationRef); +const { t } = useTranslationRef(myPluginTranslationRef); return ( diff --git a/docs/plugins/new-backend-system.md b/docs/plugins/new-backend-system.md index 0023584d0d..be27e9427d 100644 --- a/docs/plugins/new-backend-system.md +++ b/docs/plugins/new-backend-system.md @@ -1,14 +1,12 @@ --- id: new-backend-system title: New Backend System -description: Details of the upcoming backend system +description: Details of the new backend system --- -> **DISCLAIMER: The new backend system is in alpha, and still under active development. While we have reviewed the interfaces carefully, they may still be iterated on before the stable release.** - ## Status -The new backend system is in alpha, and only a small number of plugins have been migrated so far. It is possible to try it out, but it is not recommended to use this new system in production yet. +The new backend system is in alpha, and some plugins do not yet fully implement it. But do feel free to try it out! We would love to hear back about your impressions. You can find an example backend setup in [the backend-next package](https://github.com/backstage/backstage/tree/master/packages/backend-next). diff --git a/docs/plugins/plugin-development.md b/docs/plugins/plugin-development.md index 100f9012be..8d8db8c387 100644 --- a/docs/plugins/plugin-development.md +++ b/docs/plugins/plugin-development.md @@ -79,5 +79,5 @@ This extension can then be imported and used in the app as follow, typically placed within the top-level ``: ```tsx -} /> +} /> ``` diff --git a/docs/plugins/proxying.md b/docs/plugins/proxying.md index 442721a355..40d155e13b 100644 --- a/docs/plugins/proxying.md +++ b/docs/plugins/proxying.md @@ -36,13 +36,14 @@ Example: ```yaml # in app-config.yaml proxy: - /simple-example: http://simple.example.com:8080 - '/larger-example/v1': - target: http://larger.example.com:8080/svc.v1 - headers: - Authorization: ${EXAMPLE_AUTH_HEADER} - # ...or interpolating a value into part of a string, - # Authorization: Bearer ${EXAMPLE_AUTH_TOKEN} + endpoints: + /simple-example: http://simple.example.com:8080 + '/larger-example/v1': + target: http://larger.example.com:8080/svc.v1 + headers: + Authorization: ${EXAMPLE_AUTH_HEADER} + # ...or interpolating a value into part of a string, + # Authorization: Bearer ${EXAMPLE_AUTH_TOKEN} ``` Each key under the proxy configuration entry is a route to match, below the diff --git a/docs/publishing.md b/docs/publishing.md index 3ffc29e6df..2424bc1352 100644 --- a/docs/publishing.md +++ b/docs/publishing.md @@ -15,9 +15,10 @@ PR is merged. This is typically done every Tuesday around noon CET. ## Next Line Release Process -- PR Checks: Ensure there are no outstanding PRs pending to be merged for this version. If there are any, reach out to maintainers and relevant owners of the affected code reminding them of the deadline for the release. -- [optional] Lock main branch - - Lock the main branch to prevent any new merges. +- PR Checks: Notify the teams & ensure there are no outstanding PRs pending to be merged for this version. This should be done in time to ensure a smooth release day. If there are any, reach out to maintainers and relevant owners of the affected code reminding them of the deadline for the release. +- Lock main branch + - Lock the main branch to prevent any new merges by other maintainers. Do not unlock the main branch until the release was published successfully + - Core maintainers can still merge last PRs using their admin override including the Version Packages PR - Note: Admin rights are required to lock the branch. If you lack the necessary permissions, contact a core maintainer to perform this action on your behalf. - Check [`Version Packages (next)` Pull Request](https://github.com/backstage/backstage/pulls?q=is%3Aopen+is%3Apr+in%3Atitle+%22Version+Packages+%28next%29%22) - Verify the version we are shipping is correct, by looking at the version packages PR title. It should be "Version Packages (next)" @@ -32,7 +33,28 @@ PR is merged. This is typically done every Tuesday around noon CET. Merging the `Version Packages (next)` Pull Request will trigger the deployment workflows. Follow along the [deployment workflow](https://github.com/backstage/backstage/actions/workflows/deploy_packages.yml). If you notice flakiness (e.g. if the build is flaky or if the release step runs into an error with releasing to npm) just restart the workflow. -Congratulations on the release! There should be now a post in the [`#announcements` channel](https://discord.com/channels/687207715902193673/705123584468582400) in Discord linking to the release tag - check if links & tag look as expected. Finally unlock the main branch again. Merging PRs in master directly after release should be done with caution as it potential complicates fixing issues introduced in the release. +Congratulations on the release! There should be now a post in the [`#announcements` channel](https://discord.com/channels/687207715902193673/705123584468582400) in Discord linking to the release tag - check if links & tag look as expected. Once the notification has gone out on Discord you can unlock the main branch & the release is complete. + +## Main Line Release Process + +Additional steps for the main line release + +- [Switch Release Mode](#switching-release-modes) to exit pre-release mode. This can be done at any time after the last Next Line Release. + - Check [`.changeset/pre.json`](https://github.com/backstage/backstage/blob/master/.changeset/pre.json) if the `mode` is set to `exit`. If you encounter `mode: "pre"` it indicates a next line release. +- Check [`Version Packages` Pull Request](https://github.com/backstage/backstage/pulls?q=is%3Aopen+is%3Apr+in%3Atitle+%22Version+Packages) + - Check for mentions of "major" & "breaking" and if they are expected in the current release + - Verify the version we are shipping is correct +- Create Release Notes + - There exists a [release notes template](./release-notes-template.md) for creating the release notes. It can already be created after the last main line release to keep track of major changes during the month + - The content is picked by relevancy showcasing the work of the community during the month of the release + - Mention newly added packages or features + - Mention any security fixes +- Create Release Notes PR + - Add the release note file as [`/docs/releases/vx.y.0.md`](./releases) + - Add an entry to [`/microsite/sidebar.json`](https://github.com/backstage/backstage/blob/master/microsite/sidebars.json) for the release note + - Update the navigation bar item in [`/microsite/docusaurus.config.js`](https://github.com/backstage/backstage/blob/master/microsite/docusaurus.config.js) to point to the new release note + +Once the release has been published edit the newly created release in the [GitHub repository](https://github.com/backstage/backstage/releases) and replace the text content with the release notes. ## Switching Release Modes diff --git a/docs/release-notes-template.md b/docs/release-notes-template.md new file mode 100644 index 0000000000..9f9a0b76ee --- /dev/null +++ b/docs/release-notes-template.md @@ -0,0 +1,40 @@ +--- +id: v1.1.0 +title: v1.1.0 +description: Backstage Release v1.1.0 +--- + +These are the release notes for the v1.1.0 release of [Backstage](https://backstage.io/). + +A huge thanks to the whole team of maintainers and contributors as well as the amazing Backstage Community for the hard work in getting this release developed and done. + +## Highlights + +### + +<short description>. Contributed by [@<user>](https://github.com/<user>) [#<pr>](https://github.com/backstage/backstage/pull/<pr>) + +## Security Fixes + +This release does not contain any security fixes. + +<or> + +@backstage/<package-name>, please upgrade to the latest version if you are using this module. + +## Upgrade path + +We recommend that you keep your Backstage project up to date with this latest release. For more guidance on how to upgrade, check out the documentation for [keeping Backstage updated](https://backstage.io/docs/getting-started/keeping-backstage-updated). + +## Links and References + +Below you can find a list of links and references to help you learn about and start using this new release. + +- [Backstage official website](https://backstage.io/), [documentation](https://backstage.io/docs/), and [getting started guide](https://backstage.io/docs/getting-started/) +- [GitHub repository](https://github.com/backstage/backstage) +- Backstage's [versioning and support policy](https://backstage.io/docs/overview/versioning-policy) +- [Community Discord](https://discord.gg/backstage-687207715902193673) for discussions and support +- [Changelog](https://github.com/backstage/backstage/tree/master/docs/releases/v1.1.0-changelog.md) +- Backstage [Demos](https://backstage.io/demos), [Blog](https://backstage.io/blog), [Roadmap](https://backstage.io/docs/overview/roadmap) and [Plugins](https://backstage.io/plugins) + +Sign up for our [newsletter](https://info.backstage.spotify.com/newsletter_subscribe) if you want to be informed about what is happening in the world of Backstage. diff --git a/docs/releases/v1.19.0-next.0-changelog.md b/docs/releases/v1.19.0-next.0-changelog.md new file mode 100644 index 0000000000..d1861165b9 --- /dev/null +++ b/docs/releases/v1.19.0-next.0-changelog.md @@ -0,0 +1,2868 @@ +# Release v1.19.0-next.0 + +## @backstage/cli@0.23.0-next.0 + +### Minor Changes + +- 7077dbf131: The new backend start command that used to be enabled by setting `EXPERIMENTAL_BACKEND_START` is now the default. To revert to the old behavior, set `LEGACY_BACKEND_START` instead. + + This new command is no longer based on Webpack, but instead uses Node.js loaders to transpile on the fly. Rather than hot reloading modules the entire backend is now restarted on change, but the SQLite database state is still maintained across restarts via a parent process. + +### Patch Changes + +- 68158034e8: Fix for the new backend `start` command to make it work on Windows. +- 21cd3b1b24: Added a template for creating `node-library` packages with `yarn new`. +- de42eebaaf: Bumped dev dependencies `@types/node` and `mock-fs`. +- 3ef18f8c06: Explicitly set `exports: 'named'` for CJS builds, ensuring that they have e.g. `exports["default"] = catalogPlugin;` +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/config-loader@1.5.1-next.0 + - @backstage/cli-common@0.1.13-next.0 + - @backstage/config@1.1.0 + - @backstage/release-manifests@0.0.10 + - @backstage/catalog-model@1.4.2 + - @backstage/cli-node@0.1.5-next.0 + - @backstage/errors@1.2.2 + - @backstage/eslint-plugin@0.1.3 + - @backstage/types@1.1.1 + +## @backstage/core-plugin-api@1.7.0-next.0 + +### Minor Changes + +- 322bbcae24: Removed the exprimental plugin configuration API. The `__experimentalReconfigure()` from the plugin options as well as the `__experimentalConfigure()` method on plugin instances have both been removed. + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.1.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.5 + +## @backstage/e2e-test-utils@0.1.0-next.0 + +### Minor Changes + +- f5b41b27a9: Initial release. + +## @backstage/frontend-app-api@0.2.0-next.0 + +### Minor Changes + +- 9d03dfe5e3: The `createApp` config option has been replaced by a new `configLoader` option. There is now also a `pluginLoader` option that can be used to dynamically load plugins into the app. + +### Patch Changes + +- 322bbcae24: Internal update for removal of experimental plugin configuration API. +- 66d51a4827: Prevents root extension override and duplicated plugin extensions. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/frontend-plugin-api@0.1.1-next.0 + - @backstage/config@1.1.0 + - @backstage/core-app-api@1.10.1-next.0 + - @backstage/plugin-graphiql@0.2.55-next.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog@1.14.0-next.0 + +### Minor Changes + +- 28f1ab2e1a: The catalog plugin no longer implements the experimental reconfiguration API. The create button title can now instead be configured using the new experimental internationalization API, via the `catalogTranslationRef` exported at `/alpha`. For example: + + ```ts + import { catalogTranslationRef } from '@backstage/plugin-catalog/alpha'; + + const app = createApp({ + __experimentalTranslations: { + resources: [ + createTranslationMessages({ + ref: catalogTranslationRef, + catalog_page_create_button_title: 'Create Software', + }), + ], + }, + }); + ``` + +- f3561a2935: include owner chip in catalog search result item + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/integration-react@1.1.20-next.0 + - @backstage/plugin-search-react@1.7.1-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-scaffolder-common@1.4.1 + - @backstage/plugin-search-common@1.2.6 + +## @backstage/plugin-catalog-backend@1.14.0-next.0 + +### Minor Changes + +- 78af9433c8: Instrumenting some missing metrics with `OpenTelemetry` + +### Patch Changes + +- 348e8c1cdb: Fixes a bug where eagerly deleted entities did not properly trigger re-stitching of entities that they had relations to. +- b97e9790f0: Internal refactors, laying the foundation for later introducing deferred stitching (see #18062). +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-openapi-utils@0.0.4 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-catalog-node@1.4.6-next.0 + - @backstage/plugin-events-node@0.2.14-next.0 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-permission-node@0.7.16-next.0 + - @backstage/plugin-scaffolder-common@1.4.1 + - @backstage/plugin-search-backend-module-catalog@0.1.9-next.0 + - @backstage/plugin-search-common@1.2.6 + +## @backstage/app-defaults@1.4.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/core-app-api@1.10.1-next.0 + - @backstage/plugin-permission-react@0.4.16-next.0 + - @backstage/theme@0.4.2 + +## @backstage/backend-app-api@0.5.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/config-loader@1.5.1-next.0 + - @backstage/cli-common@0.1.13-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/cli-node@0.1.5-next.0 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-node@0.7.16-next.0 + +## @backstage/backend-common@0.19.7-next.0 + +### Patch Changes + +- 1c3d6fa2b2: The `useHotCleanup` and `useHotMemoize` helpers are now deprecated, since hot module reloads for backend are being phased out. +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/config-loader@1.5.1-next.0 + - @backstage/cli-common@0.1.13-next.0 + - @backstage/config@1.1.0 + - @backstage/integration-aws-node@0.1.6 + - @backstage/backend-app-api@0.5.5-next.0 + - @backstage/backend-dev-utils@0.1.1 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + +## @backstage/backend-defaults@0.2.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/backend-app-api@0.5.5-next.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + +## @backstage/backend-plugin-api@0.6.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.8 + +## @backstage/backend-tasks@0.5.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + +## @backstage/backend-test-utils@0.2.6-next.0 + +### Patch Changes + +- 5ddc03813e: Remove third type parameter used for `MockInstance`, in order to be compatible with older versions of `@types/jest`. +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-app-api@0.5.5-next.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/types@1.1.1 + +## @backstage/cli-common@0.1.13-next.0 + +### Patch Changes + +- de42eebaaf: Bumped dev dependencies `@types/node` and `mock-fs`. + +## @backstage/cli-node@0.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/cli-common@0.1.13-next.0 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + +## @backstage/codemods@0.1.46-next.0 + +### Patch Changes + +- de42eebaaf: Bumped dev dependencies `@types/node` and `mock-fs`. +- Updated dependencies + - @backstage/cli-common@0.1.13-next.0 + +## @backstage/config-loader@1.5.1-next.0 + +### Patch Changes + +- 773ea341d2: The `FileConfigSource` will now retry file reading after a short delay if it reads an empty file. This is to avoid flakiness during watch mode where change events can trigger before the file content has been written. +- Updated dependencies + - @backstage/cli-common@0.1.13-next.0 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + +## @backstage/core-app-api@1.10.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.5 + +## @backstage/core-components@0.13.6-next.0 + +### Patch Changes + +- d19a827ef1: MissingAnnotationEmptyState component can now dynamically generate a YAML example based off the current entity being used. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/version-bridge@1.0.5 + +## @backstage/create-app@0.5.6-next.0 + +### Patch Changes + +- ba6a3b59c1: Removed duplicate `apple-touch-icon` link from `packages/app/public/index.html` that linked to nonexistent icon. + +- c8ec0dea4a: Create unique temp directory for each `create-app` execution. + +- b665f2ce65: Change base node image from node:18-bullseye-slim to node:18-bookworm-slim due to Docker build error on bullseye. + + You can apply these change to your own `Dockerfile` by replacing `node:18-bullseye-slim` with `node:18-bookworm-slim` + +- deed089a3d: Bump `cypress` to fix the end-to-end tests + +- de42eebaaf: Bumped dev dependencies `@types/node` and `mock-fs`. + +- 04a3f65e15: Bump Docker base images to `node:18-bookworm-slim` to fix node compatibility issues raised during image build. + + You can apply these change to your own `Dockerfile` by replacing `node:16-bullseye-slim` with `node:18-bookworm-slim` + +- 5eacd5d213: The E2E test setup based on Cypress has been replaced with one based on [Playwright](https://playwright.dev/). Migrating existing apps is not required as this is a standalone setup, only do so if you also want to switch from Cypress to Playwright. + + The scripts to run the E2E tests have been removed from `packages/app/package.json`, as they are now instead run from the root. Instead, a new script has been added to the root `package.json`, `yarn test:e2e`, which runs the E2E tests in development mode, unless `CI` is set in the environment. + + The Playwright setup uses utilities from the new `@backstage/e2e-test-utils` package to find and include all packages in the monorepo that have an `e2e-tests` folder. + +- Updated dependencies + - @backstage/cli-common@0.1.13-next.0 + +## @backstage/dev-utils@1.0.22-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/test-utils@1.4.4-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/integration-react@1.1.20-next.0 + - @backstage/app-defaults@1.4.4-next.0 + - @backstage/core-app-api@1.10.1-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## @backstage/frontend-plugin-api@0.1.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/types@1.1.1 + +## @backstage/integration@1.7.1-next.0 + +### Patch Changes + +- 3963d0b885: Ensure that all relevant config fields are properly marked as secret +- Updated dependencies + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + +## @backstage/integration-react@1.1.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/config@1.1.0 + - @backstage/theme@0.4.2 + +## @backstage/repo-tools@0.3.5-next.0 + +### Patch Changes + +- de42eebaaf: Bumped dev dependencies `@types/node` and `mock-fs`. +- Updated dependencies + - @backstage/cli-common@0.1.13-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/cli-node@0.1.5-next.0 + - @backstage/errors@1.2.2 + +## @techdocs/cli@1.5.2-next.0 + +### Patch Changes + +- de42eebaaf: Bumped dev dependencies `@types/node` and `mock-fs`. +- 2b6e572051: Restructured tests. +- Updated dependencies + - @backstage/cli-common@0.1.13-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/plugin-techdocs-node@1.8.2-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + +## @backstage/test-utils@1.4.4-next.0 + +### Patch Changes + +- 322bbcae24: Removed the alpha `MockPluginProvider` export since the plugin configuration API has been removed. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/core-app-api@1.10.1-next.0 + - @backstage/plugin-permission-react@0.4.16-next.0 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.8 + +## @backstage/plugin-adr@0.6.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/integration-react@1.1.20-next.0 + - @backstage/plugin-adr-common@0.2.16-next.0 + - @backstage/plugin-search-react@1.7.1-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-search-common@1.2.6 + +## @backstage/plugin-adr-backend@0.4.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/plugin-adr-common@0.2.16-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/plugin-search-common@1.2.6 + +## @backstage/plugin-adr-common@0.2.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/plugin-search-common@1.2.6 + +## @backstage/plugin-airbrake@0.3.25-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/test-utils@1.4.4-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/dev-utils@1.0.22-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-airbrake-backend@0.3.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + +## @backstage/plugin-allure@0.1.41-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-analytics-module-ga@0.1.34-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/config@1.1.0 + - @backstage/theme@0.4.2 + +## @backstage/plugin-analytics-module-ga4@0.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/config@1.1.0 + - @backstage/theme@0.4.2 + +## @backstage/plugin-analytics-module-newrelic-browser@0.0.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/config@1.1.0 + +## @backstage/plugin-apache-airflow@0.2.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + +## @backstage/plugin-api-docs@0.9.12-next.0 + +### Patch Changes + +- 0117a6b47e: Adding `requestInterceptor` option to `api-docs` and pass it to SwaggerUI. This will enable to configure a proxy or headers to be sent to all the request made through the `Try it out` button on SwaggerUI. +- 18f1756908: added aria-label on api definition button for better a11y. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/plugin-catalog@1.14.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-apollo-explorer@0.1.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/theme@0.4.2 + +## @backstage/plugin-app-backend@0.3.53-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.5.1-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-app-node@0.1.5-next.0 + +## @backstage/plugin-app-node@0.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.5-next.0 + +## @backstage/plugin-auth-backend@0.19.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-backend-module-github-provider@0.1.2-next.0 + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.1.2-next.0 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.2-next.0 + - @backstage/plugin-auth-backend-module-google-provider@0.1.2-next.0 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.1.2-next.0 + - @backstage/plugin-catalog-node@1.4.6-next.0 + +## @backstage/plugin-auth-backend-module-gcp-iap-provider@0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + +## @backstage/plugin-auth-backend-module-github-provider@0.1.2-next.0 + +### Patch Changes + +- 5d32a58b5a: Fixed a bug where the GitHub authenticator did not properly persist granted OAuth scopes. +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + +## @backstage/plugin-auth-backend-module-gitlab-provider@0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + +## @backstage/plugin-auth-backend-module-google-provider@0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + +## @backstage/plugin-auth-backend-module-oauth2-provider@0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + +## @backstage/plugin-auth-node@0.3.2-next.0 + +### Patch Changes + +- 6c2b0793bf: Fix for persisted scopes not being properly restored on sign-in. +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + +## @backstage/plugin-azure-devops@0.3.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-azure-devops-common@0.3.1 + +## @backstage/plugin-azure-devops-backend@0.4.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/plugin-azure-devops-common@0.3.1 + +## @backstage/plugin-azure-sites@0.1.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-azure-sites-common@0.1.1 + +## @backstage/plugin-azure-sites-backend@0.1.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/plugin-azure-sites-common@0.1.1 + +## @backstage/plugin-badges@0.2.49-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-badges-backend@0.3.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + +## @backstage/plugin-bazaar@0.2.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/cli@0.23.0-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/plugin-catalog@1.14.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-bazaar-backend@0.3.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/errors@1.2.2 + +## @backstage/plugin-bitbucket-cloud-common@0.2.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + +## @backstage/plugin-bitrise@0.1.52-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-catalog-backend-module-aws@0.2.8-next.0 + +### Patch Changes + +- 890e3b5ad4: Make sure to include the error message when ingestion fails +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/integration-aws-node@0.1.6 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-catalog-node@1.4.6-next.0 + - @backstage/plugin-kubernetes-common@0.6.6 + +## @backstage/plugin-catalog-backend-module-azure@0.1.24-next.0 + +### Patch Changes + +- 890e3b5ad4: Make sure to include the error message when ingestion fails +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-catalog-node@1.4.6-next.0 + +## @backstage/plugin-catalog-backend-module-bitbucket@0.2.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.13-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-node@1.4.6-next.0 + +## @backstage/plugin-catalog-backend-module-bitbucket-cloud@0.1.20-next.0 + +### Patch Changes + +- 890e3b5ad4: Make sure to include the error message when ingestion fails +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.13-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-catalog-node@1.4.6-next.0 + - @backstage/plugin-events-node@0.2.14-next.0 + +## @backstage/plugin-catalog-backend-module-bitbucket-server@0.1.18-next.0 + +### Patch Changes + +- 890e3b5ad4: Make sure to include the error message when ingestion fails +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/plugin-catalog-node@1.4.6-next.0 + +## @backstage/plugin-catalog-backend-module-gcp@0.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/plugin-catalog-node@1.4.6-next.0 + - @backstage/plugin-kubernetes-common@0.6.6 + +## @backstage/plugin-catalog-backend-module-gerrit@0.1.21-next.0 + +### Patch Changes + +- 890e3b5ad4: Make sure to include the error message when ingestion fails +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/plugin-catalog-node@1.4.6-next.0 + +## @backstage/plugin-catalog-backend-module-github@0.4.3-next.0 + +### Patch Changes + +- 890e3b5ad4: Make sure to include the error message when ingestion fails +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/plugin-catalog-backend@1.14.0-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-catalog-node@1.4.6-next.0 + - @backstage/plugin-events-node@0.2.14-next.0 + +## @backstage/plugin-catalog-backend-module-gitlab@0.3.2-next.0 + +### Patch Changes + +- 890e3b5ad4: Make sure to include the error message when ingestion fails +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-node@1.4.6-next.0 + +## @backstage/plugin-catalog-backend-module-incremental-ingestion@0.4.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.14.0-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/plugin-catalog-node@1.4.6-next.0 + - @backstage/plugin-events-node@0.2.14-next.0 + - @backstage/plugin-permission-common@0.7.8 + +## @backstage/plugin-catalog-backend-module-ldap@0.5.20-next.0 + +### Patch Changes + +- 890e3b5ad4: Make sure to include the error message when ingestion fails +- Updated dependencies + - @backstage/config@1.1.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-catalog-node@1.4.6-next.0 + +## @backstage/plugin-catalog-backend-module-msgraph@0.5.12-next.0 + +### Patch Changes + +- 890e3b5ad4: Make sure to include the error message when ingestion fails +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-catalog-node@1.4.6-next.0 + +## @backstage/plugin-catalog-backend-module-openapi@0.1.22-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/plugin-catalog-backend@1.14.0-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-catalog-node@1.4.6-next.0 + +## @backstage/plugin-catalog-backend-module-puppetdb@0.1.10-next.0 + +### Patch Changes + +- 890e3b5ad4: Make sure to include the error message when ingestion fails +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-node@1.4.6-next.0 + +## @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-catalog-node@1.4.6-next.0 + - @backstage/plugin-scaffolder-common@1.4.1 + +## @backstage/plugin-catalog-backend-module-unprocessed@0.3.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/catalog-model@1.4.2 + +## @backstage/plugin-catalog-graph@0.2.37-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-import@0.10.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/integration-react@1.1.20-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/plugin-catalog-common@1.0.16 + +## @backstage/plugin-catalog-node@1.4.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.16 + +## @backstage/plugin-catalog-react@1.8.5-next.0 + +### Patch Changes + +- a402e1dfb9: Fixed an issue causing `EntityPage` to show an error for entities containing special characters +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/plugin-permission-react@0.4.16-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.5 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-permission-common@0.7.8 + +## @backstage/plugin-catalog-unprocessed-entities@0.1.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-cicd-statistics@0.1.27-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + +## @backstage/plugin-cicd-statistics-module-gitlab@0.1.21-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/plugin-cicd-statistics@0.1.27-next.0 + - @backstage/catalog-model@1.4.2 + +## @backstage/plugin-circleci@0.3.25-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-cloudbuild@0.3.25-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-code-climate@0.1.25-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-code-coverage@0.2.18-next.0 + +### Patch Changes + +- a468544fa9: Updated layout to improve contrasts and consistency with other plugins +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-code-coverage-backend@0.2.19-next.0 + +### Patch Changes + +- 4aa27aa200: Added option to set body size limit +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + +## @backstage/plugin-codescene@0.1.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-config-schema@0.1.46-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + +## @backstage/plugin-cost-insights@0.12.14-next.0 + +### Patch Changes + +- 959aa2a09f: The experimental plugin configuration has been removed. The trend line can now instead be hidden by setting `costInsights.hideTrendLine` to `true` in the configuration. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-cost-insights-common@0.1.2 + +## @backstage/plugin-devtools@0.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/plugin-permission-react@0.4.16-next.0 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.4 + +## @backstage/plugin-devtools-backend@0.2.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/config-loader@1.5.1-next.0 + - @backstage/cli-common@0.1.13-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.4 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-permission-node@0.7.16-next.0 + +## @backstage/plugin-dynatrace@7.0.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-entity-feedback@0.2.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## @backstage/plugin-entity-feedback-backend@0.2.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## @backstage/plugin-entity-validation@0.1.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-catalog-common@1.0.16 + +## @backstage/plugin-events-backend@0.2.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/plugin-events-node@0.2.14-next.0 + +## @backstage/plugin-events-backend-module-aws-sqs@0.2.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.2.14-next.0 + +## @backstage/plugin-events-backend-module-azure@0.1.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/plugin-events-node@0.2.14-next.0 + +## @backstage/plugin-events-backend-module-bitbucket-cloud@0.1.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/plugin-events-node@0.2.14-next.0 + +## @backstage/plugin-events-backend-module-gerrit@0.1.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/plugin-events-node@0.2.14-next.0 + +## @backstage/plugin-events-backend-module-github@0.1.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/plugin-events-node@0.2.14-next.0 + +## @backstage/plugin-events-backend-module-gitlab@0.1.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/plugin-events-node@0.2.14-next.0 + +## @backstage/plugin-events-backend-test-utils@0.1.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.2.14-next.0 + +## @backstage/plugin-events-node@0.2.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.5-next.0 + +## @backstage/plugin-explore@0.4.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/plugin-explore-react@0.0.32-next.0 + - @backstage/plugin-search-react@1.7.1-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-common@1.2.6 + +## @backstage/plugin-explore-backend@0.0.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/types@1.1.1 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-backend-module-explore@0.1.9-next.0 + - @backstage/plugin-search-common@1.2.6 + +## @backstage/plugin-explore-react@0.0.32-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/plugin-explore-common@0.0.2 + +## @backstage/plugin-firehydrant@0.2.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-fossa@0.2.57-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-gcalendar@0.3.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-gcp-projects@0.3.42-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/theme@0.4.2 + +## @backstage/plugin-git-release-manager@0.3.38-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/theme@0.4.2 + +## @backstage/plugin-github-actions@0.6.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/integration-react@1.1.20-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-github-deployments@0.1.56-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/integration-react@1.1.20-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-github-issues@0.2.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-github-pull-requests-board@0.1.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-gitops-profiles@0.3.41-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/config@1.1.0 + - @backstage/theme@0.4.2 + +## @backstage/plugin-gocd@0.1.31-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-graphiql@0.2.55-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/frontend-plugin-api@0.1.1-next.0 + - @backstage/theme@0.4.2 + +## @backstage/plugin-graphql-backend@0.1.43-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/plugin-catalog-graphql@0.3.23 + +## @backstage/plugin-graphql-voyager@0.1.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/theme@0.4.2 + +## @backstage/plugin-home@0.5.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/config@1.1.0 + - @backstage/plugin-home-react@0.1.4-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-home-react@0.1.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + +## @backstage/plugin-ilert@0.2.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-jenkins@0.8.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-jenkins-common@0.1.19 + +## @backstage/plugin-jenkins-backend@0.2.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/plugin-jenkins-common@0.1.19 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-permission-node@0.7.16-next.0 + +## @backstage/plugin-kafka@0.3.25-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-kafka-backend@0.3.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + +## @backstage/plugin-kubernetes@0.10.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + - @backstage/plugin-kubernetes-common@0.6.6 + +## @backstage/plugin-kubernetes-backend@0.12.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/integration-aws-node@0.1.6 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-node@1.4.6-next.0 + - @backstage/plugin-kubernetes-common@0.6.6 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-permission-node@0.7.16-next.0 + +## @backstage/plugin-lighthouse@0.4.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-lighthouse-common@0.1.3 + +## @backstage/plugin-lighthouse-backend@0.3.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-node@1.4.6-next.0 + - @backstage/plugin-lighthouse-common@0.1.3 + +## @backstage/plugin-linguist@0.1.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-linguist-common@0.1.2 + +## @backstage/plugin-linguist-backend@0.5.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-node@1.4.6-next.0 + - @backstage/plugin-linguist-common@0.1.2 + +## @backstage/plugin-microsoft-calendar@0.1.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-newrelic@0.3.41-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/theme@0.4.2 + +## @backstage/plugin-newrelic-dashboard@0.2.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + +## @backstage/plugin-nomad@0.1.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-nomad-backend@0.1.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + +## @backstage/plugin-octopus-deploy@0.2.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-opencost@0.2.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/theme@0.4.2 + +## @backstage/plugin-org@0.6.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-org-react@0.1.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-pagerduty@0.6.6-next.0 + +### Patch Changes + +- b9ce306814: Minor fix to avoid usage of deprecated prop +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/plugin-home-react@0.1.4-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-periskop@0.1.23-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-periskop-backend@0.2.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + +## @backstage/plugin-permission-backend@0.5.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/errors@1.2.2 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-permission-node@0.7.16-next.0 + +## @backstage/plugin-permission-backend-module-allow-all-policy@0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-permission-node@0.7.16-next.0 + +## @backstage/plugin-permission-node@0.7.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/errors@1.2.2 + - @backstage/plugin-permission-common@0.7.8 + +## @backstage/plugin-permission-react@0.4.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/plugin-permission-common@0.7.8 + +## @backstage/plugin-playlist@0.1.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/plugin-permission-react@0.4.16-next.0 + - @backstage/plugin-search-react@1.7.1-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-playlist-common@0.1.10 + +## @backstage/plugin-playlist-backend@0.3.9-next.0 + +### Patch Changes + +- 9e46f5ff49: Added support to the playlist plugin for the new backend +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-permission-node@0.7.16-next.0 + - @backstage/plugin-playlist-common@0.1.10 + +## @backstage/plugin-proxy-backend@0.4.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + +## @backstage/plugin-puppetdb@0.1.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-rollbar@0.4.25-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-rollbar-backend@0.1.50-next.0 + +### Patch Changes + +- 407f4284be: ensure rollbar token is hidden +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + +## @backstage/plugin-scaffolder@1.15.1-next.0 + +### Patch Changes + +- b337d78c3b: fixed issue related template editor fails with multiple templates per file. +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/integration-react@1.1.20-next.0 + - @backstage/plugin-scaffolder-react@1.5.6-next.0 + - @backstage/config@1.1.0 + - @backstage/plugin-permission-react@0.4.16-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-scaffolder-common@1.4.1 + +## @backstage/plugin-scaffolder-backend@1.17.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/plugin-catalog-backend@1.14.0-next.0 + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/plugin-scaffolder-node@0.2.5-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.2-next.0 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-catalog-node@1.4.6-next.0 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-permission-node@0.7.16-next.0 + - @backstage/plugin-scaffolder-common@1.4.1 + +## @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/plugin-scaffolder-node@0.2.5-next.0 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.2.29-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/plugin-scaffolder-node@0.2.5-next.0 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-gitlab@0.2.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/plugin-scaffolder-node@0.2.5-next.0 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + +## @backstage/plugin-scaffolder-backend-module-rails@0.4.22-next.0 + +### Patch Changes + +- de42eebaaf: Bumped dev dependencies `@types/node` and `mock-fs`. +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/plugin-scaffolder-node@0.2.5-next.0 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-sentry@0.1.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.5-next.0 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + +## @backstage/plugin-scaffolder-backend-module-yeoman@0.2.26-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.5-next.0 + - @backstage/config@1.1.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-node@0.2.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-common@1.4.1 + +## @backstage/plugin-scaffolder-react@1.5.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.5 + - @backstage/plugin-scaffolder-common@1.4.1 + +## @backstage/plugin-search@1.4.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/config@1.1.0 + - @backstage/plugin-search-react@1.7.1-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.5 + - @backstage/plugin-search-common@1.2.6 + +## @backstage/plugin-search-backend@1.4.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-openapi-utils@0.0.4 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-permission-node@0.7.16-next.0 + - @backstage/plugin-search-backend-node@1.2.9-next.0 + - @backstage/plugin-search-common@1.2.6 + +## @backstage/plugin-search-backend-module-catalog@0.1.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-catalog-node@1.4.6-next.0 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-search-backend-node@1.2.9-next.0 + - @backstage/plugin-search-common@1.2.6 + +## @backstage/plugin-search-backend-module-elasticsearch@1.3.8-next.0 + +### Patch Changes + +- 3963d0b885: Ensure that all relevant config fields are properly marked as secret +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/integration-aws-node@0.1.6 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/plugin-search-backend-node@1.2.9-next.0 + - @backstage/plugin-search-common@1.2.6 + +## @backstage/plugin-search-backend-module-explore@0.1.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-backend-node@1.2.9-next.0 + - @backstage/plugin-search-common@1.2.6 + +## @backstage/plugin-search-backend-module-pg@0.5.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/plugin-search-backend-node@1.2.9-next.0 + - @backstage/plugin-search-common@1.2.6 + +## @backstage/plugin-search-backend-module-techdocs@0.1.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/plugin-techdocs-node@1.8.2-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-catalog-node@1.4.6-next.0 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-search-backend-node@1.2.9-next.0 + - @backstage/plugin-search-common@1.2.6 + +## @backstage/plugin-search-backend-node@1.2.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/errors@1.2.2 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-search-common@1.2.6 + +## @backstage/plugin-search-react@1.7.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.5 + - @backstage/plugin-search-common@1.2.6 + +## @backstage/plugin-sentry@0.5.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-shortcuts@0.3.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + +## @backstage/plugin-sonarqube@0.7.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-sonarqube-react@0.1.9-next.0 + +## @backstage/plugin-sonarqube-backend@0.2.7-next.0 + +### Patch Changes + +- a5d592d0ad: Added support for the [new backend system](https://backstage.io/docs/backend-system/) +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/errors@1.2.2 + +## @backstage/plugin-sonarqube-react@0.1.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + +## @backstage/plugin-splunk-on-call@0.4.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-stack-overflow@0.1.21-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/config@1.1.0 + - @backstage/plugin-home-react@0.1.4-next.0 + - @backstage/plugin-search-react@1.7.1-next.0 + - @backstage/theme@0.4.2 + - @backstage/plugin-search-common@1.2.6 + +## @backstage/plugin-stack-overflow-backend@0.2.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/plugin-search-common@1.2.6 + +## @backstage/plugin-stackstorm@0.1.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-tech-insights@0.3.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-insights-backend@0.5.19-next.0 + +### Patch Changes + +- cc7dddfa7f: Increase the maximum allowed length of an entity filter for tech insights fact schemas. +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + - @backstage/plugin-tech-insights-node@0.4.11-next.0 + +## @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.37-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + - @backstage/plugin-tech-insights-common@0.2.12 + - @backstage/plugin-tech-insights-node@0.4.11-next.0 + +## @backstage/plugin-tech-insights-node@0.4.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-radar@0.6.9-next.0 + +### Patch Changes + +- c09d2fa1d6: Added experimental support for the declarative integration. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/frontend-plugin-api@0.1.1-next.0 + - @backstage/theme@0.4.2 + +## @backstage/plugin-techdocs@1.7.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/integration-react@1.1.20-next.0 + - @backstage/config@1.1.0 + - @backstage/plugin-search-react@1.7.1-next.0 + - @backstage/plugin-techdocs-react@1.1.12-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-search-common@1.2.6 + +## @backstage/plugin-techdocs-addons-test-utils@1.0.22-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/test-utils@1.4.4-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/plugin-catalog@1.14.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/integration-react@1.1.20-next.0 + - @backstage/plugin-techdocs@1.7.1-next.0 + - @backstage/core-app-api@1.10.1-next.0 + - @backstage/plugin-search-react@1.7.1-next.0 + - @backstage/plugin-techdocs-react@1.1.12-next.0 + - @backstage/theme@0.4.2 + +## @backstage/plugin-techdocs-backend@1.7.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/plugin-techdocs-node@1.8.2-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-search-backend-module-techdocs@0.1.9-next.0 + - @backstage/plugin-search-common@1.2.6 + +## @backstage/plugin-techdocs-module-addons-contrib@1.1.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/integration-react@1.1.20-next.0 + - @backstage/plugin-techdocs-react@1.1.12-next.0 + - @backstage/theme@0.4.2 + +## @backstage/plugin-techdocs-node@1.8.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/integration-aws-node@0.1.6 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/plugin-search-common@1.2.6 + +## @backstage/plugin-techdocs-react@1.1.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/version-bridge@1.0.5 + +## @backstage/plugin-todo@0.2.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-todo-backend@0.3.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-openapi-utils@0.0.4 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/plugin-catalog-node@1.4.6-next.0 + +## @backstage/plugin-user-settings@0.7.11-next.0 + +### Patch Changes + +- d1b637d005: Fixed a bug where the theme icons would not be colored according to their active state. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/core-app-api@1.10.1-next.0 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + +## @backstage/plugin-user-settings-backend@0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + +## @backstage/plugin-vault@0.1.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-vault-backend@0.3.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/errors@1.2.2 + +## @backstage/plugin-xcmetrics@0.2.44-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## example-app@0.2.88-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-app-api@0.2.0-next.0 + - @backstage/plugin-pagerduty@0.6.6-next.0 + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/cli@0.23.0-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/plugin-catalog@1.14.0-next.0 + - @backstage/plugin-scaffolder@1.15.1-next.0 + - @backstage/plugin-tech-radar@0.6.9-next.0 + - @backstage/plugin-user-settings@0.7.11-next.0 + - @backstage/plugin-api-docs@0.9.12-next.0 + - @backstage/plugin-code-coverage@0.2.18-next.0 + - @backstage/plugin-cost-insights@0.12.14-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/integration-react@1.1.20-next.0 + - @backstage/plugin-catalog-import@0.10.1-next.0 + - @backstage/plugin-github-actions@0.6.6-next.0 + - @backstage/plugin-techdocs@1.7.1-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.1-next.0 + - @backstage/plugin-adr@0.6.8-next.0 + - @backstage/plugin-airbrake@0.3.25-next.0 + - @backstage/plugin-azure-devops@0.3.7-next.0 + - @backstage/plugin-azure-sites@0.1.14-next.0 + - @backstage/plugin-badges@0.2.49-next.0 + - @backstage/plugin-catalog-graph@0.2.37-next.0 + - @backstage/plugin-circleci@0.3.25-next.0 + - @backstage/plugin-cloudbuild@0.3.25-next.0 + - @backstage/plugin-dynatrace@7.0.5-next.0 + - @backstage/plugin-entity-feedback@0.2.8-next.0 + - @backstage/plugin-explore@0.4.11-next.0 + - @backstage/plugin-gocd@0.1.31-next.0 + - @backstage/plugin-home@0.5.9-next.0 + - @backstage/plugin-jenkins@0.8.7-next.0 + - @backstage/plugin-kafka@0.3.25-next.0 + - @backstage/plugin-kubernetes@0.10.4-next.0 + - @backstage/plugin-lighthouse@0.4.10-next.0 + - @backstage/plugin-linguist@0.1.10-next.0 + - @backstage/plugin-newrelic-dashboard@0.2.18-next.0 + - @backstage/plugin-nomad@0.1.6-next.0 + - @backstage/plugin-octopus-deploy@0.2.7-next.0 + - @backstage/plugin-org@0.6.15-next.0 + - @backstage/plugin-playlist@0.1.17-next.0 + - @backstage/plugin-puppetdb@0.1.8-next.0 + - @backstage/plugin-rollbar@0.4.25-next.0 + - @backstage/plugin-scaffolder-react@1.5.6-next.0 + - @backstage/plugin-search@1.4.1-next.0 + - @backstage/plugin-sentry@0.5.10-next.0 + - @backstage/plugin-tech-insights@0.3.17-next.0 + - @backstage/plugin-todo@0.2.28-next.0 + - @backstage/app-defaults@1.4.4-next.0 + - @backstage/config@1.1.0 + - @backstage/core-app-api@1.10.1-next.0 + - @backstage/plugin-apache-airflow@0.2.16-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.1.4-next.0 + - @backstage/plugin-devtools@0.1.5-next.0 + - @backstage/plugin-gcalendar@0.3.19-next.0 + - @backstage/plugin-gcp-projects@0.3.42-next.0 + - @backstage/plugin-graphiql@0.2.55-next.0 + - @backstage/plugin-microsoft-calendar@0.1.8-next.0 + - @backstage/plugin-newrelic@0.3.41-next.0 + - @backstage/plugin-permission-react@0.4.16-next.0 + - @backstage/plugin-search-react@1.7.1-next.0 + - @backstage/plugin-shortcuts@0.3.15-next.0 + - @backstage/plugin-stack-overflow@0.1.21-next.0 + - @backstage/plugin-stackstorm@0.1.7-next.0 + - @backstage/plugin-techdocs-react@1.1.12-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.6 + +## example-app-next@0.0.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-app-api@0.2.0-next.0 + - @backstage/plugin-pagerduty@0.6.6-next.0 + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/cli@0.23.0-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/plugin-catalog@1.14.0-next.0 + - @backstage/plugin-scaffolder@1.15.1-next.0 + - @backstage/plugin-tech-radar@0.6.9-next.0 + - @backstage/plugin-user-settings@0.7.11-next.0 + - @backstage/plugin-api-docs@0.9.12-next.0 + - @backstage/plugin-code-coverage@0.2.18-next.0 + - @backstage/plugin-cost-insights@0.12.14-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/frontend-plugin-api@0.1.1-next.0 + - @backstage/integration-react@1.1.20-next.0 + - @backstage/plugin-catalog-import@0.10.1-next.0 + - @backstage/plugin-github-actions@0.6.6-next.0 + - @backstage/plugin-techdocs@1.7.1-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.1-next.0 + - @backstage/plugin-adr@0.6.8-next.0 + - @backstage/plugin-airbrake@0.3.25-next.0 + - @backstage/plugin-azure-devops@0.3.7-next.0 + - @backstage/plugin-azure-sites@0.1.14-next.0 + - @backstage/plugin-badges@0.2.49-next.0 + - @backstage/plugin-catalog-graph@0.2.37-next.0 + - @backstage/plugin-circleci@0.3.25-next.0 + - @backstage/plugin-cloudbuild@0.3.25-next.0 + - @backstage/plugin-dynatrace@7.0.5-next.0 + - @backstage/plugin-entity-feedback@0.2.8-next.0 + - @backstage/plugin-explore@0.4.11-next.0 + - @backstage/plugin-gocd@0.1.31-next.0 + - @backstage/plugin-home@0.5.9-next.0 + - @backstage/plugin-jenkins@0.8.7-next.0 + - @backstage/plugin-kafka@0.3.25-next.0 + - @backstage/plugin-kubernetes@0.10.4-next.0 + - @backstage/plugin-lighthouse@0.4.10-next.0 + - @backstage/plugin-linguist@0.1.10-next.0 + - @backstage/plugin-newrelic-dashboard@0.2.18-next.0 + - @backstage/plugin-octopus-deploy@0.2.7-next.0 + - @backstage/plugin-org@0.6.15-next.0 + - @backstage/plugin-playlist@0.1.17-next.0 + - @backstage/plugin-puppetdb@0.1.8-next.0 + - @backstage/plugin-rollbar@0.4.25-next.0 + - @backstage/plugin-scaffolder-react@1.5.6-next.0 + - @backstage/plugin-search@1.4.1-next.0 + - @backstage/plugin-sentry@0.5.10-next.0 + - @backstage/plugin-tech-insights@0.3.17-next.0 + - @backstage/plugin-todo@0.2.28-next.0 + - @backstage/app-defaults@1.4.4-next.0 + - @backstage/config@1.1.0 + - @backstage/core-app-api@1.10.1-next.0 + - @backstage/plugin-apache-airflow@0.2.16-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.1.4-next.0 + - @backstage/plugin-devtools@0.1.5-next.0 + - @backstage/plugin-gcalendar@0.3.19-next.0 + - @backstage/plugin-gcp-projects@0.3.42-next.0 + - @backstage/plugin-graphiql@0.2.55-next.0 + - @backstage/plugin-microsoft-calendar@0.1.8-next.0 + - @backstage/plugin-newrelic@0.3.41-next.0 + - @backstage/plugin-permission-react@0.4.16-next.0 + - @backstage/plugin-search-react@1.7.1-next.0 + - @backstage/plugin-shortcuts@0.3.15-next.0 + - @backstage/plugin-stack-overflow@0.1.21-next.0 + - @backstage/plugin-stackstorm@0.1.7-next.0 + - @backstage/plugin-techdocs-react@1.1.12-next.0 + - app-next-example-plugin@0.0.2-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.6 + +## app-next-example-plugin@0.0.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.0 + - @backstage/frontend-plugin-api@0.1.1-next.0 + +## example-backend@0.2.88-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-backend-module-elasticsearch@1.3.8-next.0 + - @backstage/integration@1.7.1-next.0 + - @backstage/plugin-playlist-backend@0.3.9-next.0 + - @backstage/plugin-rollbar-backend@0.1.50-next.0 + - @backstage/plugin-catalog-backend@1.14.0-next.0 + - @backstage/plugin-tech-insights-backend@0.5.19-next.0 + - @backstage/plugin-code-coverage-backend@0.2.19-next.0 + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.22-next.0 + - @backstage/backend-common@0.19.7-next.0 + - example-app@0.2.88-next.0 + - @backstage/plugin-adr-backend@0.4.2-next.0 + - @backstage/plugin-scaffolder-backend@1.17.3-next.0 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.6-next.0 + - @backstage/plugin-techdocs-backend@1.7.2-next.0 + - @backstage/plugin-todo-backend@0.3.3-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/plugin-app-backend@0.3.53-next.0 + - @backstage/plugin-auth-backend@0.19.2-next.0 + - @backstage/plugin-azure-devops-backend@0.4.2-next.0 + - @backstage/plugin-azure-sites-backend@0.1.15-next.0 + - @backstage/plugin-badges-backend@0.3.2-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.2-next.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.2-next.0 + - @backstage/plugin-catalog-node@1.4.6-next.0 + - @backstage/plugin-devtools-backend@0.2.2-next.0 + - @backstage/plugin-entity-feedback-backend@0.2.2-next.0 + - @backstage/plugin-events-backend@0.2.14-next.0 + - @backstage/plugin-events-node@0.2.14-next.0 + - @backstage/plugin-explore-backend@0.0.15-next.0 + - @backstage/plugin-graphql-backend@0.1.43-next.0 + - @backstage/plugin-jenkins-backend@0.2.8-next.0 + - @backstage/plugin-kafka-backend@0.3.2-next.0 + - @backstage/plugin-kubernetes-backend@0.12.2-next.0 + - @backstage/plugin-lighthouse-backend@0.3.2-next.0 + - @backstage/plugin-linguist-backend@0.5.2-next.0 + - @backstage/plugin-nomad-backend@0.1.7-next.0 + - @backstage/plugin-permission-backend@0.5.28-next.0 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-permission-node@0.7.16-next.0 + - @backstage/plugin-proxy-backend@0.4.2-next.0 + - @backstage/plugin-search-backend@1.4.5-next.0 + - @backstage/plugin-search-backend-module-catalog@0.1.9-next.0 + - @backstage/plugin-search-backend-module-explore@0.1.9-next.0 + - @backstage/plugin-search-backend-module-pg@0.5.14-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.9-next.0 + - @backstage/plugin-search-backend-node@1.2.9-next.0 + - @backstage/plugin-search-common@1.2.6 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.37-next.0 + - @backstage/plugin-tech-insights-node@0.4.11-next.0 + +## example-backend-next@0.0.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-sonarqube-backend@0.2.7-next.0 + - @backstage/plugin-playlist-backend@0.3.9-next.0 + - @backstage/plugin-catalog-backend@1.14.0-next.0 + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/plugin-adr-backend@0.4.2-next.0 + - @backstage/plugin-scaffolder-backend@1.17.3-next.0 + - @backstage/plugin-techdocs-backend@1.7.2-next.0 + - @backstage/plugin-todo-backend@0.3.3-next.0 + - @backstage/backend-defaults@0.2.5-next.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/plugin-app-backend@0.3.53-next.0 + - @backstage/plugin-azure-devops-backend@0.4.2-next.0 + - @backstage/plugin-badges-backend@0.3.2-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.2-next.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.2-next.0 + - @backstage/plugin-devtools-backend@0.2.2-next.0 + - @backstage/plugin-entity-feedback-backend@0.2.2-next.0 + - @backstage/plugin-kubernetes-backend@0.12.2-next.0 + - @backstage/plugin-lighthouse-backend@0.3.2-next.0 + - @backstage/plugin-linguist-backend@0.5.2-next.0 + - @backstage/plugin-permission-backend@0.5.28-next.0 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.2-next.0 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-permission-node@0.7.16-next.0 + - @backstage/plugin-proxy-backend@0.4.2-next.0 + - @backstage/plugin-search-backend@1.4.5-next.0 + - @backstage/plugin-search-backend-module-catalog@0.1.9-next.0 + - @backstage/plugin-search-backend-module-explore@0.1.9-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.9-next.0 + - @backstage/plugin-search-backend-node@1.2.9-next.0 + +## @backstage/backend-plugin-manager@0.0.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.14.0-next.0 + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/cli-common@0.1.13-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/plugin-scaffolder-node@0.2.5-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/cli-node@0.1.5-next.0 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-events-backend@0.2.14-next.0 + - @backstage/plugin-events-node@0.2.14-next.0 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-permission-node@0.7.16-next.0 + - @backstage/plugin-search-backend-node@1.2.9-next.0 + - @backstage/plugin-search-common@1.2.6 + +## e2e-test@0.2.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.6-next.0 + - @backstage/cli-common@0.1.13-next.0 + - @backstage/errors@1.2.2 + +## techdocs-cli-embedded-app@0.2.87-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/test-utils@1.4.4-next.0 + - @backstage/cli@0.23.0-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/plugin-catalog@1.14.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/integration-react@1.1.20-next.0 + - @backstage/plugin-techdocs@1.7.1-next.0 + - @backstage/app-defaults@1.4.4-next.0 + - @backstage/config@1.1.0 + - @backstage/core-app-api@1.10.1-next.0 + - @backstage/plugin-techdocs-react@1.1.12-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## @internal/plugin-todo-list@1.0.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/theme@0.4.2 + +## @internal/plugin-todo-list-backend@1.0.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/errors@1.2.2 diff --git a/docs/releases/v1.19.0-next.1-changelog.md b/docs/releases/v1.19.0-next.1-changelog.md new file mode 100644 index 0000000000..1b6075095b --- /dev/null +++ b/docs/releases/v1.19.0-next.1-changelog.md @@ -0,0 +1,2758 @@ +# Release v1.19.0-next.1 + +## @backstage/plugin-kubernetes@0.11.0-next.1 + +### Minor Changes + +- 2d8151061c: Refactor Kubernetes plugins in line with ADR 11, no breaking changes yet + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-kubernetes-common@0.7.0-next.0 + - @backstage/plugin-kubernetes-react@0.1.0-next.0 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + +## @backstage/plugin-kubernetes-common@0.7.0-next.0 + +### Minor Changes + +- 2d8151061c: Refactor Kubernetes plugins in line with ADR 11, no breaking changes yet + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.8 + +## @backstage/plugin-kubernetes-react@0.1.0-next.0 + +### Minor Changes + +- 2d8151061c: Refactor Kubernetes plugins in line with ADR 11, no breaking changes yet + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-kubernetes-common@0.7.0-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-backend@1.18.0-next.1 + +### Minor Changes + +- f41099bb31: Display meaningful error to the output if Gitlab namespace not found inside `publish:gitlab`. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-backend@1.14.0-next.1 + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.2-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/plugin-permission-node@0.7.16-next.1 + - @backstage/plugin-scaffolder-node@0.2.5-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-scaffolder-common@1.4.1 + +## @backstage/app-defaults@1.4.4-next.1 + +### Patch Changes + +- 1a0616fa10: Add missing resource and template app icons +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-app-api@1.10.1-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/plugin-permission-react@0.4.16-next.0 + - @backstage/theme@0.4.2 + +## @backstage/backend-app-api@0.5.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/plugin-permission-node@0.7.16-next.1 + - @backstage/config@1.1.0 + - @backstage/cli-common@0.1.13-next.0 + - @backstage/cli-node@0.1.5-next.0 + - @backstage/config-loader@1.5.1-next.0 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + +## @backstage/backend-common@0.19.7-next.1 + +### Patch Changes + +- b94f32271e: Added the ability to fetch git tags through the `Git` class. This is useful for scaffolder actions that want to take action based on tag versions in a cloned repository +- Updated dependencies + - @backstage/backend-dev-utils@0.1.2-next.0 + - @backstage/backend-app-api@0.5.5-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/integration-aws-node@0.1.6 + - @backstage/cli-common@0.1.13-next.0 + - @backstage/config-loader@1.5.1-next.0 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/types@1.1.1 + +## @backstage/backend-defaults@0.2.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-app-api@0.5.5-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + +## @backstage/backend-dev-utils@0.1.2-next.0 + +### Patch Changes + +- afa48341fb: Fix an issue where early IPC responses would be lost. + +## @backstage/backend-plugin-api@0.6.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/config@1.1.0 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.8 + +## @backstage/backend-tasks@0.5.10-next.1 + +### Patch Changes + +- 5db102bfdf: Instrument `backend-tasks` with some counters and histograms for duration. + + `backend_tasks.task.runs.count`: Counter with the total number of times a task has been run. + `backend_tasks.task.runs.duration`: Histogram with the run durations for each task. + + Both these metrics have come with `result` `taskId` and `scope` labels for finer grained grouping. + +- ddd76ac98d: Fix bug where backend tasks that are defined with HumanDuration are immediately triggered on application startup + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + +## @backstage/backend-test-utils@0.2.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-app-api@0.5.5-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/config@1.1.0 + - @backstage/types@1.1.1 + +## @backstage/cli@0.23.0-next.1 + +### Patch Changes + +- d0f26cfa4f: Fixed an issue where the new backend start command would not gracefully shut down the backend process on Windows. +- Updated dependencies + - @backstage/config@1.1.0 + - @backstage/release-manifests@0.0.10 + - @backstage/catalog-model@1.4.2 + - @backstage/cli-common@0.1.13-next.0 + - @backstage/cli-node@0.1.5-next.0 + - @backstage/config-loader@1.5.1-next.0 + - @backstage/errors@1.2.2 + - @backstage/eslint-plugin@0.1.3 + - @backstage/integration@1.7.1-next.0 + - @backstage/types@1.1.1 + +## @backstage/core-app-api@1.10.1-next.1 + +### Patch Changes + +- 1a0616fa10: Add missing resource and template app icons +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.5 + +## @backstage/core-components@0.13.6-next.1 + +### Patch Changes + +- 4eab5cf901: The `TabbedLayout` component will now also navigate when clicking the active tab, which allows for navigation back from any sub routes. +- 997a71850c: Changed SupportButton menuitems to support text wrap +- 16126dbe6a: Change overlay header colors in the mobile menu to use navigation color from the theme +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/version-bridge@1.0.5 + +## @backstage/create-app@0.5.6-next.1 + +### Patch Changes + +- 8d2e640af4: Added missing `.eslintignore` file + + To apply this change to an existing app, create a new `.eslintignore` file at the root of your project with the following content: + + ```diff + + playwright.config.ts + ``` + +- Updated dependencies + - @backstage/cli-common@0.1.13-next.0 + +## @backstage/dev-utils@1.0.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-app-api@1.10.1-next.1 + - @backstage/app-defaults@1.4.4-next.1 + - @backstage/test-utils@1.4.4-next.1 + - @backstage/integration-react@1.1.20-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## @backstage/frontend-app-api@0.2.0-next.1 + +### Patch Changes + +- 52366db5b3: Make themes configurable through extensions, and switched default themes to use extensions instead. +- e5a2956dd2: Register default api implementations when creating declarative integrated apps. +- Updated dependencies + - @backstage/frontend-plugin-api@0.1.1-next.1 + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-app-api@1.10.1-next.1 + - @backstage/plugin-graphiql@0.2.55-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + +## @backstage/frontend-plugin-api@0.1.1-next.1 + +### Patch Changes + +- d3a37f55c0: Add support for `SidebarGroup` on the sidebar item extension. +- 52366db5b3: Added `createThemeExtension` and `coreExtensionData.theme`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/types@1.1.1 + +## @backstage/integration-react@1.1.20-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/integration@1.7.1-next.0 + - @backstage/theme@0.4.2 + +## @techdocs/cli@1.5.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/plugin-techdocs-node@1.8.2-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/cli-common@0.1.13-next.0 + +## @backstage/test-utils@1.4.4-next.1 + +### Patch Changes + +- 1a0616fa10: Add missing resource and template app icons +- Updated dependencies + - @backstage/core-app-api@1.10.1-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/plugin-permission-react@0.4.16-next.0 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.8 + +## @backstage/plugin-adr@0.6.8-next.1 + +### Patch Changes + +- 1204e7628e: Create an experimental `AdrSearchResultItemExtension` for declarative integration with Backstage; it can be accessed via the `/alpha` import. +- Updated dependencies + - @backstage/frontend-plugin-api@0.1.1-next.1 + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-search-react@1.7.1-next.1 + - @backstage/integration-react@1.1.20-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-adr-common@0.2.16-next.0 + - @backstage/plugin-search-common@1.2.6 + +## @backstage/plugin-adr-backend@0.4.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/plugin-adr-common@0.2.16-next.0 + - @backstage/plugin-search-common@1.2.6 + +## @backstage/plugin-airbrake@0.3.25-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/test-utils@1.4.4-next.1 + - @backstage/dev-utils@1.0.22-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-airbrake-backend@0.3.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + +## @backstage/plugin-allure@0.1.41-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-analytics-module-ga@0.1.34-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/theme@0.4.2 + +## @backstage/plugin-analytics-module-ga4@0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/theme@0.4.2 + +## @backstage/plugin-analytics-module-newrelic-browser@0.0.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + +## @backstage/plugin-apache-airflow@0.2.16-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + +## @backstage/plugin-api-docs@0.9.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.14.0-next.1 + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-apollo-explorer@0.1.16-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/theme@0.4.2 + +## @backstage/plugin-app-backend@0.3.53-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/config-loader@1.5.1-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-app-node@0.1.5-next.1 + +## @backstage/plugin-app-node@0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.5-next.1 + +## @backstage/plugin-auth-backend@0.19.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-auth-backend-module-github-provider@0.1.2-next.1 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.2-next.1 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.1.2-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.1.2-next.1 + - @backstage/plugin-auth-backend-module-google-provider@0.1.2-next.1 + +## @backstage/plugin-auth-backend-module-gcp-iap-provider@0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + +## @backstage/plugin-auth-backend-module-github-provider@0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + +## @backstage/plugin-auth-backend-module-gitlab-provider@0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + +## @backstage/plugin-auth-backend-module-google-provider@0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + +## @backstage/plugin-auth-backend-module-oauth2-provider@0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + +## @backstage/plugin-auth-node@0.3.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + +## @backstage/plugin-azure-devops@0.3.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-azure-devops-common@0.3.1 + +## @backstage/plugin-azure-devops-backend@0.4.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/plugin-azure-devops-common@0.3.1 + +## @backstage/plugin-azure-sites@0.1.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-azure-sites-common@0.1.1 + +## @backstage/plugin-azure-sites-backend@0.1.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/config@1.1.0 + - @backstage/plugin-azure-sites-common@0.1.1 + +## @backstage/plugin-badges@0.2.49-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-badges-backend@0.3.2-next.1 + +### Patch Changes + +- 817f2acbb1: Make sure the default badge factory is used if nothing is defined +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + +## @backstage/plugin-bazaar@0.2.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.14.0-next.1 + - @backstage/core-components@0.13.6-next.1 + - @backstage/cli@0.23.0-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-bazaar-backend@0.3.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + +## @backstage/plugin-bitrise@0.1.52-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-catalog@1.14.0-next.1 + +### Patch Changes + +- 7c4a8e4d5f: Create an experimental `CatalogSearchResultItemExtension` for declarative integration with Backstage; it can be accessed via the `/alpha` import. +- e5a2956dd2: Migrate catalog api to declarative integration system, it is exported from `/alpha` subpath. +- Updated dependencies + - @backstage/frontend-plugin-api@0.1.1-next.1 + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-search-react@1.7.1-next.1 + - @backstage/integration-react@1.1.20-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-scaffolder-common@1.4.1 + - @backstage/plugin-search-common@1.2.6 + +## @backstage/plugin-catalog-backend@1.14.0-next.1 + +### Patch Changes + +- 7a2e2924c7: Marked the `LocationEntityProcessor` as deprecated, as it is no longer used internally since way back and can even be harmful at this point. +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.9-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/plugin-permission-node@0.7.16-next.1 + - @backstage/config@1.1.0 + - @backstage/backend-openapi-utils@0.0.4 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-events-node@0.2.14-next.1 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-scaffolder-common@1.4.1 + - @backstage/plugin-search-common@1.2.6 + +## @backstage/plugin-catalog-backend-module-aws@0.2.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/plugin-kubernetes-common@0.7.0-next.0 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/integration-aws-node@0.1.6 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.16 + +## @backstage/plugin-catalog-backend-module-azure@0.1.24-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.16 + +## @backstage/plugin-catalog-backend-module-bitbucket@0.2.20-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-bitbucket-cloud-common@0.2.13-next.0 + +## @backstage/plugin-catalog-backend-module-bitbucket-cloud@0.1.20-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.13-next.0 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-events-node@0.2.14-next.1 + +## @backstage/plugin-catalog-backend-module-bitbucket-server@0.1.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + +## @backstage/plugin-catalog-backend-module-gcp@0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/plugin-kubernetes-common@0.7.0-next.0 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + +## @backstage/plugin-catalog-backend-module-gerrit@0.1.21-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + +## @backstage/plugin-catalog-backend-module-github@0.4.3-next.1 + +### Patch Changes + +- b4b1cbf9fa: Make `defaultUserTransformer` resolve to `UserEntity` instead of `Entity` +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-backend@1.14.0-next.1 + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-events-node@0.2.14-next.1 + +## @backstage/plugin-catalog-backend-module-gitlab@0.3.2-next.1 + +### Patch Changes + +- 6ae7f12abb: Make sure the archived projects are skipped with the Gitlab API +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-backend-module-incremental-ingestion@0.4.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-backend@1.14.0-next.1 + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/plugin-events-node@0.2.14-next.1 + - @backstage/plugin-permission-common@0.7.8 + +## @backstage/plugin-catalog-backend-module-ldap@0.5.20-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.16 + +## @backstage/plugin-catalog-backend-module-msgraph@0.5.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/plugin-catalog-common@1.0.16 + +## @backstage/plugin-catalog-backend-module-openapi@0.1.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.14.0-next.1 + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.16 + +## @backstage/plugin-catalog-backend-module-puppetdb@0.1.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/catalog-model@1.4.2 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-scaffolder-common@1.4.1 + +## @backstage/plugin-catalog-backend-module-unprocessed@0.3.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/catalog-model@1.4.2 + +## @backstage/plugin-catalog-graph@0.2.37-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-import@0.10.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/integration-react@1.1.20-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/plugin-catalog-common@1.0.16 + +## @backstage/plugin-catalog-node@1.4.6-next.1 + +### Patch Changes + +- 7a2e2924c7: Added docs to `processingResult` +- Updated dependencies + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.16 + +## @backstage/plugin-catalog-react@1.8.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/plugin-permission-react@0.4.16-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.5 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-permission-common@0.7.8 + +## @backstage/plugin-catalog-unprocessed-entities@0.1.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-cicd-statistics@0.1.27-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + +## @backstage/plugin-cicd-statistics-module-gitlab@0.1.21-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/plugin-cicd-statistics@0.1.27-next.1 + +## @backstage/plugin-circleci@0.3.25-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-cloudbuild@0.3.25-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-code-climate@0.1.25-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-code-coverage@0.2.18-next.1 + +### Patch Changes + +- 88b0b32547: Fixed the coverage history statistics to compare newest with oldest record +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-code-coverage-backend@0.2.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + +## @backstage/plugin-codescene@0.1.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-config-schema@0.1.46-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + +## @backstage/plugin-cost-insights@0.12.14-next.1 + +### Patch Changes + +- ba4820883c: Updated dependency `@types/pluralize` to `^0.0.31`. +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-cost-insights-common@0.1.2 + +## @backstage/plugin-devtools@0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/plugin-permission-react@0.4.16-next.0 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.4 + +## @backstage/plugin-devtools-backend@0.2.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/plugin-permission-node@0.7.16-next.1 + - @backstage/config@1.1.0 + - @backstage/cli-common@0.1.13-next.0 + - @backstage/config-loader@1.5.1-next.0 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.4 + - @backstage/plugin-permission-common@0.7.8 + +## @backstage/plugin-dynatrace@7.0.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-entity-feedback@0.2.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## @backstage/plugin-entity-feedback-backend@0.2.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## @backstage/plugin-entity-validation@0.1.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-catalog-common@1.0.16 + +## @backstage/plugin-events-backend@0.2.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/plugin-events-node@0.2.14-next.1 + +## @backstage/plugin-events-backend-module-aws-sqs@0.2.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.2.14-next.1 + +## @backstage/plugin-events-backend-module-azure@0.1.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-events-node@0.2.14-next.1 + +## @backstage/plugin-events-backend-module-bitbucket-cloud@0.1.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-events-node@0.2.14-next.1 + +## @backstage/plugin-events-backend-module-gerrit@0.1.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-events-node@0.2.14-next.1 + +## @backstage/plugin-events-backend-module-github@0.1.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/plugin-events-node@0.2.14-next.1 + +## @backstage/plugin-events-backend-module-gitlab@0.1.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/plugin-events-node@0.2.14-next.1 + +## @backstage/plugin-events-backend-test-utils@0.1.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.2.14-next.1 + +## @backstage/plugin-events-node@0.2.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.5-next.1 + +## @backstage/plugin-explore@0.4.11-next.1 + +### Patch Changes + +- 0f10c53a05: Create an experimental `ExploreSearchResultItemExtension` for declarative integration with Backstage; it can be accessed via the `/alpha` import. +- Updated dependencies + - @backstage/frontend-plugin-api@0.1.1-next.1 + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-search-react@1.7.1-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/plugin-explore-react@0.0.32-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-common@1.2.6 + +## @backstage/plugin-explore-backend@0.0.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/plugin-search-backend-module-explore@0.1.9-next.1 + - @backstage/config@1.1.0 + - @backstage/types@1.1.1 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-common@1.2.6 + +## @backstage/plugin-firehydrant@0.2.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-fossa@0.2.57-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-gcalendar@0.3.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-gcp-projects@0.3.42-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/theme@0.4.2 + +## @backstage/plugin-git-release-manager@0.3.38-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/integration@1.7.1-next.0 + - @backstage/theme@0.4.2 + +## @backstage/plugin-github-actions@0.6.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/integration-react@1.1.20-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/theme@0.4.2 + +## @backstage/plugin-github-deployments@0.1.56-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/integration-react@1.1.20-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/theme@0.4.2 + +## @backstage/plugin-github-issues@0.2.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/theme@0.4.2 + +## @backstage/plugin-github-pull-requests-board@0.1.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/theme@0.4.2 + +## @backstage/plugin-gitops-profiles@0.3.41-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/theme@0.4.2 + +## @backstage/plugin-gocd@0.1.31-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-graphiql@0.2.55-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.1.1-next.1 + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/theme@0.4.2 + +## @backstage/plugin-graphql-backend@0.1.43-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/config@1.1.0 + - @backstage/plugin-catalog-graphql@0.3.23 + +## @backstage/plugin-graphql-voyager@0.1.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/theme@0.4.2 + +## @backstage/plugin-home@0.5.9-next.1 + +### Patch Changes + +- f997f771da: Adds Top/Recently Visited components to homepage +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-app-api@1.10.1-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/plugin-home-react@0.1.4-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + +## @backstage/plugin-home-react@0.1.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + +## @backstage/plugin-ilert@0.2.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-jenkins@0.8.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-jenkins-common@0.1.19 + +## @backstage/plugin-jenkins-backend@0.2.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/plugin-permission-node@0.7.16-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/plugin-jenkins-common@0.1.19 + - @backstage/plugin-permission-common@0.7.8 + +## @backstage/plugin-kafka@0.3.25-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-kafka-backend@0.3.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + +## @backstage/plugin-kubernetes-backend@0.12.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/plugin-kubernetes-common@0.7.0-next.0 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/plugin-permission-node@0.7.16-next.1 + - @backstage/config@1.1.0 + - @backstage/integration-aws-node@0.1.6 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.8 + +## @backstage/plugin-lighthouse@0.4.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-lighthouse-common@0.1.3 + +## @backstage/plugin-lighthouse-backend@0.3.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/types@1.1.1 + - @backstage/plugin-lighthouse-common@0.1.3 + +## @backstage/plugin-linguist@0.1.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-linguist-common@0.1.2 + +## @backstage/plugin-linguist-backend@0.5.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-linguist-common@0.1.2 + +## @backstage/plugin-microsoft-calendar@0.1.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-newrelic@0.3.41-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/theme@0.4.2 + +## @backstage/plugin-newrelic-dashboard@0.2.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + +## @backstage/plugin-nomad@0.1.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-nomad-backend@0.1.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + +## @backstage/plugin-octopus-deploy@0.2.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-opencost@0.2.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/theme@0.4.2 + +## @backstage/plugin-org@0.6.15-next.1 + +### Patch Changes + +- dc5b6b971b: Fixed the display of OwnershipCard with aggregated relations by loading relations when getting children of entity. + This allows the already existing recursive method to work properly when children of entity have children themselves. +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-org-react@0.1.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-pagerduty@0.6.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/plugin-home-react@0.1.4-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-periskop@0.1.23-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-periskop-backend@0.2.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + +## @backstage/plugin-permission-backend@0.5.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/plugin-permission-node@0.7.16-next.1 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + - @backstage/plugin-permission-common@0.7.8 + +## @backstage/plugin-permission-backend-module-allow-all-policy@0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/plugin-permission-node@0.7.16-next.1 + - @backstage/plugin-permission-common@0.7.8 + +## @backstage/plugin-permission-node@0.7.16-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + - @backstage/plugin-permission-common@0.7.8 + +## @backstage/plugin-playlist@0.1.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-search-react@1.7.1-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/plugin-permission-react@0.4.16-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-playlist-common@0.1.10 + +## @backstage/plugin-playlist-backend@0.3.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/plugin-permission-node@0.7.16-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-playlist-common@0.1.10 + +## @backstage/plugin-proxy-backend@0.4.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + +## @backstage/plugin-puppetdb@0.1.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-rollbar@0.4.25-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-rollbar-backend@0.1.50-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/config@1.1.0 + +## @backstage/plugin-scaffolder@1.15.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-scaffolder-react@1.5.6-next.1 + - @backstage/integration-react@1.1.20-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/plugin-permission-react@0.4.16-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-scaffolder-common@1.4.1 + +## @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/plugin-scaffolder-node@0.2.5-next.1 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.2.29-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/plugin-scaffolder-node@0.2.5-next.1 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-gitlab@0.2.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.5-next.1 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + +## @backstage/plugin-scaffolder-backend-module-rails@0.4.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/plugin-scaffolder-node@0.2.5-next.1 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-sentry@0.1.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.5-next.1 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + +## @backstage/plugin-scaffolder-backend-module-yeoman@0.2.26-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.5-next.1 + - @backstage/config@1.1.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-node@0.2.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-common@1.4.1 + +## @backstage/plugin-scaffolder-react@1.5.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.5 + - @backstage/plugin-scaffolder-common@1.4.1 + +## @backstage/plugin-search@1.4.1-next.1 + +### Patch Changes + +- e5a2956dd2: Create an experimental search plugin that is compatible with the declarative integration system, it is exported from `/alpha` subpath. +- Updated dependencies + - @backstage/frontend-plugin-api@0.1.1-next.1 + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-search-react@1.7.1-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.5 + - @backstage/plugin-search-common@1.2.6 + +## @backstage/plugin-search-backend@1.4.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-search-backend-node@1.2.9-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/plugin-permission-node@0.7.16-next.1 + - @backstage/config@1.1.0 + - @backstage/backend-openapi-utils@0.0.4 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-search-common@1.2.6 + +## @backstage/plugin-search-backend-module-catalog@0.1.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-search-backend-node@1.2.9-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-search-common@1.2.6 + +## @backstage/plugin-search-backend-module-elasticsearch@1.3.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-search-backend-node@1.2.9-next.1 + - @backstage/config@1.1.0 + - @backstage/integration-aws-node@0.1.6 + - @backstage/plugin-search-common@1.2.6 + +## @backstage/plugin-search-backend-module-explore@0.1.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-search-backend-node@1.2.9-next.1 + - @backstage/config@1.1.0 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-common@1.2.6 + +## @backstage/plugin-search-backend-module-pg@0.5.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-search-backend-node@1.2.9-next.1 + - @backstage/config@1.1.0 + - @backstage/plugin-search-common@1.2.6 + +## @backstage/plugin-search-backend-module-techdocs@0.1.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-search-backend-node@1.2.9-next.1 + - @backstage/plugin-techdocs-node@1.8.2-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-search-common@1.2.6 + +## @backstage/plugin-search-backend-node@1.2.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-search-common@1.2.6 + +## @backstage/plugin-search-react@1.7.1-next.1 + +### Patch Changes + +- 703a4ffc5b: Create `createSearchResultListItem` alpha version that only supports declarative integration. +- Updated dependencies + - @backstage/frontend-plugin-api@0.1.1-next.1 + - @backstage/core-components@0.13.6-next.1 + - @backstage/frontend-app-api@0.2.0-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.5 + - @backstage/plugin-search-common@1.2.6 + +## @backstage/plugin-sentry@0.5.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-shortcuts@0.3.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + +## @backstage/plugin-sonarqube@0.7.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-sonarqube-react@0.1.9-next.0 + +## @backstage/plugin-sonarqube-backend@0.2.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + +## @backstage/plugin-splunk-on-call@0.4.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-stack-overflow@0.1.21-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-search-react@1.7.1-next.1 + - @backstage/plugin-home-react@0.1.4-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/theme@0.4.2 + - @backstage/plugin-search-common@1.2.6 + +## @backstage/plugin-stack-overflow-backend@0.2.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/config@1.1.0 + - @backstage/plugin-search-common@1.2.6 + +## @backstage/plugin-stackstorm@0.1.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-tech-insights@0.3.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-insights-backend@0.5.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/plugin-tech-insights-node@0.4.11-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.37-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/plugin-tech-insights-node@0.4.11-next.1 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-insights-node@0.4.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/config@1.1.0 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-radar@0.6.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.1.1-next.1 + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/theme@0.4.2 + +## @backstage/plugin-techdocs@1.7.1-next.1 + +### Patch Changes + +- 4918f65ab2: Create an experimental `TechDocsSearchResultItemExtension` for declarative integration with Backstage; it can be accessed via the `/alpha` import. +- df449a7a31: Add kind column by default to TechDocsTable +- Updated dependencies + - @backstage/frontend-plugin-api@0.1.1-next.1 + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-search-react@1.7.1-next.1 + - @backstage/integration-react@1.1.20-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/plugin-techdocs-react@1.1.12-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/theme@0.4.2 + - @backstage/plugin-search-common@1.2.6 + +## @backstage/plugin-techdocs-addons-test-utils@1.0.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.14.0-next.1 + - @backstage/plugin-techdocs@1.7.1-next.1 + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-app-api@1.10.1-next.1 + - @backstage/test-utils@1.4.4-next.1 + - @backstage/plugin-search-react@1.7.1-next.1 + - @backstage/integration-react@1.1.20-next.1 + - @backstage/plugin-techdocs-react@1.1.12-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/theme@0.4.2 + +## @backstage/plugin-techdocs-backend@1.7.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.9-next.1 + - @backstage/plugin-techdocs-node@1.8.2-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-search-common@1.2.6 + +## @backstage/plugin-techdocs-module-addons-contrib@1.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/integration-react@1.1.20-next.1 + - @backstage/plugin-techdocs-react@1.1.12-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/integration@1.7.1-next.0 + - @backstage/theme@0.4.2 + +## @backstage/plugin-techdocs-node@1.8.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/config@1.1.0 + - @backstage/integration-aws-node@0.1.6 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/plugin-search-common@1.2.6 + +## @backstage/plugin-techdocs-react@1.1.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/version-bridge@1.0.5 + +## @backstage/plugin-todo@0.2.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-todo-backend@0.3.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/backend-openapi-utils@0.0.4 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + +## @backstage/plugin-user-settings@0.7.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-app-api@1.10.1-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + +## @backstage/plugin-user-settings-backend@0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + +## @backstage/plugin-vault@0.1.20-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## @backstage/plugin-vault-backend@0.3.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + +## @backstage/plugin-xcmetrics@0.2.44-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## example-app@0.2.88-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-org@0.6.15-next.1 + - @backstage/plugin-code-coverage@0.2.18-next.1 + - @backstage/plugin-catalog@1.14.0-next.1 + - @backstage/plugin-techdocs@1.7.1-next.1 + - @backstage/plugin-home@0.5.9-next.1 + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-app-api@1.10.1-next.1 + - @backstage/app-defaults@1.4.4-next.1 + - @backstage/frontend-app-api@0.2.0-next.1 + - @backstage/plugin-search@1.4.1-next.1 + - @backstage/cli@0.23.0-next.1 + - @backstage/plugin-cost-insights@0.12.14-next.1 + - @backstage/plugin-kubernetes@0.11.0-next.1 + - @backstage/plugin-adr@0.6.8-next.1 + - @backstage/plugin-explore@0.4.11-next.1 + - @backstage/plugin-search-react@1.7.1-next.1 + - @backstage/plugin-api-docs@0.9.12-next.1 + - @backstage/plugin-catalog-graph@0.2.37-next.1 + - @backstage/plugin-scaffolder@1.15.1-next.1 + - @backstage/plugin-scaffolder-react@1.5.6-next.1 + - @backstage/plugin-user-settings@0.7.11-next.1 + - @backstage/plugin-graphiql@0.2.55-next.1 + - @backstage/plugin-tech-radar@0.6.9-next.1 + - @backstage/integration-react@1.1.20-next.1 + - @backstage/plugin-airbrake@0.3.25-next.1 + - @backstage/plugin-apache-airflow@0.2.16-next.1 + - @backstage/plugin-azure-devops@0.3.7-next.1 + - @backstage/plugin-azure-sites@0.1.14-next.1 + - @backstage/plugin-badges@0.2.49-next.1 + - @backstage/plugin-catalog-import@0.10.1-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/plugin-catalog-unprocessed-entities@0.1.4-next.1 + - @backstage/plugin-circleci@0.3.25-next.1 + - @backstage/plugin-cloudbuild@0.3.25-next.1 + - @backstage/plugin-devtools@0.1.5-next.1 + - @backstage/plugin-dynatrace@7.0.5-next.1 + - @backstage/plugin-entity-feedback@0.2.8-next.1 + - @backstage/plugin-gcalendar@0.3.19-next.1 + - @backstage/plugin-gcp-projects@0.3.42-next.1 + - @backstage/plugin-github-actions@0.6.6-next.1 + - @backstage/plugin-gocd@0.1.31-next.1 + - @backstage/plugin-jenkins@0.8.7-next.1 + - @backstage/plugin-kafka@0.3.25-next.1 + - @backstage/plugin-lighthouse@0.4.10-next.1 + - @backstage/plugin-linguist@0.1.10-next.1 + - @backstage/plugin-microsoft-calendar@0.1.8-next.1 + - @backstage/plugin-newrelic@0.3.41-next.1 + - @backstage/plugin-newrelic-dashboard@0.2.18-next.1 + - @backstage/plugin-nomad@0.1.6-next.1 + - @backstage/plugin-octopus-deploy@0.2.7-next.1 + - @backstage/plugin-pagerduty@0.6.6-next.1 + - @backstage/plugin-playlist@0.1.17-next.1 + - @backstage/plugin-puppetdb@0.1.8-next.1 + - @backstage/plugin-rollbar@0.4.25-next.1 + - @backstage/plugin-sentry@0.5.10-next.1 + - @backstage/plugin-shortcuts@0.3.15-next.1 + - @backstage/plugin-stack-overflow@0.1.21-next.1 + - @backstage/plugin-stackstorm@0.1.7-next.1 + - @backstage/plugin-tech-insights@0.3.17-next.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.1-next.1 + - @backstage/plugin-techdocs-react@1.1.12-next.1 + - @backstage/plugin-todo@0.2.28-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/plugin-permission-react@0.4.16-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.6 + +## example-app-next@0.0.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-org@0.6.15-next.1 + - @backstage/plugin-code-coverage@0.2.18-next.1 + - @backstage/plugin-catalog@1.14.0-next.1 + - @backstage/plugin-techdocs@1.7.1-next.1 + - @backstage/plugin-home@0.5.9-next.1 + - @backstage/frontend-plugin-api@0.1.1-next.1 + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-app-api@1.10.1-next.1 + - @backstage/app-defaults@1.4.4-next.1 + - @backstage/frontend-app-api@0.2.0-next.1 + - @backstage/plugin-search@1.4.1-next.1 + - @backstage/cli@0.23.0-next.1 + - @backstage/plugin-cost-insights@0.12.14-next.1 + - @backstage/plugin-kubernetes@0.11.0-next.1 + - @backstage/plugin-adr@0.6.8-next.1 + - @backstage/plugin-explore@0.4.11-next.1 + - @backstage/plugin-search-react@1.7.1-next.1 + - @backstage/plugin-api-docs@0.9.12-next.1 + - @backstage/plugin-catalog-graph@0.2.37-next.1 + - @backstage/plugin-scaffolder@1.15.1-next.1 + - @backstage/plugin-scaffolder-react@1.5.6-next.1 + - @backstage/plugin-user-settings@0.7.11-next.1 + - app-next-example-plugin@0.0.2-next.1 + - @backstage/plugin-graphiql@0.2.55-next.1 + - @backstage/plugin-tech-radar@0.6.9-next.1 + - @backstage/integration-react@1.1.20-next.1 + - @backstage/plugin-airbrake@0.3.25-next.1 + - @backstage/plugin-apache-airflow@0.2.16-next.1 + - @backstage/plugin-azure-devops@0.3.7-next.1 + - @backstage/plugin-azure-sites@0.1.14-next.1 + - @backstage/plugin-badges@0.2.49-next.1 + - @backstage/plugin-catalog-import@0.10.1-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/plugin-catalog-unprocessed-entities@0.1.4-next.1 + - @backstage/plugin-circleci@0.3.25-next.1 + - @backstage/plugin-cloudbuild@0.3.25-next.1 + - @backstage/plugin-devtools@0.1.5-next.1 + - @backstage/plugin-dynatrace@7.0.5-next.1 + - @backstage/plugin-entity-feedback@0.2.8-next.1 + - @backstage/plugin-gcalendar@0.3.19-next.1 + - @backstage/plugin-gcp-projects@0.3.42-next.1 + - @backstage/plugin-github-actions@0.6.6-next.1 + - @backstage/plugin-gocd@0.1.31-next.1 + - @backstage/plugin-jenkins@0.8.7-next.1 + - @backstage/plugin-kafka@0.3.25-next.1 + - @backstage/plugin-lighthouse@0.4.10-next.1 + - @backstage/plugin-linguist@0.1.10-next.1 + - @backstage/plugin-microsoft-calendar@0.1.8-next.1 + - @backstage/plugin-newrelic@0.3.41-next.1 + - @backstage/plugin-newrelic-dashboard@0.2.18-next.1 + - @backstage/plugin-octopus-deploy@0.2.7-next.1 + - @backstage/plugin-pagerduty@0.6.6-next.1 + - @backstage/plugin-playlist@0.1.17-next.1 + - @backstage/plugin-puppetdb@0.1.8-next.1 + - @backstage/plugin-rollbar@0.4.25-next.1 + - @backstage/plugin-sentry@0.5.10-next.1 + - @backstage/plugin-shortcuts@0.3.15-next.1 + - @backstage/plugin-stack-overflow@0.1.21-next.1 + - @backstage/plugin-stackstorm@0.1.7-next.1 + - @backstage/plugin-tech-insights@0.3.17-next.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.1-next.1 + - @backstage/plugin-techdocs-react@1.1.12-next.1 + - @backstage/plugin-todo@0.2.28-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/plugin-permission-react@0.4.16-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.6 + +## app-next-example-plugin@0.0.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.1.1-next.1 + - @backstage/core-components@0.13.6-next.1 + +## example-backend@0.2.88-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-backend@1.14.0-next.1 + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/plugin-scaffolder-backend@1.18.0-next.1 + - @backstage/plugin-badges-backend@0.3.2-next.1 + - @backstage/plugin-lighthouse-backend@0.3.2-next.1 + - @backstage/plugin-linguist-backend@0.5.2-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.9-next.1 + - @backstage/plugin-search-backend-module-explore@0.1.9-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.9-next.1 + - @backstage/plugin-search-backend-node@1.2.9-next.1 + - @backstage/plugin-tech-insights-backend@0.5.19-next.1 + - @backstage/plugin-tech-insights-node@0.4.11-next.1 + - example-app@0.2.88-next.1 + - @backstage/plugin-auth-backend@0.19.2-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.2-next.1 + - @backstage/plugin-kubernetes-backend@0.12.2-next.1 + - @backstage/plugin-todo-backend@0.3.3-next.1 + - @backstage/plugin-adr-backend@0.4.2-next.1 + - @backstage/plugin-app-backend@0.3.53-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/plugin-azure-devops-backend@0.4.2-next.1 + - @backstage/plugin-azure-sites-backend@0.1.15-next.1 + - @backstage/plugin-code-coverage-backend@0.2.19-next.1 + - @backstage/plugin-devtools-backend@0.2.2-next.1 + - @backstage/plugin-entity-feedback-backend@0.2.2-next.1 + - @backstage/plugin-events-backend@0.2.14-next.1 + - @backstage/plugin-explore-backend@0.0.15-next.1 + - @backstage/plugin-graphql-backend@0.1.43-next.1 + - @backstage/plugin-jenkins-backend@0.2.8-next.1 + - @backstage/plugin-kafka-backend@0.3.2-next.1 + - @backstage/plugin-nomad-backend@0.1.7-next.1 + - @backstage/plugin-permission-backend@0.5.28-next.1 + - @backstage/plugin-permission-node@0.7.16-next.1 + - @backstage/plugin-playlist-backend@0.3.9-next.1 + - @backstage/plugin-proxy-backend@0.4.2-next.1 + - @backstage/plugin-rollbar-backend@0.1.50-next.1 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.6-next.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.22-next.1 + - @backstage/plugin-search-backend@1.4.5-next.1 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.8-next.1 + - @backstage/plugin-search-backend-module-pg@0.5.14-next.1 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.37-next.1 + - @backstage/plugin-techdocs-backend@1.7.2-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.2-next.1 + - @backstage/plugin-events-node@0.2.14-next.1 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-search-common@1.2.6 + +## example-backend-next@0.0.16-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-backend@1.14.0-next.1 + - @backstage/plugin-scaffolder-backend@1.18.0-next.1 + - @backstage/plugin-badges-backend@0.3.2-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-lighthouse-backend@0.3.2-next.1 + - @backstage/plugin-linguist-backend@0.5.2-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.9-next.1 + - @backstage/plugin-search-backend-module-explore@0.1.9-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.9-next.1 + - @backstage/plugin-search-backend-node@1.2.9-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.2-next.1 + - @backstage/plugin-kubernetes-backend@0.12.2-next.1 + - @backstage/plugin-todo-backend@0.3.3-next.1 + - @backstage/backend-defaults@0.2.5-next.1 + - @backstage/plugin-adr-backend@0.4.2-next.1 + - @backstage/plugin-app-backend@0.3.53-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/plugin-azure-devops-backend@0.4.2-next.1 + - @backstage/plugin-devtools-backend@0.2.2-next.1 + - @backstage/plugin-entity-feedback-backend@0.2.2-next.1 + - @backstage/plugin-permission-backend@0.5.28-next.1 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.2-next.1 + - @backstage/plugin-permission-node@0.7.16-next.1 + - @backstage/plugin-playlist-backend@0.3.9-next.1 + - @backstage/plugin-proxy-backend@0.4.2-next.1 + - @backstage/plugin-search-backend@1.4.5-next.1 + - @backstage/plugin-sonarqube-backend@0.2.7-next.1 + - @backstage/plugin-techdocs-backend@1.7.2-next.1 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.2-next.1 + - @backstage/plugin-permission-common@0.7.8 + +## @backstage/backend-plugin-manager@0.0.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-backend@1.14.0-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-search-backend-node@1.2.9-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/plugin-events-backend@0.2.14-next.1 + - @backstage/plugin-permission-node@0.7.16-next.1 + - @backstage/plugin-scaffolder-node@0.2.5-next.1 + - @backstage/config@1.1.0 + - @backstage/cli-common@0.1.13-next.0 + - @backstage/cli-node@0.1.5-next.0 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.2.14-next.1 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-search-common@1.2.6 + +## e2e-test@0.2.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.6-next.1 + - @backstage/cli-common@0.1.13-next.0 + - @backstage/errors@1.2.2 + +## techdocs-cli-embedded-app@0.2.87-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.14.0-next.1 + - @backstage/plugin-techdocs@1.7.1-next.1 + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-app-api@1.10.1-next.1 + - @backstage/app-defaults@1.4.4-next.1 + - @backstage/test-utils@1.4.4-next.1 + - @backstage/cli@0.23.0-next.1 + - @backstage/integration-react@1.1.20-next.1 + - @backstage/plugin-techdocs-react@1.1.12-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## @internal/plugin-todo-list@1.0.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/theme@0.4.2 + +## @internal/plugin-todo-list-backend@1.0.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 diff --git a/microsite/blog/2023-09-29-chicago-traiding-company-adopter-spotlight.mdx b/microsite/blog/2023-09-29-chicago-traiding-company-adopter-spotlight.mdx new file mode 100644 index 0000000000..8b4f332d54 --- /dev/null +++ b/microsite/blog/2023-09-29-chicago-traiding-company-adopter-spotlight.mdx @@ -0,0 +1,61 @@ +--- +# prettier-ignore +title: "Adopter Spotlight: How Chicago Trading Company saved 18 months of developer effort with Backstage" +author: Tiffany Cox, Spotify +--- + +![backstage header](assets/2023-09-29/header.png) + +**_TL;DR [Chicago Trading Company](https://www.chicagotrading.com/) (CTC) adopted Backstage ten months ago to help reduce onboarding frictions with their new cloud-based DevOps Kubernetes platform. Through templatization and open feedback loops, the team has conservatively saved 18 months of developer time to date with Backstage. We spoke with CTC DevOps engineer [Scott Kausler](https://github.com/scott-kausler) who shared the details of their onboarding journey, lessons learned, and insights for other Backstage adopters._** + +{/* truncate */} + +## Templates or the cluster didn't happen + +While mid-activation on a new cloud-based DevOps Kubernetes platform, Scott's team received early feedback that it was difficult to onboard teams onto this platform due to the breadth of requirements and new tools developers needed — from dependency management tools (such as Gradle, Conan, and Conda) to Docker/Kubernetes, Helm/FluxCD, and Vault. Not only were CTC developers required to learn new systems to build, package, and deploy their apps, in several cases even the code needed to be changed. There were also significant modifications required to existing tools such as Jenkins. + +Scott's team quickly recognized that this friction could lead to lower adoption and longer onboarding times to the new platform. So he started investigating solutions that would allow him to templatize these new services and create turnkey onboarding with less reference knowledge required. + +After exploring several service routes from managed to in-house/owned, CTC opted to use Backstage — already in POC for use of the [Software Catalog](https://backstage.io/docs/features/software-catalog/) — due to the [Software Templates](https://backstage.io/docs/features/software-templates/) plugin form-based input, UI/json-schema-form abilities, and its extensibility. Scott's team felt Backstage provided the most sustainable solution for growth amongst the multiple developer portal and templation options vetted and would help bridge the gap between UI-driven deployment and GitOps. + +## Early wins on documentation and onboarding + +The CTC DevOps team created a small special interest group to champion the developer portal build and quickly delved into the big issues impacting their developer experience. From there, the team began creating tasks and templates within Backstage. + +To start, Scott worked with end-user teams outside DevOps early in the process of documenting migration to the new DevOps Kubernetes platform services. When Scott wrote the onboarding documentation, he made it a point to pair with a developer on another team that would be using it. This approach provided him with a quality sounding board, great instantaneous feedback, and a sort of "beta developer" to test V1 documentation clarity., A few weeks later, another colleague on the same end-user team followed the documentation and she didn't reach out to Scott at all. + +After this early win, the team was ready for broad distribution. Partnering with the senior leadership team, Scott's team began onboarding teams to the new DevOps Kubernetes platform using the templates his team created in Backstage. At CTC, their Backstage instance is set up to automatically scan for deployments in Kubernetes; so if you're in Kubernetes, you're onboarded to Backstage. + +"Backstage made onboarding [to the new DevOps platform] not scary,"" Scott said. "Because now — all of a sudden — you have this recipe for how to do it, you don't have to jump through these hoops, the templates are there and ready for you. You choose what you want based on these templates we have available, and you're off and running on your own."" + +Scott's team monitored progress against their onboarding goals partially by how often the DevOps team was getting pinged for support and found that it has made support smoother. They can easily refer people to templates and repo standards instead of making them create something ad hoc. + +"It's really been cool seeing how that progressed. I even have a few teams that didn't talk to DevOps at all. They used a [template] and they have a service ready. We were actually pretty excited about that, because that means now we have a scalable tool able to onboard others onto our platform."" said Scott. + +Another exciting win for CTC was template additions generated outside the initial toolkit, which has eased the burden substantially for the DevOps team. They were able to create new templates to deploy against best practices such as a template for creating a brand-new Terraform module and Git repo or — Scott's favorite — ​​a template that creates a Java repository along with Jenkins jobs for CI and the Flux CD config for deployment. + +"The template builds and auto-deploys a Docker image, so if you make a change to your mainline branch, then it will automatically build a new Docker image and deploy it to a Kubernetes cluster."" Scott said. "So within basically 10 minutes of you filling out a form, you actually have something deployed out to a Kubernetes cluster."" + +This process eased flows for both end-user devs and DevOps teams overall. + +## Measuring Backstage impact at CTC + +To calculate the impact of Backstage, Scott began with reviewing template types and assigning a weighted value to each based upon their perceived workload. + +At CTC, some templates create a repo, some templates create a repo with some code, some templates even go as far as creating a repo with code and all the prerequisites to deploy to Flux and Jenkins jobs. To be conservative, the highest weight Scott assigned to a template would be saving three days of developer time. Even with that conservative estimate, the figure came out to be a savings of 18 months in developer effort since Backstage was deployed ten months ago. + +For CTC, the journey with Backstage has just begun. They're now looking to drive more Catalog adoption and determine what custom plugins they need to build to better support their workflows. + +## The power of partnership (and good docs!) + +When asked about advice he has for other Backstage adopters, Scott talked about the DevOps team's comms strategy and ensuring end-user developers had pathways to provide feedback. In addition to the focus on templates for the new services, having both a dedicated Slack channel and open-door communication with the DevOps team helped reduce onboarding friction to the DevOps Kubernetes platform. + +Outside of that, he believes the approach to documentation is paramount. "Write your documentation from the perspective of, 'Hey, you have this task assigned to you to write a template, here are the exact steps you have to follow.'"" Scott said. "Think of it as a recipe. Removing your familiarity bias will help make this tool more useful for less familiar teams."" + +Finally, don't be afraid to step outside the core use cases when it comes to the Backstage framework and finding solutions to meet your needs. + +"Backstage gives you a lot of really easy to use features right out of the box. And one of the great things about open source is you can look at the code and see exactly what the behavior is and work within that behavior. But we've also developed our own processes for custom tasks because — at the end of the day — our platform has some very custom aspects to it."" Scott said. + +Interested in more stories from Backstage adopters? Check out these recent posts from [Stash](https://backstage.io/blog/2023/07/08/stash-adopter-post) and [Expedia Group](https://backstage.io/blog/2023/08/17/expedia-proof-of-value-metrics-2). + +Want to learn more about Backstage? Join our weekly [Office Hours](https://info.backstage.spotify.com/office-hours) and bring your burning questions. diff --git a/microsite/blog/assets/2023-09-29/header.png b/microsite/blog/assets/2023-09-29/header.png new file mode 100644 index 0000000000..fbc48954c3 Binary files /dev/null and b/microsite/blog/assets/2023-09-29/header.png differ diff --git a/microsite/data/plugins/veecode-github-workflows b/microsite/data/plugins/github-workflows.yaml similarity index 92% rename from microsite/data/plugins/veecode-github-workflows rename to microsite/data/plugins/github-workflows.yaml index cd518dd8b8..de17a218b6 100644 --- a/microsite/data/plugins/veecode-github-workflows +++ b/microsite/data/plugins/github-workflows.yaml @@ -1,7 +1,7 @@ --- title: Veecode GitHub Workflows author: Veecode Platform -authorUrl: https://github.com/veecode-platform +authorUrl: https://platform.vee.codes/ category: CI/CD description: The Github Workflows plugin provides an alternative for manually triggering GitHub workflows from within your Backstage component. documentation: https://github.com/veecode-platform/platform-backstage-plugins/tree/master/plugins/github-workflows diff --git a/microsite/data/plugins/gitlab-pipelines.yaml b/microsite/data/plugins/gitlab-pipelines.yaml new file mode 100644 index 0000000000..22f42684db --- /dev/null +++ b/microsite/data/plugins/gitlab-pipelines.yaml @@ -0,0 +1,16 @@ +--- +title: Veecode Gitlab Pipelines +author: Veecode Platform +authorUrl: https://platform.vee.codes +category: CI/CD +description: The Gitlab pipelines plugin integrates GitlabCi with its backstage component in a simple way. +documentation: https://github.com/veecode-platform/platform-backstage-plugins/tree/master/plugins/gitlab-pipelines +iconUrl: https://veecode-platform.github.io/support/imgs/logo_1.svg +npmPackageName: '@veecode-platform/backstage-plugin-gitlab-pipelines' +tags: + - ci + - cd + - gitlabCi + - pipelines + - jobs +addedDate: '2023-09-27' diff --git a/microsite/data/plugins/pulumi.yaml b/microsite/data/plugins/pulumi.yaml new file mode 100644 index 0000000000..ea97bcdef3 --- /dev/null +++ b/microsite/data/plugins/pulumi.yaml @@ -0,0 +1,10 @@ +--- +title: Pulumi +author: Pulumi +authorUrl: https://www.pulumi.com +category: Infrastructure +description: View Pulumi stack information in Backstage. +documentation: https://github.com/pulumi/pulumi-backstage-plugin +iconUrl: https://www.pulumi.com/logos/brand/avatar-on-white.png +npmPackageName: '@pulumi/backstage-plugin-pulumi' +addedDate: '2023-09-27' diff --git a/microsite/docusaurus.config.js b/microsite/docusaurus.config.js index a7df33623a..1879e35e72 100644 --- a/microsite/docusaurus.config.js +++ b/microsite/docusaurus.config.js @@ -276,7 +276,7 @@ module.exports = { }, ], copyright: - '<p style="text-align:center"><a href="https://spotify.github.io/">Made with ❤️ at Spotify</a></p><p class="copyright">Copyright © 2022 Backstage Project Authors. All rights reserved. The Linux Foundation has registered trademarks and uses trademarks. For a list of trademarks of The Linux Foundation, please see our Trademark Usage page: https://www.linuxfoundation.org/trademark-usage</p>', + '<p style="text-align:center"><a href="https://spotify.github.io/">Made with ❤️ at Spotify</a></p><p class="copyright">Copyright © 2023 Backstage Project Authors. All rights reserved. The Linux Foundation has registered trademarks and uses trademarks. For a list of trademarks of The Linux Foundation, please see our Trademark Usage page: https://www.linuxfoundation.org/trademark-usage</p>', }, algolia: { apiKey: '1f0ba86672ccfc3576faa94583e5b318', diff --git a/microsite/sidebars.json b/microsite/sidebars.json index 0f4aef1373..bc394982ca 100644 --- a/microsite/sidebars.json +++ b/microsite/sidebars.json @@ -243,7 +243,6 @@ "plugins/integrating-plugin-into-software-catalog", "plugins/integrating-search-into-plugins", "plugins/composability", - "plugins/customization", "plugins/internationalization", "plugins/analytics", "plugins/feature-flags", diff --git a/microsite/src/components/contentBlock/contentBlock.tsx b/microsite/src/components/contentBlock/contentBlock.tsx index 983f684927..5c3e47fe74 100644 --- a/microsite/src/components/contentBlock/contentBlock.tsx +++ b/microsite/src/components/contentBlock/contentBlock.tsx @@ -37,7 +37,14 @@ export const ContentBlock = ({ {children && React.isValidElement(children) ? children : <p>{children}</p>} {actionButtons && ( - <div className="actionButtons"> + <div + className="actionButtons" + style={{ + display: 'grid', + gridTemplateColumns: 'repeat(auto-fill, minmax(200px, 1fr))', + gap: '15px', + }} + > {actionButtons.map(({ link, label }, index) => ( <Link key={index} diff --git a/microsite/src/pages/demos/index.tsx b/microsite/src/pages/demos/index.tsx index 1221c38a63..e3b4b7dbfd 100644 --- a/microsite/src/pages/demos/index.tsx +++ b/microsite/src/pages/demos/index.tsx @@ -175,12 +175,16 @@ const Demos = () => { <BannerSectionGrid> <ContentBlock title={<h1>{demoItem.title}</h1>} - actionButtons={[ - { - link: demoItem.actionItemLink, - label: 'WATCH NOW', - }, - ]} + actionButtons={ + demoItem.actionItemLink + ? [ + { + link: demoItem.actionItemLink, + label: 'WATCH NOW', + }, + ] + : [] + } > {demoItem.content} </ContentBlock> diff --git a/microsite/yarn.lock b/microsite/yarn.lock index b3ec70512f..27b077b8da 100644 --- a/microsite/yarn.lock +++ b/microsite/yarn.lock @@ -2604,91 +2604,92 @@ __metadata: languageName: node linkType: hard -"@swc/core-darwin-arm64@npm:1.3.84": - version: 1.3.84 - resolution: "@swc/core-darwin-arm64@npm:1.3.84" +"@swc/core-darwin-arm64@npm:1.3.90": + version: 1.3.90 + resolution: "@swc/core-darwin-arm64@npm:1.3.90" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@swc/core-darwin-x64@npm:1.3.84": - version: 1.3.84 - resolution: "@swc/core-darwin-x64@npm:1.3.84" +"@swc/core-darwin-x64@npm:1.3.90": + version: 1.3.90 + resolution: "@swc/core-darwin-x64@npm:1.3.90" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@swc/core-linux-arm-gnueabihf@npm:1.3.84": - version: 1.3.84 - resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.84" +"@swc/core-linux-arm-gnueabihf@npm:1.3.90": + version: 1.3.90 + resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.90" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@swc/core-linux-arm64-gnu@npm:1.3.84": - version: 1.3.84 - resolution: "@swc/core-linux-arm64-gnu@npm:1.3.84" +"@swc/core-linux-arm64-gnu@npm:1.3.90": + version: 1.3.90 + resolution: "@swc/core-linux-arm64-gnu@npm:1.3.90" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-arm64-musl@npm:1.3.84": - version: 1.3.84 - resolution: "@swc/core-linux-arm64-musl@npm:1.3.84" +"@swc/core-linux-arm64-musl@npm:1.3.90": + version: 1.3.90 + resolution: "@swc/core-linux-arm64-musl@npm:1.3.90" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@swc/core-linux-x64-gnu@npm:1.3.84": - version: 1.3.84 - resolution: "@swc/core-linux-x64-gnu@npm:1.3.84" +"@swc/core-linux-x64-gnu@npm:1.3.90": + version: 1.3.90 + resolution: "@swc/core-linux-x64-gnu@npm:1.3.90" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-x64-musl@npm:1.3.84": - version: 1.3.84 - resolution: "@swc/core-linux-x64-musl@npm:1.3.84" +"@swc/core-linux-x64-musl@npm:1.3.90": + version: 1.3.90 + resolution: "@swc/core-linux-x64-musl@npm:1.3.90" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@swc/core-win32-arm64-msvc@npm:1.3.84": - version: 1.3.84 - resolution: "@swc/core-win32-arm64-msvc@npm:1.3.84" +"@swc/core-win32-arm64-msvc@npm:1.3.90": + version: 1.3.90 + resolution: "@swc/core-win32-arm64-msvc@npm:1.3.90" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@swc/core-win32-ia32-msvc@npm:1.3.84": - version: 1.3.84 - resolution: "@swc/core-win32-ia32-msvc@npm:1.3.84" +"@swc/core-win32-ia32-msvc@npm:1.3.90": + version: 1.3.90 + resolution: "@swc/core-win32-ia32-msvc@npm:1.3.90" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@swc/core-win32-x64-msvc@npm:1.3.84": - version: 1.3.84 - resolution: "@swc/core-win32-x64-msvc@npm:1.3.84" +"@swc/core-win32-x64-msvc@npm:1.3.90": + version: 1.3.90 + resolution: "@swc/core-win32-x64-msvc@npm:1.3.90" conditions: os=win32 & cpu=x64 languageName: node linkType: hard "@swc/core@npm:^1.3.46": - version: 1.3.84 - resolution: "@swc/core@npm:1.3.84" + version: 1.3.90 + resolution: "@swc/core@npm:1.3.90" dependencies: - "@swc/core-darwin-arm64": 1.3.84 - "@swc/core-darwin-x64": 1.3.84 - "@swc/core-linux-arm-gnueabihf": 1.3.84 - "@swc/core-linux-arm64-gnu": 1.3.84 - "@swc/core-linux-arm64-musl": 1.3.84 - "@swc/core-linux-x64-gnu": 1.3.84 - "@swc/core-linux-x64-musl": 1.3.84 - "@swc/core-win32-arm64-msvc": 1.3.84 - "@swc/core-win32-ia32-msvc": 1.3.84 - "@swc/core-win32-x64-msvc": 1.3.84 - "@swc/types": ^0.1.4 + "@swc/core-darwin-arm64": 1.3.90 + "@swc/core-darwin-x64": 1.3.90 + "@swc/core-linux-arm-gnueabihf": 1.3.90 + "@swc/core-linux-arm64-gnu": 1.3.90 + "@swc/core-linux-arm64-musl": 1.3.90 + "@swc/core-linux-x64-gnu": 1.3.90 + "@swc/core-linux-x64-musl": 1.3.90 + "@swc/core-win32-arm64-msvc": 1.3.90 + "@swc/core-win32-ia32-msvc": 1.3.90 + "@swc/core-win32-x64-msvc": 1.3.90 + "@swc/counter": ^0.1.1 + "@swc/types": ^0.1.5 peerDependencies: "@swc/helpers": ^0.5.0 dependenciesMeta: @@ -2715,14 +2716,21 @@ __metadata: peerDependenciesMeta: "@swc/helpers": optional: true - checksum: dee45823923c29dde579ed1121c4392c937826d575c87f62399ba7a0b27cacfeb05da97b65cf49a721a50127bb1e22ca5c07defa784ec2a47fed33e3498ef1b9 + checksum: f8ced5187068dc73445c135065c6492f0ac559d0f7720c2482aa9663c87bd015f3d2abef6ee7b2f817280a5e8dd0946c59cce7e1499180644fbc948a9e3823ab languageName: node linkType: hard -"@swc/types@npm:^0.1.4": - version: 0.1.4 - resolution: "@swc/types@npm:0.1.4" - checksum: 9b09de7dca8e4b19bfb43f9e332c771855158cb761d26000807fe858447ecbc5342a6c257b26d9aa5497f7138fc58913693e2bee222e5042e0e8f57c2979ae66 +"@swc/counter@npm:^0.1.1": + version: 0.1.1 + resolution: "@swc/counter@npm:0.1.1" + checksum: bb974babd493ba01c0d4a95ab610c3fc15fbf609c08cb0342798e485f57ecc0950abbf84e07124e63c5fe610b492d9a8dd03701d3b9ef7329d9e8bf3cc44980f + languageName: node + linkType: hard + +"@swc/types@npm:^0.1.5": + version: 0.1.5 + resolution: "@swc/types@npm:0.1.5" + checksum: 6aee11f62d3d805a64848e0bd5f0e0e615f958e327a9e1260056c368d7d28764d89e38bd8005a536c9bf18afbcd303edd84099d60df34a2975d62540f61df13b languageName: node linkType: hard @@ -3137,9 +3145,9 @@ __metadata: linkType: hard "@types/webpack-env@npm:^1.18.0": - version: 1.18.1 - resolution: "@types/webpack-env@npm:1.18.1" - checksum: 3173c069763e51a96565d602af7e6dac9d772ae4aa6f26cac187cbf599a7f0b88f790b4b050b9dbdb0485daed3061b4a337863f3b8ce66f8a4e51f75ad387c6a + version: 1.18.2 + resolution: "@types/webpack-env@npm:1.18.2" + checksum: 883908ade827d35a10efc574fb6f2728a7c520d4296cf1507633ac7457204ccd697bc6c8cadac99bc5d96074a6109c658ebfde59f42ba5ba0fdfffc538892b0f languageName: node linkType: hard diff --git a/package.json b/package.json index dcdd66f7c3..7b7d962780 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "clean": "backstage-cli repo clean", "test": "backstage-cli repo test", "test:all": "backstage-cli repo test --coverage", + "test:e2e": "playwright test", "fix": "backstage-cli repo fix", "lint": "backstage-cli repo lint --since origin/master", "lint:docs": "node ./scripts/check-docs-quality", @@ -47,9 +48,10 @@ "resolutions": { "@types/react": "^17", "@types/react-dom": "^17", + "jest-haste-map@^29.4.3": "patch:jest-haste-map@npm%3A29.4.3#./.yarn/patches/jest-haste-map-npm-29.4.3-19b03fcef3.patch", "mock-fs@^5.2.0": "patch:mock-fs@npm%3A5.2.0#./.yarn/patches/mock-fs-npm-5.2.0-5103a7b507.patch" }, - "version": "1.18.0", + "version": "1.19.0-next.1", "dependencies": { "@backstage/errors": "workspace:^", "@manypkg/get-packages": "^1.1.3" @@ -58,9 +60,11 @@ "@backstage/cli": "workspace:*", "@backstage/codemods": "workspace:*", "@backstage/create-app": "workspace:*", + "@backstage/e2e-test-utils": "workspace:*", "@backstage/repo-tools": "workspace:*", "@changesets/cli": "^2.14.0", "@octokit/rest": "^19.0.3", + "@playwright/test": "^1.32.3", "@spotify/eslint-plugin": "^14.1.3", "@spotify/prettier-config": "^14.0.0", "@techdocs/cli": "workspace:*", diff --git a/packages/app-defaults/CHANGELOG.md b/packages/app-defaults/CHANGELOG.md index 84681ef715..573ef62905 100644 --- a/packages/app-defaults/CHANGELOG.md +++ b/packages/app-defaults/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/app-defaults +## 1.4.4-next.1 + +### Patch Changes + +- 1a0616fa10: Add missing resource and template app icons +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-app-api@1.10.1-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/plugin-permission-react@0.4.16-next.0 + - @backstage/theme@0.4.2 + +## 1.4.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/core-app-api@1.10.1-next.0 + - @backstage/plugin-permission-react@0.4.16-next.0 + - @backstage/theme@0.4.2 + ## 1.4.3 ### Patch Changes @@ -271,7 +294,7 @@ ### Minor Changes -- 7908d72e033: Introduce a new global config parameter, `auth.enableExperimentalRedirectFlow`. When enabled, auth will happen with an in-window redirect flow rather than through a popup window. +- 7908d72e033: Introduce a new global config parameter, `enableExperimentalRedirectFlow`. When enabled, auth will happen with an in-window redirect flow rather than through a popup window. ### Patch Changes @@ -319,7 +342,7 @@ ### Minor Changes -- 7908d72e033: Introduce a new global config parameter, `auth.enableExperimentalRedirectFlow`. When enabled, auth will happen with an in-window redirect flow rather than through a popup window. +- 7908d72e033: Introduce a new global config parameter, `enableExperimentalRedirectFlow`. When enabled, auth will happen with an in-window redirect flow rather than through a popup window. ### Patch Changes diff --git a/packages/app-defaults/package.json b/packages/app-defaults/package.json index d18ade17a1..b583443902 100644 --- a/packages/app-defaults/package.json +++ b/packages/app-defaults/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/app-defaults", "description": "Provides the default wiring of a Backstage App", - "version": "1.4.3", + "version": "1.4.4-next.1", "publishConfig": { "access": "public", "main": "dist/index.esm.js", diff --git a/packages/app-defaults/src/defaults/icons.tsx b/packages/app-defaults/src/defaults/icons.tsx index 80fa4dcf12..fbdfb14e5b 100644 --- a/packages/app-defaults/src/defaults/icons.tsx +++ b/packages/app-defaults/src/defaults/icons.tsx @@ -35,6 +35,7 @@ import MuiPeopleIcon from '@material-ui/icons/People'; import MuiPersonIcon from '@material-ui/icons/Person'; import MuiWarningIcon from '@material-ui/icons/Warning'; import MuiWorkIcon from '@material-ui/icons/Work'; +import MuiFeaturedPlayListIcon from '@material-ui/icons/FeaturedPlayList'; export const icons = { brokenImage: MuiBrokenImageIcon as IconComponent, @@ -58,6 +59,7 @@ export const icons = { 'kind:system': MuiCategoryIcon as IconComponent, 'kind:user': MuiPersonIcon as IconComponent, 'kind:resource': MuiWorkIcon as IconComponent, + 'kind:template': MuiFeaturedPlayListIcon as IconComponent, user: MuiPersonIcon as IconComponent, warning: MuiWarningIcon as IconComponent, }; diff --git a/packages/app-next-example-plugin/CHANGELOG.md b/packages/app-next-example-plugin/CHANGELOG.md index e833efee8b..22136e2b59 100644 --- a/packages/app-next-example-plugin/CHANGELOG.md +++ b/packages/app-next-example-plugin/CHANGELOG.md @@ -1,5 +1,21 @@ # app-next-example-plugin +## 0.0.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.1.1-next.1 + - @backstage/core-components@0.13.6-next.1 + +## 0.0.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.0 + - @backstage/frontend-plugin-api@0.1.1-next.0 + ## 0.0.1 ### Patch Changes diff --git a/packages/app-next-example-plugin/package.json b/packages/app-next-example-plugin/package.json index 5d86099d2a..ad797aaeb7 100644 --- a/packages/app-next-example-plugin/package.json +++ b/packages/app-next-example-plugin/package.json @@ -1,7 +1,7 @@ { "name": "app-next-example-plugin", "description": "Backstage internal example plugin", - "version": "0.0.1", + "version": "0.0.2-next.1", "publishConfig": { "access": "public", "main": "dist/index.esm.js", diff --git a/packages/app-next/CHANGELOG.md b/packages/app-next/CHANGELOG.md index f6e8142480..b9aa117f5b 100644 --- a/packages/app-next/CHANGELOG.md +++ b/packages/app-next/CHANGELOG.md @@ -1,5 +1,159 @@ # example-app-next +## 0.0.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-org@0.6.15-next.1 + - @backstage/plugin-code-coverage@0.2.18-next.1 + - @backstage/plugin-catalog@1.14.0-next.1 + - @backstage/plugin-techdocs@1.7.1-next.1 + - @backstage/plugin-home@0.5.9-next.1 + - @backstage/frontend-plugin-api@0.1.1-next.1 + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-app-api@1.10.1-next.1 + - @backstage/app-defaults@1.4.4-next.1 + - @backstage/frontend-app-api@0.2.0-next.1 + - @backstage/plugin-search@1.4.1-next.1 + - @backstage/cli@0.23.0-next.1 + - @backstage/plugin-cost-insights@0.12.14-next.1 + - @backstage/plugin-kubernetes@0.11.0-next.1 + - @backstage/plugin-adr@0.6.8-next.1 + - @backstage/plugin-explore@0.4.11-next.1 + - @backstage/plugin-search-react@1.7.1-next.1 + - @backstage/plugin-api-docs@0.9.12-next.1 + - @backstage/plugin-catalog-graph@0.2.37-next.1 + - @backstage/plugin-scaffolder@1.15.1-next.1 + - @backstage/plugin-scaffolder-react@1.5.6-next.1 + - @backstage/plugin-user-settings@0.7.11-next.1 + - app-next-example-plugin@0.0.2-next.1 + - @backstage/plugin-graphiql@0.2.55-next.1 + - @backstage/plugin-tech-radar@0.6.9-next.1 + - @backstage/integration-react@1.1.20-next.1 + - @backstage/plugin-airbrake@0.3.25-next.1 + - @backstage/plugin-apache-airflow@0.2.16-next.1 + - @backstage/plugin-azure-devops@0.3.7-next.1 + - @backstage/plugin-azure-sites@0.1.14-next.1 + - @backstage/plugin-badges@0.2.49-next.1 + - @backstage/plugin-catalog-import@0.10.1-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/plugin-catalog-unprocessed-entities@0.1.4-next.1 + - @backstage/plugin-circleci@0.3.25-next.1 + - @backstage/plugin-cloudbuild@0.3.25-next.1 + - @backstage/plugin-devtools@0.1.5-next.1 + - @backstage/plugin-dynatrace@7.0.5-next.1 + - @backstage/plugin-entity-feedback@0.2.8-next.1 + - @backstage/plugin-gcalendar@0.3.19-next.1 + - @backstage/plugin-gcp-projects@0.3.42-next.1 + - @backstage/plugin-github-actions@0.6.6-next.1 + - @backstage/plugin-gocd@0.1.31-next.1 + - @backstage/plugin-jenkins@0.8.7-next.1 + - @backstage/plugin-kafka@0.3.25-next.1 + - @backstage/plugin-lighthouse@0.4.10-next.1 + - @backstage/plugin-linguist@0.1.10-next.1 + - @backstage/plugin-microsoft-calendar@0.1.8-next.1 + - @backstage/plugin-newrelic@0.3.41-next.1 + - @backstage/plugin-newrelic-dashboard@0.2.18-next.1 + - @backstage/plugin-octopus-deploy@0.2.7-next.1 + - @backstage/plugin-pagerduty@0.6.6-next.1 + - @backstage/plugin-playlist@0.1.17-next.1 + - @backstage/plugin-puppetdb@0.1.8-next.1 + - @backstage/plugin-rollbar@0.4.25-next.1 + - @backstage/plugin-sentry@0.5.10-next.1 + - @backstage/plugin-shortcuts@0.3.15-next.1 + - @backstage/plugin-stack-overflow@0.1.21-next.1 + - @backstage/plugin-stackstorm@0.1.7-next.1 + - @backstage/plugin-tech-insights@0.3.17-next.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.1-next.1 + - @backstage/plugin-techdocs-react@1.1.12-next.1 + - @backstage/plugin-todo@0.2.28-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/plugin-permission-react@0.4.16-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.6 + +## 0.0.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-app-api@0.2.0-next.0 + - @backstage/plugin-pagerduty@0.6.6-next.0 + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/cli@0.23.0-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/plugin-catalog@1.14.0-next.0 + - @backstage/plugin-scaffolder@1.15.1-next.0 + - @backstage/plugin-tech-radar@0.6.9-next.0 + - @backstage/plugin-user-settings@0.7.11-next.0 + - @backstage/plugin-api-docs@0.9.12-next.0 + - @backstage/plugin-code-coverage@0.2.18-next.0 + - @backstage/plugin-cost-insights@0.12.14-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/frontend-plugin-api@0.1.1-next.0 + - @backstage/integration-react@1.1.20-next.0 + - @backstage/plugin-catalog-import@0.10.1-next.0 + - @backstage/plugin-github-actions@0.6.6-next.0 + - @backstage/plugin-techdocs@1.7.1-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.1-next.0 + - @backstage/plugin-adr@0.6.8-next.0 + - @backstage/plugin-airbrake@0.3.25-next.0 + - @backstage/plugin-azure-devops@0.3.7-next.0 + - @backstage/plugin-azure-sites@0.1.14-next.0 + - @backstage/plugin-badges@0.2.49-next.0 + - @backstage/plugin-catalog-graph@0.2.37-next.0 + - @backstage/plugin-circleci@0.3.25-next.0 + - @backstage/plugin-cloudbuild@0.3.25-next.0 + - @backstage/plugin-dynatrace@7.0.5-next.0 + - @backstage/plugin-entity-feedback@0.2.8-next.0 + - @backstage/plugin-explore@0.4.11-next.0 + - @backstage/plugin-gocd@0.1.31-next.0 + - @backstage/plugin-home@0.5.9-next.0 + - @backstage/plugin-jenkins@0.8.7-next.0 + - @backstage/plugin-kafka@0.3.25-next.0 + - @backstage/plugin-kubernetes@0.10.4-next.0 + - @backstage/plugin-lighthouse@0.4.10-next.0 + - @backstage/plugin-linguist@0.1.10-next.0 + - @backstage/plugin-newrelic-dashboard@0.2.18-next.0 + - @backstage/plugin-octopus-deploy@0.2.7-next.0 + - @backstage/plugin-org@0.6.15-next.0 + - @backstage/plugin-playlist@0.1.17-next.0 + - @backstage/plugin-puppetdb@0.1.8-next.0 + - @backstage/plugin-rollbar@0.4.25-next.0 + - @backstage/plugin-scaffolder-react@1.5.6-next.0 + - @backstage/plugin-search@1.4.1-next.0 + - @backstage/plugin-sentry@0.5.10-next.0 + - @backstage/plugin-tech-insights@0.3.17-next.0 + - @backstage/plugin-todo@0.2.28-next.0 + - @backstage/app-defaults@1.4.4-next.0 + - @backstage/config@1.1.0 + - @backstage/core-app-api@1.10.1-next.0 + - @backstage/plugin-apache-airflow@0.2.16-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.1.4-next.0 + - @backstage/plugin-devtools@0.1.5-next.0 + - @backstage/plugin-gcalendar@0.3.19-next.0 + - @backstage/plugin-gcp-projects@0.3.42-next.0 + - @backstage/plugin-graphiql@0.2.55-next.0 + - @backstage/plugin-microsoft-calendar@0.1.8-next.0 + - @backstage/plugin-newrelic@0.3.41-next.0 + - @backstage/plugin-permission-react@0.4.16-next.0 + - @backstage/plugin-search-react@1.7.1-next.0 + - @backstage/plugin-shortcuts@0.3.15-next.0 + - @backstage/plugin-stack-overflow@0.1.21-next.0 + - @backstage/plugin-stackstorm@0.1.7-next.0 + - @backstage/plugin-techdocs-react@1.1.12-next.0 + - app-next-example-plugin@0.0.2-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.6 + ## 0.0.1 ### Patch Changes diff --git a/packages/app-next/package.json b/packages/app-next/package.json index e374f31dd9..50ebf77ec2 100644 --- a/packages/app-next/package.json +++ b/packages/app-next/package.json @@ -1,6 +1,6 @@ { "name": "example-app-next", - "version": "0.0.1", + "version": "0.0.2-next.1", "private": true, "backstage": { "role": "frontend" @@ -24,6 +24,7 @@ "@backstage/plugin-azure-devops": "workspace:^", "@backstage/plugin-azure-sites": "workspace:^", "@backstage/plugin-badges": "workspace:^", + "@backstage/plugin-catalog": "workspace:^", "@backstage/plugin-catalog-common": "workspace:^", "@backstage/plugin-catalog-graph": "workspace:^", "@backstage/plugin-catalog-import": "workspace:^", @@ -76,7 +77,6 @@ "@backstage/plugin-todo": "workspace:^", "@backstage/plugin-user-settings": "workspace:^", "@backstage/theme": "workspace:^", - "@internal/plugin-catalog-customized": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", @@ -99,7 +99,6 @@ }, "devDependencies": { "@backstage/test-utils": "workspace:^", - "@testing-library/cypress": "^9.0.0", "@testing-library/dom": "^8.0.0", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", @@ -108,21 +107,14 @@ "@types/react": "*", "@types/react-dom": "*", "@types/zen-observable": "^0.8.0", - "cross-env": "^7.0.0", - "cypress": "^10.0.0", - "eslint-plugin-cypress": "^2.10.3", - "start-server-and-test": "^1.10.11" + "cross-env": "^7.0.0" }, "scripts": { "start": "backstage-cli package start --config ../../app-config.yaml --config app-config.yaml", "build": "backstage-cli package build", "clean": "backstage-cli package clean", "test": "backstage-cli package test", - "lint": "backstage-cli package lint", - "test:e2e": "start-server-and-test start http://localhost:3000 cy:dev", - "test:e2e:ci": "start-server-and-test start http://localhost:3000 cy:run", - "cy:dev": "cypress open", - "cy:run": "cypress run" + "lint": "backstage-cli package lint" }, "browserslist": { "production": [ diff --git a/packages/app-next/public/index.html b/packages/app-next/public/index.html index 0710a0d69d..a3c3ef19b8 100644 --- a/packages/app-next/public/index.html +++ b/packages/app-next/public/index.html @@ -8,7 +8,6 @@ name="description" content="Backstage is an open platform for building developer portals" /> - <link rel="apple-touch-icon" href="<%= publicPath %>/logo192.png" /> <!-- manifest.json provides metadata used when your web app is installed on a user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/ diff --git a/packages/app-next/src/App.tsx b/packages/app-next/src/App.tsx index aa9bb985c2..d844939cf2 100644 --- a/packages/app-next/src/App.tsx +++ b/packages/app-next/src/App.tsx @@ -17,6 +17,7 @@ import { createApp } from '@backstage/frontend-app-api'; import { pagesPlugin } from './examples/pagesPlugin'; import graphiqlPlugin from '@backstage/plugin-graphiql/alpha'; +import techRadarPlugin from '@backstage/plugin-tech-radar/alpha'; /* @@ -48,7 +49,7 @@ TODO: /* app.tsx */ const app = createApp({ - plugins: [graphiqlPlugin, pagesPlugin], + plugins: [graphiqlPlugin, pagesPlugin, techRadarPlugin], // bindRoutes({ bind }) { // bind(catalogPlugin.externalRoutes, { // createComponent: scaffolderPlugin.routes.root, diff --git a/packages/app-next/src/examples/pagesPlugin.tsx b/packages/app-next/src/examples/pagesPlugin.tsx index c805442305..290c6b118e 100644 --- a/packages/app-next/src/examples/pagesPlugin.tsx +++ b/packages/app-next/src/examples/pagesPlugin.tsx @@ -48,6 +48,9 @@ const IndexPage = createPageExtension({ <div> <Link to="/graphiql">GraphiQL</Link> </div> + <div> + <Link to="/search">Search</Link> + </div> </div> ); }; diff --git a/packages/app/CHANGELOG.md b/packages/app/CHANGELOG.md index 9d232123db..7b14d026a0 100644 --- a/packages/app/CHANGELOG.md +++ b/packages/app/CHANGELOG.md @@ -1,5 +1,157 @@ # example-app +## 0.2.88-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-org@0.6.15-next.1 + - @backstage/plugin-code-coverage@0.2.18-next.1 + - @backstage/plugin-catalog@1.14.0-next.1 + - @backstage/plugin-techdocs@1.7.1-next.1 + - @backstage/plugin-home@0.5.9-next.1 + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-app-api@1.10.1-next.1 + - @backstage/app-defaults@1.4.4-next.1 + - @backstage/frontend-app-api@0.2.0-next.1 + - @backstage/plugin-search@1.4.1-next.1 + - @backstage/cli@0.23.0-next.1 + - @backstage/plugin-cost-insights@0.12.14-next.1 + - @backstage/plugin-kubernetes@0.11.0-next.1 + - @backstage/plugin-adr@0.6.8-next.1 + - @backstage/plugin-explore@0.4.11-next.1 + - @backstage/plugin-search-react@1.7.1-next.1 + - @backstage/plugin-api-docs@0.9.12-next.1 + - @backstage/plugin-catalog-graph@0.2.37-next.1 + - @backstage/plugin-scaffolder@1.15.1-next.1 + - @backstage/plugin-scaffolder-react@1.5.6-next.1 + - @backstage/plugin-user-settings@0.7.11-next.1 + - @backstage/plugin-graphiql@0.2.55-next.1 + - @backstage/plugin-tech-radar@0.6.9-next.1 + - @backstage/integration-react@1.1.20-next.1 + - @backstage/plugin-airbrake@0.3.25-next.1 + - @backstage/plugin-apache-airflow@0.2.16-next.1 + - @backstage/plugin-azure-devops@0.3.7-next.1 + - @backstage/plugin-azure-sites@0.1.14-next.1 + - @backstage/plugin-badges@0.2.49-next.1 + - @backstage/plugin-catalog-import@0.10.1-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/plugin-catalog-unprocessed-entities@0.1.4-next.1 + - @backstage/plugin-circleci@0.3.25-next.1 + - @backstage/plugin-cloudbuild@0.3.25-next.1 + - @backstage/plugin-devtools@0.1.5-next.1 + - @backstage/plugin-dynatrace@7.0.5-next.1 + - @backstage/plugin-entity-feedback@0.2.8-next.1 + - @backstage/plugin-gcalendar@0.3.19-next.1 + - @backstage/plugin-gcp-projects@0.3.42-next.1 + - @backstage/plugin-github-actions@0.6.6-next.1 + - @backstage/plugin-gocd@0.1.31-next.1 + - @backstage/plugin-jenkins@0.8.7-next.1 + - @backstage/plugin-kafka@0.3.25-next.1 + - @backstage/plugin-lighthouse@0.4.10-next.1 + - @backstage/plugin-linguist@0.1.10-next.1 + - @backstage/plugin-microsoft-calendar@0.1.8-next.1 + - @backstage/plugin-newrelic@0.3.41-next.1 + - @backstage/plugin-newrelic-dashboard@0.2.18-next.1 + - @backstage/plugin-nomad@0.1.6-next.1 + - @backstage/plugin-octopus-deploy@0.2.7-next.1 + - @backstage/plugin-pagerduty@0.6.6-next.1 + - @backstage/plugin-playlist@0.1.17-next.1 + - @backstage/plugin-puppetdb@0.1.8-next.1 + - @backstage/plugin-rollbar@0.4.25-next.1 + - @backstage/plugin-sentry@0.5.10-next.1 + - @backstage/plugin-shortcuts@0.3.15-next.1 + - @backstage/plugin-stack-overflow@0.1.21-next.1 + - @backstage/plugin-stackstorm@0.1.7-next.1 + - @backstage/plugin-tech-insights@0.3.17-next.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.1-next.1 + - @backstage/plugin-techdocs-react@1.1.12-next.1 + - @backstage/plugin-todo@0.2.28-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/plugin-permission-react@0.4.16-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.6 + +## 0.2.88-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-app-api@0.2.0-next.0 + - @backstage/plugin-pagerduty@0.6.6-next.0 + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/cli@0.23.0-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/plugin-catalog@1.14.0-next.0 + - @backstage/plugin-scaffolder@1.15.1-next.0 + - @backstage/plugin-tech-radar@0.6.9-next.0 + - @backstage/plugin-user-settings@0.7.11-next.0 + - @backstage/plugin-api-docs@0.9.12-next.0 + - @backstage/plugin-code-coverage@0.2.18-next.0 + - @backstage/plugin-cost-insights@0.12.14-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/integration-react@1.1.20-next.0 + - @backstage/plugin-catalog-import@0.10.1-next.0 + - @backstage/plugin-github-actions@0.6.6-next.0 + - @backstage/plugin-techdocs@1.7.1-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.1-next.0 + - @backstage/plugin-adr@0.6.8-next.0 + - @backstage/plugin-airbrake@0.3.25-next.0 + - @backstage/plugin-azure-devops@0.3.7-next.0 + - @backstage/plugin-azure-sites@0.1.14-next.0 + - @backstage/plugin-badges@0.2.49-next.0 + - @backstage/plugin-catalog-graph@0.2.37-next.0 + - @backstage/plugin-circleci@0.3.25-next.0 + - @backstage/plugin-cloudbuild@0.3.25-next.0 + - @backstage/plugin-dynatrace@7.0.5-next.0 + - @backstage/plugin-entity-feedback@0.2.8-next.0 + - @backstage/plugin-explore@0.4.11-next.0 + - @backstage/plugin-gocd@0.1.31-next.0 + - @backstage/plugin-home@0.5.9-next.0 + - @backstage/plugin-jenkins@0.8.7-next.0 + - @backstage/plugin-kafka@0.3.25-next.0 + - @backstage/plugin-kubernetes@0.10.4-next.0 + - @backstage/plugin-lighthouse@0.4.10-next.0 + - @backstage/plugin-linguist@0.1.10-next.0 + - @backstage/plugin-newrelic-dashboard@0.2.18-next.0 + - @backstage/plugin-nomad@0.1.6-next.0 + - @backstage/plugin-octopus-deploy@0.2.7-next.0 + - @backstage/plugin-org@0.6.15-next.0 + - @backstage/plugin-playlist@0.1.17-next.0 + - @backstage/plugin-puppetdb@0.1.8-next.0 + - @backstage/plugin-rollbar@0.4.25-next.0 + - @backstage/plugin-scaffolder-react@1.5.6-next.0 + - @backstage/plugin-search@1.4.1-next.0 + - @backstage/plugin-sentry@0.5.10-next.0 + - @backstage/plugin-tech-insights@0.3.17-next.0 + - @backstage/plugin-todo@0.2.28-next.0 + - @backstage/app-defaults@1.4.4-next.0 + - @backstage/config@1.1.0 + - @backstage/core-app-api@1.10.1-next.0 + - @backstage/plugin-apache-airflow@0.2.16-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.1.4-next.0 + - @backstage/plugin-devtools@0.1.5-next.0 + - @backstage/plugin-gcalendar@0.3.19-next.0 + - @backstage/plugin-gcp-projects@0.3.42-next.0 + - @backstage/plugin-graphiql@0.2.55-next.0 + - @backstage/plugin-microsoft-calendar@0.1.8-next.0 + - @backstage/plugin-newrelic@0.3.41-next.0 + - @backstage/plugin-permission-react@0.4.16-next.0 + - @backstage/plugin-search-react@1.7.1-next.0 + - @backstage/plugin-shortcuts@0.3.15-next.0 + - @backstage/plugin-stack-overflow@0.1.21-next.0 + - @backstage/plugin-stackstorm@0.1.7-next.0 + - @backstage/plugin-techdocs-react@1.1.12-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.6 + ## 0.2.87 ### Patch Changes diff --git a/packages/app/cypress.json b/packages/app/cypress.json deleted file mode 100644 index 6ae01d9c2a..0000000000 --- a/packages/app/cypress.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "baseUrl": "http://localhost:3000", - "fixturesFolder": false, - "pluginsFile": false -} diff --git a/packages/app/cypress/.eslintrc.json b/packages/app/cypress/.eslintrc.json deleted file mode 100644 index b903ff250a..0000000000 --- a/packages/app/cypress/.eslintrc.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "plugins": ["cypress"], - "extends": ["plugin:cypress/recommended"], - "rules": { - "jest/expect-expect": [ - "error", - { - "assertFunctionNames": ["expect", "cy.contains", "cy.**.should"] - } - ] - } -} diff --git a/packages/app/cypress/integration/app.js b/packages/app/cypress/integration/app.js deleted file mode 100644 index 6371bcc4f8..0000000000 --- a/packages/app/cypress/integration/app.js +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -describe('App', () => { - it('should render the welcome page', () => { - cy.visit('/'); - cy.contains('Welcome to Backstage'); - cy.contains('Getting Started'); - cy.contains('Quick Links'); - cy.contains('APIs'); - }); - - it('should display support info when clicking the button', () => { - cy.visit('/'); - // eslint-disable-next-line testing-library/await-async-query - cy.findByTestId('support-button').click({ force: true }); - cy.contains('#backstage'); - }); - - it('should display error message when triggering it', () => { - cy.visit('/'); - // eslint-disable-next-line testing-library/await-async-query - cy.findByTestId('error-button').click({ force: true }); - cy.contains('Error: Oh no!'); - // eslint-disable-next-line testing-library/await-async-query - cy.findByTestId('error-button-close').click({ force: true }); - }); - - it('should be able to login and logout', () => { - const name = 'test-name'; - Cypress.on('window:before:load', win => { - win.fetch = cy.stub().resolves({ - status: 200, - json: () => ({ username: 'test name', token: 'token', name }), - }); - }); - - cy.visit('/'); - cy.get('a[href="/login"]').click({ force: true }); - cy.url().should('include', '/login'); - cy.contains('Welcome, guest!'); - cy.contains('Username') - .get('input[name=github-username-tf]') - .type(name, { force: true }); - cy.contains('Token') - .get('input[name=github-auth-tf]') - .type('password', { force: true }); - // eslint-disable-next-line testing-library/await-async-query - cy.findByTestId('github-auth-button').click({ force: true }); - cy.contains(`Welcome, ${name}!`); - cy.contains('Logout').click({ force: true }); - cy.contains('Welcome, guest!'); - }); -}); diff --git a/packages/app/cypress/integration/components/search/SearchPage.js b/packages/app/cypress/integration/components/search/SearchPage.js deleted file mode 100644 index 11f31cfed3..0000000000 --- a/packages/app/cypress/integration/components/search/SearchPage.js +++ /dev/null @@ -1,121 +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. - */ - -const API_ENDPOINT = 'http://localhost:7007/api/search/query'; - -describe('SearchPage', () => { - describe('Given a search context with a term, results, and filter values', () => { - it('The results are rendered as expected', () => { - const results = [ - { - type: 'software-catalog', - document: { - title: 'backstage', - text: 'Backstage system documentation', - location: '/result/location/path', - }, - }, - ]; - - cy.enterAsGuest(); - cy.visit('/search-next', { - onBeforeLoad(win) { - cy.stub(win, 'fetch') - .withArgs(`${API_ENDPOINT}?term=`) - .resolves({ - ok: true, - json: () => ({ results }), - }); - }, - }); - cy.contains('Search'); - - cy.contains(results[0].document.title); - cy.contains(results[0].document.text); - cy.get(`a[href="${results[0].document.location}"]`).should('be.visible'); - }); - - it('The filters are rendered as expected', () => { - cy.enterAsGuest(); - cy.visit( - '/search-next?filters%5Bkind%5D=Component&filters%5Blifecycle%5D%5B%5D=experimental', - { - onBeforeLoad(win) { - cy.stub(win, 'fetch') - .withArgs( - `${API_ENDPOINT}?term=&filters%5Bkind%5D=Component&filters%5Blifecycle%5D%5B0%5D=experimental`, - ) - .resolves({ - ok: true, - json: () => ({ results: [] }), - }); - }, - }, - ); - cy.contains('Search'); - - // lifecycle - cy.contains('lifecycle'); - - cy.contains('experimental'); - cy.get( - '[data-testid="search-checkboxfilter-next"] input[value="experimental"]', - ).should('have.attr', 'checked'); - - cy.contains('production'); - cy.get( - '[data-testid="search-checkboxfilter-next"] input[value="production"]', - ).should('not.have.attr', 'checked'); - - // kind - cy.contains('kind'); - cy.get( - '[data-testid="search-selectfilter-next"] [role="button"][aria-haspopup="listbox"]', - ).click(); - - cy.contains('All'); - cy.contains('Template'); - cy.contains('Component'); - - cy.get('[role="option"][data-value="Component"]').should( - 'have.attr', - 'aria-selected', - 'true', - ); - }); - - it('The search bar is rendered as expected', () => { - cy.enterAsGuest(); - cy.visit('/search-next?query=backstage', { - onBeforeLoad(win) { - cy.stub(win, 'fetch') - .withArgs(`${API_ENDPOINT}?term=backstage`) - .resolves({ - ok: true, - json: () => ({ results: [] }), - }); - }, - }); - cy.contains('Search'); - - cy.get('[data-testid="search-bar-next"] input').should( - 'have.attr', - 'value', - 'backstage', - ); - }); - }); -}); diff --git a/packages/app/cypress/support/index.js b/packages/app/cypress/support/index.js deleted file mode 100644 index fb62f6359f..0000000000 --- a/packages/app/cypress/support/index.js +++ /dev/null @@ -1,17 +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 '@testing-library/cypress/add-commands'; -import './commands'; diff --git a/packages/app/e2e-tests/SearchPage.test.ts b/packages/app/e2e-tests/SearchPage.test.ts new file mode 100644 index 0000000000..9c42cf3d0a --- /dev/null +++ b/packages/app/e2e-tests/SearchPage.test.ts @@ -0,0 +1,46 @@ +/* + * 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 { test, expect } from '@playwright/test'; + +test('the results are rendered as expected', async ({ page }) => { + await page.goto('/'); + + const enterButton = page.getByRole('button', { name: 'Enter' }); + await expect(enterButton).toBeVisible(); + await enterButton.click(); + + await page.goto('/search'); + await page.route(`http://*/api/search/query?term=*`, async route => { + const results = [ + { + type: 'software-catalog', + document: { + title: 'backstage', + text: 'Backstage system documentation', + location: '/result/location/path', + }, + }, + ]; + await route.fulfill({ json: { results } }); + }); + + await expect( + page.getByPlaceholder('Search in Backstage Example App'), + ).toBeVisible(); + + await expect(page.getByText('Backstage system documentation')).toBeVisible(); +}); diff --git a/cypress/src/integration/user/logout.spec.ts b/packages/app/e2e-tests/app.test.ts similarity index 52% rename from cypress/src/integration/user/logout.spec.ts rename to packages/app/e2e-tests/app.test.ts index a3aea9d6a8..7449e4d9cb 100644 --- a/cypress/src/integration/user/logout.spec.ts +++ b/packages/app/e2e-tests/app.test.ts @@ -13,23 +13,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/// <reference types="cypress" /> -import 'os'; -describe('Logout', () => { - before(() => { - cy.loginAsGuest(); - }); - it('should be able to logout', () => { - cy.visit('/settings'); - cy.get('[data-testid="user-settings-menu"]').click(); - return cy - .get('[data-testid="sign-out"]') - .click() - .then(() => { - return expect( - localStorage.getItem('@backstage/core:SignInPage:provider'), - ).to.be.null; - }); - }); +import { test, expect } from '@playwright/test'; + +test('App should render the welcome page', async ({ page }) => { + await page.goto('/'); + + const enterButton = page.getByRole('button', { name: 'Enter' }); + await expect(enterButton).toBeVisible(); + await enterButton.click(); + + await expect(page.getByText('My Company Catalog')).toBeVisible(); + + const supportButton = page.getByTestId('support-button'); + await expect(supportButton).toBeVisible(); + await supportButton.click(); + + await expect(page.getByText('#backstage')).toBeVisible(); }); diff --git a/packages/app/package.json b/packages/app/package.json index 290c4211ff..6e06d2ca03 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "example-app", - "version": "0.2.87", + "version": "0.2.88-next.1", "private": true, "backstage": { "role": "frontend" @@ -29,6 +29,7 @@ "@backstage/plugin-azure-devops": "workspace:^", "@backstage/plugin-azure-sites": "workspace:^", "@backstage/plugin-badges": "workspace:^", + "@backstage/plugin-catalog": "workspace:^", "@backstage/plugin-catalog-common": "workspace:^", "@backstage/plugin-catalog-graph": "workspace:^", "@backstage/plugin-catalog-import": "workspace:^", @@ -51,6 +52,7 @@ "@backstage/plugin-jenkins": "workspace:^", "@backstage/plugin-kafka": "workspace:^", "@backstage/plugin-kubernetes": "workspace:^", + "@backstage/plugin-kubernetes-cluster": "workspace:^", "@backstage/plugin-lighthouse": "workspace:^", "@backstage/plugin-linguist": "workspace:^", "@backstage/plugin-linguist-common": "workspace:^", @@ -82,7 +84,6 @@ "@backstage/plugin-todo": "workspace:^", "@backstage/plugin-user-settings": "workspace:^", "@backstage/theme": "workspace:^", - "@internal/plugin-catalog-customized": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", @@ -103,7 +104,7 @@ }, "devDependencies": { "@backstage/test-utils": "workspace:^", - "@testing-library/cypress": "^9.0.0", + "@playwright/test": "^1.32.3", "@testing-library/dom": "^8.0.0", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", @@ -112,21 +113,14 @@ "@types/react": "*", "@types/react-dom": "*", "@types/zen-observable": "^0.8.0", - "cross-env": "^7.0.0", - "cypress": "^10.0.0", - "eslint-plugin-cypress": "^2.10.3", - "start-server-and-test": "^1.10.11" + "cross-env": "^7.0.0" }, "scripts": { "start": "backstage-cli package start", "build": "backstage-cli package build", "clean": "backstage-cli package clean", "test": "backstage-cli package test", - "lint": "backstage-cli package lint", - "test:e2e": "start-server-and-test start http://localhost:3000 cy:dev", - "test:e2e:ci": "start-server-and-test start http://localhost:3000 cy:run", - "cy:dev": "cypress open", - "cy:run": "cypress run" + "lint": "backstage-cli package lint" }, "browserslist": { "production": [ diff --git a/packages/app/public/index.html b/packages/app/public/index.html index 0710a0d69d..a3c3ef19b8 100644 --- a/packages/app/public/index.html +++ b/packages/app/public/index.html @@ -8,7 +8,6 @@ name="description" content="Backstage is an open platform for building developer portals" /> - <link rel="apple-touch-icon" href="<%= publicPath %>/logo192.png" /> <!-- manifest.json provides metadata used when your web app is installed on a user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/ diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx index 6371182221..f2b7d66b21 100644 --- a/packages/app/src/App.tsx +++ b/packages/app/src/App.tsx @@ -46,7 +46,7 @@ import { CatalogEntityPage, CatalogIndexPage, catalogPlugin, -} from '@internal/plugin-catalog-customized'; +} from '@backstage/plugin-catalog'; import { CatalogGraphPage } from '@backstage/plugin-catalog-graph'; import { @@ -61,7 +61,7 @@ import { import { orgPlugin } from '@backstage/plugin-org'; import { ExplorePage } from '@backstage/plugin-explore'; import { GcpProjectsPage } from '@backstage/plugin-gcp-projects'; -import { HomepageCompositionRoot } from '@backstage/plugin-home'; +import { HomepageCompositionRoot, VisitListener } from '@backstage/plugin-home'; import { LighthousePage } from '@backstage/plugin-lighthouse'; import { NewRelicPage } from '@backstage/plugin-newrelic'; import { NextScaffolderPage } from '@backstage/plugin-scaffolder/alpha'; @@ -330,6 +330,7 @@ export default app.createRoot( <AlertDisplay transientTimeoutMs={2500} /> <OAuthRequestDialog /> <AppRouter> + <VisitListener /> <Root extensionTree={extensionTree}>{routes}</Root> </AppRouter> </>, diff --git a/packages/app/src/components/catalog/EntityPage.test.tsx b/packages/app/src/components/catalog/EntityPage.test.tsx index f9d23247c6..68ce5fb497 100644 --- a/packages/app/src/components/catalog/EntityPage.test.tsx +++ b/packages/app/src/components/catalog/EntityPage.test.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { EntityLayout } from '@internal/plugin-catalog-customized'; +import { EntityLayout } from '@backstage/plugin-catalog'; import { EntityProvider, starredEntitiesApiRef, diff --git a/packages/app/src/components/catalog/EntityPage.tsx b/packages/app/src/components/catalog/EntityPage.tsx index 25630253d4..81af3b91e7 100644 --- a/packages/app/src/components/catalog/EntityPage.tsx +++ b/packages/app/src/components/catalog/EntityPage.tsx @@ -68,7 +68,7 @@ import { hasLabels, hasRelationWarnings, EntityRelationWarning, -} from '@internal/plugin-catalog-customized'; +} from '@backstage/plugin-catalog'; import { Direction, EntityCatalogGraphCard, @@ -103,6 +103,10 @@ import { } from '@backstage/plugin-jenkins'; import { EntityKafkaContent } from '@backstage/plugin-kafka'; import { EntityKubernetesContent } from '@backstage/plugin-kubernetes'; +import { + isKubernetesClusterAvailable, + EntityKubernetesClusterContent, +} from '@backstage/plugin-kubernetes-cluster'; import { EntityLastLighthouseAuditCard, EntityLighthouseContent, @@ -898,6 +902,13 @@ const resourcePage = ( </Grid> </Grid> </EntityLayout.Route> + <EntityLayout.Route + path="/kubernetes-cluster" + title="Kubernetes Cluster" + if={isKubernetesClusterAvailable} + > + <EntityKubernetesClusterContent /> + </EntityLayout.Route> <EntityLayout.Route path="/puppetdb" title="Puppet" diff --git a/packages/app/src/components/home/HomePage.tsx b/packages/app/src/components/home/HomePage.tsx index a8ddc0e0e2..5940b0ac6c 100644 --- a/packages/app/src/components/home/HomePage.tsx +++ b/packages/app/src/components/home/HomePage.tsx @@ -22,6 +22,8 @@ import { HomePageRandomJoke, HomePageStarredEntities, HomePageToolkit, + HomePageTopVisited, + HomePageRecentlyVisited, WelcomeTitle, } from '@backstage/plugin-home'; import { Content, Header, Page } from '@backstage/core-components'; @@ -111,6 +113,8 @@ export const homePage = ( }, ]} /> + <HomePageTopVisited /> + <HomePageRecentlyVisited /> </CustomHomepageGrid> </Content> </Page> diff --git a/packages/app/src/components/search/SearchModal.tsx b/packages/app/src/components/search/SearchModal.tsx index 6b701d394d..23aec53a58 100644 --- a/packages/app/src/components/search/SearchModal.tsx +++ b/packages/app/src/components/search/SearchModal.tsx @@ -29,7 +29,7 @@ import { useSearch, } from '@backstage/plugin-search-react'; import { TechDocsSearchResultListItem } from '@backstage/plugin-techdocs'; -import { CatalogSearchResultListItem } from '@internal/plugin-catalog-customized'; +import { CatalogSearchResultListItem } from '@backstage/plugin-catalog'; import { Box, DialogActions, diff --git a/packages/app/src/components/search/SearchPage.tsx b/packages/app/src/components/search/SearchPage.tsx index 2e577e6589..a9f54cdb49 100644 --- a/packages/app/src/components/search/SearchPage.tsx +++ b/packages/app/src/components/search/SearchPage.tsx @@ -23,7 +23,7 @@ import { useSidebarPinState, } from '@backstage/core-components'; import { useApi } from '@backstage/core-plugin-api'; -import { CatalogSearchResultListItem } from '@internal/plugin-catalog-customized'; +import { CatalogSearchResultListItem } from '@backstage/plugin-catalog'; import { catalogApiRef, CATALOG_FILTER_EXISTS, diff --git a/packages/app/src/plugins.ts b/packages/app/src/plugins.ts index a1e952a07c..36f7a86acc 100644 --- a/packages/app/src/plugins.ts +++ b/packages/app/src/plugins.ts @@ -18,3 +18,4 @@ // ideally we have an API for the context menu that permits that. export { badgesPlugin } from '@backstage/plugin-badges'; export { shortcutsPlugin } from '@backstage/plugin-shortcuts'; +export { homePlugin } from '@backstage/plugin-home'; diff --git a/packages/backend-app-api/CHANGELOG.md b/packages/backend-app-api/CHANGELOG.md index 3d7864d95c..cf24e558fd 100644 --- a/packages/backend-app-api/CHANGELOG.md +++ b/packages/backend-app-api/CHANGELOG.md @@ -1,5 +1,39 @@ # @backstage/backend-app-api +## 0.5.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/plugin-permission-node@0.7.16-next.1 + - @backstage/config@1.1.0 + - @backstage/cli-common@0.1.13-next.0 + - @backstage/cli-node@0.1.5-next.0 + - @backstage/config-loader@1.5.1-next.0 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + +## 0.5.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/config-loader@1.5.1-next.0 + - @backstage/cli-common@0.1.13-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/cli-node@0.1.5-next.0 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-node@0.7.16-next.0 + ## 0.5.3 ### Patch Changes diff --git a/packages/backend-app-api/api-report.md b/packages/backend-app-api/api-report.md index 3bddcc48d5..ecfbc1fe7d 100644 --- a/packages/backend-app-api/api-report.md +++ b/packages/backend-app-api/api-report.md @@ -10,6 +10,7 @@ import { BackendFeature } from '@backstage/backend-plugin-api'; import { CacheClient } from '@backstage/backend-common'; import { Config } from '@backstage/config'; import { CorsOptions } from 'cors'; +import { DiscoveryService } from '@backstage/backend-plugin-api'; import { ErrorRequestHandler } from 'express'; import { Express as Express_2 } from 'express'; import { Format } from 'logform'; @@ -25,7 +26,6 @@ import { LoadConfigOptionsRemote } from '@backstage/config-loader'; import { LoggerService } from '@backstage/backend-plugin-api'; import { PermissionsService } from '@backstage/backend-plugin-api'; import { PluginDatabaseManager } from '@backstage/backend-common'; -import { PluginEndpointDiscovery } from '@backstage/backend-common'; import { RemoteConfigSourceOptions } from '@backstage/config-loader'; import { RequestHandler } from 'express'; import { RequestListener } from 'http'; @@ -114,7 +114,7 @@ export interface DefaultRootHttpRouterOptions { // @public (undocumented) export const discoveryServiceFactory: () => ServiceFactory< - PluginEndpointDiscovery, + DiscoveryService, 'plugin' >; @@ -128,6 +128,20 @@ export interface ExtendedHttpServer extends http.Server { stop(): Promise<void>; } +// @public +export class HostDiscovery implements DiscoveryService { + static fromConfig( + config: Config, + options?: { + basePath?: string; + }, + ): HostDiscovery; + // (undocumented) + getBaseUrl(pluginId: string): Promise<string>; + // (undocumented) + getExternalBaseUrl(pluginId: string): Promise<string>; +} + // @public (undocumented) export interface HttpRouterFactoryOptions { getPath?(pluginId: string): string; diff --git a/packages/backend-app-api/config.d.ts b/packages/backend-app-api/config.d.ts new file mode 100644 index 0000000000..86b63b527a --- /dev/null +++ b/packages/backend-app-api/config.d.ts @@ -0,0 +1,37 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface Config { + /** Discovery options. */ + discovery?: { + /** + * Endpoints + * + * A list of target baseUrls and the associated plugins. + */ + endpoints: { + /** + * The target baseUrl to use for the plugin + * + * Can be either a string or an object with internal and external keys. + * Targets with `{{pluginId}}` or `{{ pluginId }} in the url will be replaced with the pluginId. + */ + target: string | { internal: string; external: string }; + /** Array of plugins which use the target baseUrl. */ + plugins: string[]; + }[]; + }; +} diff --git a/packages/backend-app-api/package.json b/packages/backend-app-api/package.json index 0881be4ca8..24959ff290 100644 --- a/packages/backend-app-api/package.json +++ b/packages/backend-app-api/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-app-api", "description": "Core API used by Backstage backend apps", - "version": "0.5.3", + "version": "0.5.5-next.1", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { @@ -90,8 +90,10 @@ "mock-fs": "^5.2.0", "supertest": "^6.1.3" }, + "configSchema": "config.d.ts", "files": [ "dist", + "config.d.ts", "alpha" ] } diff --git a/packages/backend-common/src/discovery/HostDiscovery.test.ts b/packages/backend-app-api/src/services/implementations/discovery/HostDiscovery.test.ts similarity index 100% rename from packages/backend-common/src/discovery/HostDiscovery.test.ts rename to packages/backend-app-api/src/services/implementations/discovery/HostDiscovery.test.ts diff --git a/packages/backend-app-api/src/services/implementations/discovery/HostDiscovery.ts b/packages/backend-app-api/src/services/implementations/discovery/HostDiscovery.ts new file mode 100644 index 0000000000..180c8706d5 --- /dev/null +++ b/packages/backend-app-api/src/services/implementations/discovery/HostDiscovery.ts @@ -0,0 +1,132 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Config } from '@backstage/config'; +import { readHttpServerOptions } from '@backstage/backend-app-api'; +import { DiscoveryService } from '@backstage/backend-plugin-api'; + +type Target = string | { internal: string; external: string }; + +/** + * HostDiscovery is a basic PluginEndpointDiscovery implementation + * that can handle plugins that are hosted in a single or multiple deployments. + * + * The deployment may be scaled horizontally, as long as the external URL + * is the same for all instances. However, internal URLs will always be + * resolved to the same host, so there won't be any balancing of internal traffic. + * + * @public + */ +export class HostDiscovery implements DiscoveryService { + /** + * Creates a new HostDiscovery discovery instance by reading + * from the `backend` config section, specifically the `.baseUrl` for + * discovering the external URL, and the `.listen` and `.https` config + * for the internal one. + * + * Can be overridden in config by providing a target and corresponding plugins in `discovery.endpoints`. + * eg. + * ```yaml + * discovery: + * endpoints: + * - target: https://internal.example.com/internal-catalog + * plugins: [catalog] + * - target: https://internal.example.com/secure/api/{{pluginId}} + * plugins: [auth, permission] + * - target: + * internal: https://internal.example.com/search + * external: https://example.com/search + * plugins: [search] + * ``` + * + * The basePath defaults to `/api`, meaning the default full internal + * path for the `catalog` plugin will be `http://localhost:7007/api/catalog`. + */ + static fromConfig(config: Config, options?: { basePath?: string }) { + const basePath = options?.basePath ?? '/api'; + const externalBaseUrl = config + .getString('backend.baseUrl') + .replace(/\/+$/, ''); + + const { + listen: { host: listenHost = '::', port: listenPort }, + } = readHttpServerOptions(config.getConfig('backend')); + const protocol = config.has('backend.https') ? 'https' : 'http'; + + // Translate bind-all to localhost, and support IPv6 + let host = listenHost; + if (host === '::' || host === '') { + // We use localhost instead of ::1, since IPv6-compatible systems should default + // to using IPv6 when they see localhost, but if the system doesn't support IPv6 + // things will still work. + host = 'localhost'; + } else if (host === '0.0.0.0') { + host = '127.0.0.1'; + } + if (host.includes(':')) { + host = `[${host}]`; + } + + const internalBaseUrl = `${protocol}://${host}:${listenPort}`; + + return new HostDiscovery( + internalBaseUrl + basePath, + externalBaseUrl + basePath, + config.getOptionalConfig('discovery'), + ); + } + + private constructor( + private readonly internalBaseUrl: string, + private readonly externalBaseUrl: string, + private readonly discoveryConfig: Config | undefined, + ) {} + + private getTargetFromConfig(pluginId: string, type: 'internal' | 'external') { + const endpoints = this.discoveryConfig?.getOptionalConfigArray('endpoints'); + + const target = endpoints + ?.find(endpoint => endpoint.getStringArray('plugins').includes(pluginId)) + ?.get<Target>('target'); + + if (!target) { + const baseUrl = + type === 'external' ? this.externalBaseUrl : this.internalBaseUrl; + + return `${baseUrl}/${encodeURIComponent(pluginId)}`; + } + + if (typeof target === 'string') { + return target.replace( + /\{\{\s*pluginId\s*\}\}/g, + encodeURIComponent(pluginId), + ); + } + + return target[type].replace( + /\{\{\s*pluginId\s*\}\}/g, + encodeURIComponent(pluginId), + ); + } + + async getBaseUrl(pluginId: string): Promise<string> { + return this.getTargetFromConfig(pluginId, 'internal'); + } + + async getExternalBaseUrl(pluginId: string): Promise<string> { + return this.getTargetFromConfig(pluginId, 'external'); + } +} diff --git a/packages/backend-app-api/src/services/implementations/discovery/discoveryServiceFactory.ts b/packages/backend-app-api/src/services/implementations/discovery/discoveryServiceFactory.ts index 6bdc4b4856..bfc5a6a489 100644 --- a/packages/backend-app-api/src/services/implementations/discovery/discoveryServiceFactory.ts +++ b/packages/backend-app-api/src/services/implementations/discovery/discoveryServiceFactory.ts @@ -14,11 +14,11 @@ * limitations under the License. */ -import { HostDiscovery } from '@backstage/backend-common'; import { coreServices, createServiceFactory, } from '@backstage/backend-plugin-api'; +import { HostDiscovery } from './HostDiscovery'; /** @public */ export const discoveryServiceFactory = createServiceFactory({ diff --git a/packages/backend-app-api/src/services/implementations/discovery/index.ts b/packages/backend-app-api/src/services/implementations/discovery/index.ts index 7b3b9816b1..ee4851271a 100644 --- a/packages/backend-app-api/src/services/implementations/discovery/index.ts +++ b/packages/backend-app-api/src/services/implementations/discovery/index.ts @@ -15,3 +15,4 @@ */ export { discoveryServiceFactory } from './discoveryServiceFactory'; +export { HostDiscovery } from './HostDiscovery'; diff --git a/packages/backend-common/CHANGELOG.md b/packages/backend-common/CHANGELOG.md index 66b9600222..05aecf893b 100644 --- a/packages/backend-common/CHANGELOG.md +++ b/packages/backend-common/CHANGELOG.md @@ -1,5 +1,39 @@ # @backstage/backend-common +## 0.19.7-next.1 + +### Patch Changes + +- b94f32271e: Added the ability to fetch git tags through the `Git` class. This is useful for scaffolder actions that want to take action based on tag versions in a cloned repository +- Updated dependencies + - @backstage/backend-dev-utils@0.1.2-next.0 + - @backstage/backend-app-api@0.5.5-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/integration-aws-node@0.1.6 + - @backstage/cli-common@0.1.13-next.0 + - @backstage/config-loader@1.5.1-next.0 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/types@1.1.1 + +## 0.19.7-next.0 + +### Patch Changes + +- 1c3d6fa2b2: The `useHotCleanup` and `useHotMemoize` helpers are now deprecated, since hot module reloads for backend are being phased out. +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/config-loader@1.5.1-next.0 + - @backstage/cli-common@0.1.13-next.0 + - @backstage/config@1.1.0 + - @backstage/integration-aws-node@0.1.6 + - @backstage/backend-app-api@0.5.5-next.0 + - @backstage/backend-dev-utils@0.1.1 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + ## 0.19.5 ### Patch Changes diff --git a/packages/backend-common/api-report.md b/packages/backend-common/api-report.md index f0fa15efb0..d6ac25326f 100644 --- a/packages/backend-common/api-report.md +++ b/packages/backend-common/api-report.md @@ -28,6 +28,7 @@ import { GiteaIntegration } from '@backstage/integration'; import { GithubCredentialsProvider } from '@backstage/integration'; import { GithubIntegration } from '@backstage/integration'; import { GitLabIntegration } from '@backstage/integration'; +import { HostDiscovery as HostDiscovery_2 } from '@backstage/backend-app-api'; import { IdentityService } from '@backstage/backend-plugin-api'; import { isChildPath } from '@backstage/cli-common'; import { Knex } from 'knex'; @@ -377,7 +378,11 @@ export class Git { }): Promise<string | undefined>; // (undocumented) deleteRemote(options: { dir: string; remote: string }): Promise<void>; - fetch(options: { dir: string; remote?: string }): Promise<void>; + fetch(options: { + dir: string; + remote?: string; + tags?: boolean; + }): Promise<void>; // (undocumented) static fromAuth: (options: { username?: string; @@ -475,18 +480,7 @@ export class GitlabUrlReader implements UrlReader { } // @public -export class HostDiscovery implements PluginEndpointDiscovery { - static fromConfig( - config: Config, - options?: { - basePath?: string; - }, - ): HostDiscovery; - // (undocumented) - getBaseUrl(pluginId: string): Promise<string>; - // (undocumented) - getExternalBaseUrl(pluginId: string): Promise<string>; -} +export const HostDiscovery: typeof HostDiscovery_2; export { isChildPath }; @@ -747,7 +741,7 @@ export type ServiceBuilder = { export function setRootLogger(newLogger: winston.Logger): void; // @public @deprecated -export const SingleHostDiscovery: typeof HostDiscovery; +export const SingleHostDiscovery: typeof HostDiscovery_2; // @public export type StatusCheck = () => Promise<any>; @@ -785,12 +779,12 @@ export type UrlReadersOptions = { factories?: ReaderFactory[]; }; -// @public +// @public @deprecated export function useHotCleanup( _module: NodeModule, cancelEffect: () => void, ): void; -// @public +// @public @deprecated export function useHotMemoize<T>(_module: NodeModule, valueFactory: () => T): T; ``` diff --git a/packages/backend-common/config.d.ts b/packages/backend-common/config.d.ts index e5b193c543..f6330d16bc 100644 --- a/packages/backend-common/config.d.ts +++ b/packages/backend-common/config.d.ts @@ -216,24 +216,4 @@ export interface Config { */ csp?: { [policyId: string]: string[] | false }; }; - - /** Discovery options. */ - discovery?: { - /** - * Endpoints - * - * A list of target baseUrls and the associated plugins. - */ - endpoints: { - /** - * The target baseUrl to use for the plugin - * - * Can be either a string or an object with internal and external keys. - * Targets with `{{pluginId}}` or `{{ pluginId }} in the url will be replaced with the pluginId. - */ - target: string | { internal: string; external: string }; - /** Array of plugins which use the target baseUrl. */ - plugins: string[]; - }[]; - }; } diff --git a/packages/backend-common/package.json b/packages/backend-common/package.json index a1487163b2..a163311128 100644 --- a/packages/backend-common/package.json +++ b/packages/backend-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-common", "description": "Common functionality library for Backstage backends", - "version": "0.19.5", + "version": "0.19.7-next.1", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { @@ -125,7 +125,6 @@ "@types/fs-extra": "^9.0.3", "@types/http-errors": "^2.0.0", "@types/minimist": "^1.2.0", - "@types/mock-fs": "^4.13.0", "@types/morgan": "^1.9.0", "@types/node-forge": "^1.3.0", "@types/pg": "^8.6.6", @@ -138,7 +137,6 @@ "aws-sdk-client-mock": "^2.0.0", "better-sqlite3": "^8.0.0", "http-errors": "^2.0.0", - "mock-fs": "^5.2.0", "msw": "^1.0.0", "mysql2": "^2.2.5", "recursive-readdir": "^2.2.2", diff --git a/packages/backend-common/src/discovery/HostDiscovery.ts b/packages/backend-common/src/discovery/HostDiscovery.ts index 89b6404143..38ac975747 100644 --- a/packages/backend-common/src/discovery/HostDiscovery.ts +++ b/packages/backend-common/src/discovery/HostDiscovery.ts @@ -14,11 +14,9 @@ * limitations under the License. */ -import { Config } from '@backstage/config'; -import { PluginEndpointDiscovery } from './types'; -import { readHttpServerOptions } from '@backstage/backend-app-api'; +import { HostDiscovery as _HostDiscovery } from '@backstage/backend-app-api'; -type Target = string | { internal: string; external: string }; +export type { DiscoveryService as PluginEndpointDiscovery } from '@backstage/backend-plugin-api'; /** * HostDiscovery is a basic PluginEndpointDiscovery implementation @@ -30,106 +28,7 @@ type Target = string | { internal: string; external: string }; * * @public */ -export class HostDiscovery implements PluginEndpointDiscovery { - /** - * Creates a new HostDiscovery discovery instance by reading - * from the `backend` config section, specifically the `.baseUrl` for - * discovering the external URL, and the `.listen` and `.https` config - * for the internal one. - * - * Can be overridden in config by providing a target and corresponding plugins in `discovery.endpoints`. - * eg. - * ```yaml - * discovery: - * endpoints: - * - target: https://internal.example.com/internal-catalog - * plugins: [catalog] - * - target: https://internal.example.com/secure/api/{{pluginId}} - * plugins: [auth, permission] - * - target: - * internal: https://internal.example.com/search - * external: https://example.com/search - * plugins: [search] - * ``` - * - * The basePath defaults to `/api`, meaning the default full internal - * path for the `catalog` plugin will be `http://localhost:7007/api/catalog`. - */ - static fromConfig(config: Config, options?: { basePath?: string }) { - const basePath = options?.basePath ?? '/api'; - const externalBaseUrl = config - .getString('backend.baseUrl') - .replace(/\/+$/, ''); - - const { - listen: { host: listenHost = '::', port: listenPort }, - } = readHttpServerOptions(config.getConfig('backend')); - const protocol = config.has('backend.https') ? 'https' : 'http'; - - // Translate bind-all to localhost, and support IPv6 - let host = listenHost; - if (host === '::' || host === '') { - // We use localhost instead of ::1, since IPv6-compatible systems should default - // to using IPv6 when they see localhost, but if the system doesn't support IPv6 - // things will still work. - host = 'localhost'; - } else if (host === '0.0.0.0') { - host = '127.0.0.1'; - } - if (host.includes(':')) { - host = `[${host}]`; - } - - const internalBaseUrl = `${protocol}://${host}:${listenPort}`; - - return new HostDiscovery( - internalBaseUrl + basePath, - externalBaseUrl + basePath, - config.getOptionalConfig('discovery'), - ); - } - - private constructor( - private readonly internalBaseUrl: string, - private readonly externalBaseUrl: string, - private readonly discoveryConfig: Config | undefined, - ) {} - - private getTargetFromConfig(pluginId: string, type: 'internal' | 'external') { - const endpoints = this.discoveryConfig?.getOptionalConfigArray('endpoints'); - - const target = endpoints - ?.find(endpoint => endpoint.getStringArray('plugins').includes(pluginId)) - ?.get<Target>('target'); - - if (!target) { - const baseUrl = - type === 'external' ? this.externalBaseUrl : this.internalBaseUrl; - - return `${baseUrl}/${encodeURIComponent(pluginId)}`; - } - - if (typeof target === 'string') { - return target.replace( - /\{\{\s*pluginId\s*\}\}/g, - encodeURIComponent(pluginId), - ); - } - - return target[type].replace( - /\{\{\s*pluginId\s*\}\}/g, - encodeURIComponent(pluginId), - ); - } - - async getBaseUrl(pluginId: string): Promise<string> { - return this.getTargetFromConfig(pluginId, 'internal'); - } - - async getExternalBaseUrl(pluginId: string): Promise<string> { - return this.getTargetFromConfig(pluginId, 'external'); - } -} +export const HostDiscovery = _HostDiscovery; /** * SingleHostDiscovery is a basic PluginEndpointDiscovery implementation @@ -142,4 +41,4 @@ export class HostDiscovery implements PluginEndpointDiscovery { * @public * @deprecated Use {@link HostDiscovery} instead */ -export const SingleHostDiscovery = HostDiscovery; +export const SingleHostDiscovery = _HostDiscovery; diff --git a/packages/backend-common/src/discovery/index.ts b/packages/backend-common/src/discovery/index.ts index 5c7f5300c0..bad721d4da 100644 --- a/packages/backend-common/src/discovery/index.ts +++ b/packages/backend-common/src/discovery/index.ts @@ -13,5 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export { HostDiscovery, SingleHostDiscovery } from './HostDiscovery'; -export type { PluginEndpointDiscovery } from './types'; +export { + HostDiscovery, + SingleHostDiscovery, + type PluginEndpointDiscovery, +} from './HostDiscovery'; diff --git a/packages/backend-common/src/hot.ts b/packages/backend-common/src/hot.ts index 7148778b8c..94ebf52307 100644 --- a/packages/backend-common/src/hot.ts +++ b/packages/backend-common/src/hot.ts @@ -47,6 +47,7 @@ function findAllAncestors(_module: NodeModule): NodeModule[] { * Useful for cleaning intervals, timers, requests etc * * @public + * @deprecated Hot module reloading is no longer supported for backends. * @example * ```ts * const intervalId = setInterval(doStuff, 1000); @@ -80,6 +81,7 @@ const CURRENT_HOT_MEMOIZE_INDEX_KEY = 'backstage.io/hmr-memoize-key'; * stateful parts of the backend, e.g. to retain a database. * * @public + * @deprecated Hot module reloading is no longer supported for backends. * @example * ```ts * const db = useHotMemoize(module, () => createDB(dbParams)); diff --git a/packages/backend-common/src/reading/AzureUrlReader.test.ts b/packages/backend-common/src/reading/AzureUrlReader.test.ts index 6b2f41a2bf..2b4bc84be7 100644 --- a/packages/backend-common/src/reading/AzureUrlReader.test.ts +++ b/packages/backend-common/src/reading/AzureUrlReader.test.ts @@ -23,12 +23,13 @@ import { AzureDevOpsCredentialLike, AzureIntegrationConfig, } from '@backstage/integration'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { + createMockDirectory, + setupRequestMockHandlers, +} from '@backstage/backend-test-utils'; import fs from 'fs-extra'; -import mockFs from 'mock-fs'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import * as os from 'os'; import path from 'path'; import { NotModifiedError } from '@backstage/errors'; import { getVoidLogger } from '../logging'; @@ -43,6 +44,8 @@ type AzureIntegrationConfigLike = Partial< const logger = getVoidLogger(); +const mockDir = createMockDirectory({ mockOsTmpDir: true }); + const treeResponseFactory = DefaultReadTreeResponseFactory.create({ config: new ConfigReader({}), }); @@ -69,18 +72,8 @@ const urlReaderFactory = (azureIntegration: AzureIntegrationConfigLike) => { ); }; -const tmpDir = os.platform() === 'win32' ? 'C:\\tmp' : '/tmp'; - describe('AzureUrlReader', () => { - beforeEach(() => { - mockFs({ - [tmpDir]: mockFs.directory(), - }); - }); - - afterEach(() => { - mockFs.restore(); - }); + beforeEach(mockDir.clear); const worker = setupServer(); setupRequestMockHandlers(worker); @@ -270,7 +263,7 @@ describe('AzureUrlReader', () => { 'https://dev.azure.com/organization/project/_git/repository', ); - const dir = await response.dir({ targetDir: tmpDir }); + const dir = await response.dir({ targetDir: mockDir.path }); await expect( fs.readFile(path.join(dir, 'mkdocs.yml'), 'utf8'), diff --git a/packages/backend-common/src/reading/BitbucketCloudUrlReader.test.ts b/packages/backend-common/src/reading/BitbucketCloudUrlReader.test.ts index c00aeba124..dc182af619 100644 --- a/packages/backend-common/src/reading/BitbucketCloudUrlReader.test.ts +++ b/packages/backend-common/src/reading/BitbucketCloudUrlReader.test.ts @@ -19,18 +19,21 @@ import { BitbucketCloudIntegration, readBitbucketCloudIntegrationConfig, } from '@backstage/integration'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { + createMockDirectory, + setupRequestMockHandlers, +} from '@backstage/backend-test-utils'; import fs from 'fs-extra'; -import mockFs from 'mock-fs'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import os from 'os'; import path from 'path'; import { NotModifiedError } from '@backstage/errors'; import { BitbucketCloudUrlReader } from './BitbucketCloudUrlReader'; import { DefaultReadTreeResponseFactory } from './tree'; import getRawBody from 'raw-body'; +const mockDir = createMockDirectory({ mockOsTmpDir: true }); + const treeResponseFactory = DefaultReadTreeResponseFactory.create({ config: new ConfigReader({}), }); @@ -49,18 +52,8 @@ const reader = new BitbucketCloudUrlReader( { treeResponseFactory }, ); -const tmpDir = os.platform() === 'win32' ? 'C:\\tmp' : '/tmp'; - describe('BitbucketCloudUrlReader', () => { - beforeEach(() => { - mockFs({ - [tmpDir]: mockFs.directory(), - }); - }); - - afterEach(() => { - mockFs.restore(); - }); + beforeEach(mockDir.clear); const worker = setupServer(); setupRequestMockHandlers(worker); @@ -316,7 +309,7 @@ describe('BitbucketCloudUrlReader', () => { 'https://bitbucket.org/backstage/mock', ); - const dir = await response.dir({ targetDir: tmpDir }); + const dir = await response.dir({ targetDir: mockDir.path }); await expect( fs.readFile(path.join(dir, 'mkdocs.yml'), 'utf8'), @@ -346,7 +339,7 @@ describe('BitbucketCloudUrlReader', () => { 'https://bitbucket.org/backstage/mock/src/master/docs', ); - const dir = await response.dir({ targetDir: tmpDir }); + const dir = await response.dir({ targetDir: mockDir.path }); await expect( fs.readFile(path.join(dir, 'index.md'), 'utf8'), diff --git a/packages/backend-common/src/reading/BitbucketServerUrlReader.test.ts b/packages/backend-common/src/reading/BitbucketServerUrlReader.test.ts index 9f231e2ba7..2870138535 100644 --- a/packages/backend-common/src/reading/BitbucketServerUrlReader.test.ts +++ b/packages/backend-common/src/reading/BitbucketServerUrlReader.test.ts @@ -19,17 +19,20 @@ import { BitbucketServerIntegration, readBitbucketServerIntegrationConfig, } from '@backstage/integration'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { + createMockDirectory, + setupRequestMockHandlers, +} from '@backstage/backend-test-utils'; import fs from 'fs-extra'; -import mockFs from 'mock-fs'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import os from 'os'; import path from 'path'; import { NotModifiedError } from '@backstage/errors'; import { BitbucketServerUrlReader } from './BitbucketServerUrlReader'; import { DefaultReadTreeResponseFactory } from './tree'; +createMockDirectory({ mockOsTmpDir: true }); + const treeResponseFactory = DefaultReadTreeResponseFactory.create({ config: new ConfigReader({}), }); @@ -46,19 +49,7 @@ const reader = new BitbucketServerUrlReader( { treeResponseFactory }, ); -const tmpDir = os.platform() === 'win32' ? 'C:\\tmp' : '/tmp'; - describe('BitbucketServerUrlReader', () => { - beforeEach(() => { - mockFs({ - [tmpDir]: mockFs.directory(), - }); - }); - - afterEach(() => { - mockFs.restore(); - }); - const worker = setupServer(); setupRequestMockHandlers(worker); diff --git a/packages/backend-common/src/reading/BitbucketUrlReader.test.ts b/packages/backend-common/src/reading/BitbucketUrlReader.test.ts index 15e007d516..4258ac9d5b 100644 --- a/packages/backend-common/src/reading/BitbucketUrlReader.test.ts +++ b/packages/backend-common/src/reading/BitbucketUrlReader.test.ts @@ -19,12 +19,13 @@ import { BitbucketIntegration, readBitbucketIntegrationConfig, } from '@backstage/integration'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { + createMockDirectory, + setupRequestMockHandlers, +} from '@backstage/backend-test-utils'; import fs from 'fs-extra'; -import mockFs from 'mock-fs'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import os from 'os'; import path from 'path'; import { NotModifiedError } from '@backstage/errors'; import { BitbucketUrlReader } from './BitbucketUrlReader'; @@ -68,6 +69,10 @@ describe('BitbucketUrlReader.factory', () => { }); describe('BitbucketUrlReader', () => { + const mockDir = createMockDirectory({ mockOsTmpDir: true }); + + beforeEach(mockDir.clear); + const treeResponseFactory = DefaultReadTreeResponseFactory.create({ config: new ConfigReader({}), }); @@ -98,18 +103,6 @@ describe('BitbucketUrlReader', () => { { treeResponseFactory }, ); - const tmpDir = os.platform() === 'win32' ? 'C:\\tmp' : '/tmp'; - - beforeEach(() => { - mockFs({ - [tmpDir]: mockFs.directory(), - }); - }); - - afterEach(() => { - mockFs.restore(); - }); - const worker = setupServer(); setupRequestMockHandlers(worker); @@ -391,7 +384,7 @@ describe('BitbucketUrlReader', () => { 'https://bitbucket.org/backstage/mock', ); - const dir = await response.dir({ targetDir: tmpDir }); + const dir = await response.dir({ targetDir: mockDir.path }); await expect( fs.readFile(path.join(dir, 'mkdocs.yml'), 'utf8'), @@ -436,7 +429,7 @@ describe('BitbucketUrlReader', () => { 'https://bitbucket.org/backstage/mock/src/master/docs', ); - const dir = await response.dir({ targetDir: tmpDir }); + const dir = await response.dir({ targetDir: mockDir.path }); await expect( fs.readFile(path.join(dir, 'index.md'), 'utf8'), diff --git a/packages/backend-common/src/reading/GerritUrlReader.test.ts b/packages/backend-common/src/reading/GerritUrlReader.test.ts index 19c67ffd56..4a3b0a5de6 100644 --- a/packages/backend-common/src/reading/GerritUrlReader.test.ts +++ b/packages/backend-common/src/reading/GerritUrlReader.test.ts @@ -14,7 +14,10 @@ * limitations under the License. */ -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { + createMockDirectory, + setupRequestMockHandlers, +} from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { NotModifiedError, NotFoundError } from '@backstage/errors'; import { @@ -24,7 +27,6 @@ import { import { JsonObject } from '@backstage/types'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import mockFs from 'mock-fs'; import fs from 'fs-extra'; import path from 'path'; import { getVoidLogger } from '../logging'; @@ -33,6 +35,8 @@ import { DefaultReadTreeResponseFactory } from './tree'; import { GerritUrlReader } from './GerritUrlReader'; import getRawBody from 'raw-body'; +const mockDir = createMockDirectory({ mockOsTmpDir: true }); + const treeResponseFactory = DefaultReadTreeResponseFactory.create({ config: new ConfigReader({}), }); @@ -89,6 +93,8 @@ describe.skip('GerritUrlReader', () => { const worker = setupServer(); setupRequestMockHandlers(worker); + beforeEach(mockDir.clear); + afterAll(() => { jest.clearAllMocks(); }); @@ -249,14 +255,13 @@ describe.skip('GerritUrlReader', () => { path.resolve(__dirname, '__fixtures__/gerrit/gerrit-master-docs.tar.gz'), ); - beforeEach(() => { - mockFs({ - '/tmp/': mockFs.directory(), - '/tmp/gerrit-clone-123abc/repo/mkdocs.yml': mkdocsContent, - '/tmp/gerrit-clone-123abc/repo/docs/first.md': mdContent, + beforeEach(async () => { + mockDir.setContent({ + 'repo/mkdocs.yml': mkdocsContent, + 'repo/docs/first.md': mdContent, }); const spy = jest.spyOn(fs, 'mkdtemp'); - spy.mockImplementation(() => '/tmp/gerrit-clone-123abc'); + spy.mockImplementation(() => mockDir.path); worker.use( rest.get( @@ -289,7 +294,6 @@ describe.skip('GerritUrlReader', () => { }); afterEach(() => { - mockFs.restore(); jest.clearAllMocks(); }); diff --git a/packages/backend-common/src/reading/GithubUrlReader.test.ts b/packages/backend-common/src/reading/GithubUrlReader.test.ts index 499f97d6ec..5e6d30f519 100644 --- a/packages/backend-common/src/reading/GithubUrlReader.test.ts +++ b/packages/backend-common/src/reading/GithubUrlReader.test.ts @@ -20,12 +20,13 @@ import { GithubIntegration, readGithubIntegrationConfig, } from '@backstage/integration'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { + createMockDirectory, + setupRequestMockHandlers, +} from '@backstage/backend-test-utils'; import fs from 'fs-extra'; -import mockFs from 'mock-fs'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import os from 'os'; import path from 'path'; import { NotFoundError, NotModifiedError } from '@backstage/errors'; import { @@ -37,6 +38,8 @@ import { } from './GithubUrlReader'; import { DefaultReadTreeResponseFactory } from './tree'; +const mockDir = createMockDirectory({ mockOsTmpDir: true }); + const treeResponseFactory = DefaultReadTreeResponseFactory.create({ config: new ConfigReader({}), }); @@ -69,21 +72,11 @@ const gheProcessor = new GithubUrlReader( { treeResponseFactory, credentialsProvider: mockCredentialsProvider }, ); -const tmpDir = os.platform() === 'win32' ? 'C:\\tmp' : '/tmp'; - describe('GithubUrlReader', () => { const worker = setupServer(); setupRequestMockHandlers(worker); - beforeEach(() => { - mockFs({ - [tmpDir]: mockFs.directory(), - }); - }); - - afterEach(() => { - mockFs.restore(); - }); + beforeEach(mockDir.clear); beforeEach(() => { jest.clearAllMocks(); @@ -420,7 +413,7 @@ describe('GithubUrlReader', () => { 'https://github.com/backstage/mock', ); - const dir = await response.dir({ targetDir: tmpDir }); + const dir = await response.dir({ targetDir: mockDir.path }); await expect( fs.readFile(path.join(dir, 'mkdocs.yml'), 'utf8'), @@ -501,7 +494,7 @@ describe('GithubUrlReader', () => { 'https://github.com/backstage/mock/tree/main/docs', ); - const dir = await response.dir({ targetDir: tmpDir }); + const dir = await response.dir({ targetDir: mockDir.path }); await expect( fs.readFile(path.join(dir, 'index.md'), 'utf8'), diff --git a/packages/backend-common/src/reading/GitlabUrlReader.test.ts b/packages/backend-common/src/reading/GitlabUrlReader.test.ts index 5af4faf7e5..3c065e8b81 100644 --- a/packages/backend-common/src/reading/GitlabUrlReader.test.ts +++ b/packages/backend-common/src/reading/GitlabUrlReader.test.ts @@ -15,12 +15,13 @@ */ import { ConfigReader } from '@backstage/config'; -import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { + createMockDirectory, + setupRequestMockHandlers, +} from '@backstage/backend-test-utils'; import fs from 'fs-extra'; -import mockFs from 'mock-fs'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; -import os from 'os'; import path from 'path'; import { getVoidLogger } from '../logging'; import { GitlabUrlReader } from './GitlabUrlReader'; @@ -33,6 +34,8 @@ import { const logger = getVoidLogger(); +const mockDir = createMockDirectory({ mockOsTmpDir: true }); + const treeResponseFactory = DefaultReadTreeResponseFactory.create({ config: new ConfigReader({}), }); @@ -65,18 +68,8 @@ const hostedGitlabProcessor = new GitlabUrlReader( { treeResponseFactory }, ); -const tmpDir = os.platform() === 'win32' ? 'C:\\tmp' : '/tmp'; - describe('GitlabUrlReader', () => { - beforeEach(() => { - mockFs({ - [tmpDir]: mockFs.directory(), - }); - }); - - afterEach(() => { - mockFs.restore(); - }); + beforeEach(mockDir.clear); const worker = setupServer(); setupRequestMockHandlers(worker); @@ -400,7 +393,7 @@ describe('GitlabUrlReader', () => { 'https://gitlab.com/backstage/mock', ); - const dir = await response.dir({ targetDir: tmpDir }); + const dir = await response.dir({ targetDir: mockDir.path }); await expect( fs.readFile(path.join(dir, 'mkdocs.yml'), 'utf8'), @@ -457,7 +450,7 @@ describe('GitlabUrlReader', () => { 'https://gitlab.com/backstage/mock/tree/main/docs', ); - const dir = await response.dir({ targetDir: tmpDir }); + const dir = await response.dir({ targetDir: mockDir.path }); await expect( fs.readFile(path.join(dir, 'index.md'), 'utf8'), diff --git a/packages/backend-common/src/reading/tree/ReadableArrayResponse.test.ts b/packages/backend-common/src/reading/tree/ReadableArrayResponse.test.ts index a5728a6169..0a27bdf09c 100644 --- a/packages/backend-common/src/reading/tree/ReadableArrayResponse.test.ts +++ b/packages/backend-common/src/reading/tree/ReadableArrayResponse.test.ts @@ -15,41 +15,54 @@ */ import fs from 'fs-extra'; -import mockFs from 'mock-fs'; -import path, { resolve as resolvePath } from 'path'; +import path from 'path'; import { FromReadableArrayOptions } from '../types'; import { ReadableArrayResponse } from './ReadableArrayResponse'; +import { createMockDirectory } from '@backstage/backend-test-utils'; -const path1 = '/file1.yaml'; +const name1 = 'file1.yaml'; const file1 = fs.readFileSync( path.resolve(__filename, '../../__fixtures__/awsS3/awsS3-mock-object.yaml'), ); -const path2 = '/file2.yaml'; +const name2 = 'file2.yaml'; const file2 = fs.readFileSync( path.resolve(__filename, '../../__fixtures__/awsS3/awsS3-mock-object2.yaml'), ); describe('ReadableArrayResponse', () => { + const sourceDir = createMockDirectory(); + const targetDir = createMockDirectory(); + beforeEach(() => { - mockFs({ - [path1]: file1, - [path2]: file2, - '/tmp': mockFs.directory(), + sourceDir.setContent({ + [name1]: file1, + [name2]: file2, }); + targetDir.clear(); }); + const openStreams = new Array<fs.ReadStream>(); + function createReadStream(filePath: string) { + const stream = fs.createReadStream(filePath); + openStreams.push(stream); + return stream; + } afterEach(() => { - mockFs.restore(); + openStreams.forEach(stream => stream.destroy()); + openStreams.length = 0; }); + const path1 = sourceDir.resolve(name1); + const path2 = sourceDir.resolve(name2); + it('should read files', async () => { const arr: FromReadableArrayOptions = [ - { data: fs.createReadStream(path1), path: path1 }, - { data: fs.createReadStream(path2), path: path2 }, + { data: createReadStream(path1), path: path1 }, + { data: createReadStream(path2), path: path2 }, ]; - const res = new ReadableArrayResponse(arr, '/tmp', 'etag'); + const res = new ReadableArrayResponse(arr, targetDir.path, 'etag'); const files = await res.files(); expect(files).toEqual([ @@ -57,26 +70,21 @@ describe('ReadableArrayResponse', () => { { path: path2, content: expect.any(Function) }, ]); const contents = await Promise.all(files.map(f => f.content())); - expect(contents.map(c => c.toString('utf8').trim())).toEqual([ - 'site_name: Test', - 'site_name: Test2', - ]); + expect(contents).toEqual([file1, file2]); }); it('should extract entire archive into directory', async () => { const arr: FromReadableArrayOptions = [ - { data: fs.createReadStream(path1), path: path1 }, - { data: fs.createReadStream(path2), path: path2 }, + { data: createReadStream(path1), path: path1 }, + { data: createReadStream(path2), path: path2 }, ]; - const res = new ReadableArrayResponse(arr, '/tmp', 'etag'); + const res = new ReadableArrayResponse(arr, targetDir.path, 'etag'); const dir = await res.dir(); - await expect( - fs.readFile(resolvePath(dir, 'file1.yaml'), 'utf8'), - ).resolves.toMatch(/site_name: Test/); - await expect( - fs.readFile(resolvePath(dir, 'file2.yaml'), 'utf8'), - ).resolves.toMatch(/site_name: Test2/); + expect(targetDir.content({ path: dir })).toEqual({ + [name1]: file1.toString('utf8'), + [name2]: file2.toString('utf8'), + }); }); }); diff --git a/packages/backend-common/src/reading/tree/TarArchiveResponse.test.ts b/packages/backend-common/src/reading/tree/TarArchiveResponse.test.ts index 1765a41156..f69fb2e0e1 100644 --- a/packages/backend-common/src/reading/tree/TarArchiveResponse.test.ts +++ b/packages/backend-common/src/reading/tree/TarArchiveResponse.test.ts @@ -15,30 +15,31 @@ */ import fs from 'fs-extra'; -import mockFs from 'mock-fs'; import { resolve as resolvePath } from 'path'; import { TarArchiveResponse } from './TarArchiveResponse'; +import { createMockDirectory } from '@backstage/backend-test-utils'; const archiveData = fs.readFileSync( resolvePath(__filename, '../../__fixtures__/mock-main.tar.gz'), ); describe('TarArchiveResponse', () => { - beforeEach(() => { - mockFs({ - '/test-archive.tar.gz': archiveData, - '/tmp': mockFs.directory(), - }); - }); + const sourceDir = createMockDirectory(); + const targetDir = createMockDirectory(); - afterEach(() => { - mockFs.restore(); + beforeAll(() => { + sourceDir.setContent({ 'test-archive.tar.gz': archiveData }); + }); + beforeEach(() => { + targetDir.clear(); }); it('should read files', async () => { - const stream = fs.createReadStream('/test-archive.tar.gz'); + const stream = fs.createReadStream( + sourceDir.resolve('test-archive.tar.gz'), + ); - const res = new TarArchiveResponse(stream, '', '/tmp', 'etag'); + const res = new TarArchiveResponse(stream, '', targetDir.path, 'etag'); const files = await res.files(); expect(files).toEqual([ @@ -61,10 +62,16 @@ describe('TarArchiveResponse', () => { }); it('should read files with filter', async () => { - const stream = fs.createReadStream('/test-archive.tar.gz'); + const stream = fs.createReadStream( + sourceDir.resolve('test-archive.tar.gz'), + ); - const res = new TarArchiveResponse(stream, '', '/tmp', 'etag', path => - path.endsWith('.yml'), + const res = new TarArchiveResponse( + stream, + '', + targetDir.path, + 'etag', + path => path.endsWith('.yml'), ); const files = await res.files(); @@ -80,16 +87,18 @@ describe('TarArchiveResponse', () => { }); it('should read as archive and files', async () => { - const stream = fs.createReadStream('/test-archive.tar.gz'); + const stream = fs.createReadStream( + sourceDir.resolve('test-archive.tar.gz'), + ); - const res = new TarArchiveResponse(stream, '', '/tmp', 'etag'); + const res = new TarArchiveResponse(stream, '', targetDir.path, 'etag'); const buffer = await res.archive(); await expect(res.archive()).rejects.toThrow( 'Response has already been read', ); - const res2 = new TarArchiveResponse(buffer, '', '/tmp', 'etag'); + const res2 = new TarArchiveResponse(buffer, '', targetDir.path, 'etag'); const files = await res2.files(); expect(files).toEqual([ @@ -112,9 +121,11 @@ describe('TarArchiveResponse', () => { }); it('should extract entire archive into directory', async () => { - const stream = fs.createReadStream('/test-archive.tar.gz'); + const stream = fs.createReadStream( + sourceDir.resolve('test-archive.tar.gz'), + ); - const res = new TarArchiveResponse(stream, '', '/tmp', 'etag'); + const res = new TarArchiveResponse(stream, '', targetDir.path, 'etag'); const dir = await res.dir(); await expect( fs.readFile(resolvePath(dir, 'mkdocs.yml'), 'utf8'), @@ -125,67 +136,91 @@ describe('TarArchiveResponse', () => { }); it('should extract archive into directory with a subpath', async () => { - const stream = fs.createReadStream('/test-archive.tar.gz'); + const stream = fs.createReadStream( + sourceDir.resolve('test-archive.tar.gz'), + ); - const res = new TarArchiveResponse(stream, 'docs', '/tmp', 'etag'); + const res = new TarArchiveResponse(stream, 'docs', targetDir.path, 'etag'); const dir = await res.dir(); - expect(dir).toMatch(/^[\/\\]tmp[\/\\].*$/); - await expect( - fs.readFile(resolvePath(dir, 'index.md'), 'utf8'), - ).resolves.toBe('# Test\n'); + expect(targetDir.content({ path: dir })).toEqual({ + 'index.md': '# Test\n', + }); }); it('should extract archive into directory with a subpath and filter', async () => { - const stream = fs.createReadStream('/test-archive.tar.gz'); - - const res = new TarArchiveResponse(stream, '', '/tmp', 'etag', path => - path.endsWith('.yml'), + const stream = fs.createReadStream( + sourceDir.resolve('test-archive.tar.gz'), ); - const dir = await res.dir({ targetDir: '/tmp' }); - expect(dir).toBe('/tmp'); - await expect(fs.pathExists(resolvePath(dir, 'mkdocs.yml'))).resolves.toBe( - true, + const res = new TarArchiveResponse( + stream, + '', + targetDir.path, + 'etag', + path => path.endsWith('.yml'), ); - await expect( - fs.pathExists(resolvePath(dir, 'docs/index.md')), - ).resolves.toBe(false); + + targetDir.addContent({ sub: {} }); + const dir = await res.dir({ targetDir: targetDir.resolve('sub') }); + + expect(dir).toBe(targetDir.resolve('sub')); + expect(targetDir.content()).toEqual({ + sub: { + 'mkdocs.yml': 'site_name: Test\n', + }, + }); }); - it('should leave temporary directories in place in the case of an error', async () => { - const stream = fs.createReadStream('/test-archive.tar.gz'); + it('should clean up temporary directories in place in the case of an error', async () => { + const stream = fs.createReadStream( + sourceDir.resolve('test-archive.tar.gz'), + ); - const res = new TarArchiveResponse(stream, '', '/tmp', 'etag', () => { - throw new Error('NOPE'); - }); + const res = new TarArchiveResponse( + stream, + '', + targetDir.path, + 'etag', + () => { + throw new Error('NOPE'); + }, + ); - const tmpDir = await fs.mkdtemp('/tmp/test'); - // selects the wrong overload by default - const mkdtemp = jest.spyOn(fs, 'mkdtemp') as unknown as jest.SpyInstance< - Promise<string>, - [] - >; - mkdtemp.mockResolvedValue(tmpDir); + targetDir.addContent({ sub: {} }); + const sub = targetDir.resolve('sub'); - await expect(fs.pathExists(tmpDir)).resolves.toBe(true); + const mkdtemp = jest + .spyOn(fs, 'mkdtemp') + .mockImplementation(async () => sub); + + await expect(fs.pathExists(sub)).resolves.toBe(true); await expect(res.dir()).rejects.toThrow('NOPE'); - await expect(fs.pathExists(tmpDir)).resolves.toBe(false); + await expect(fs.pathExists(sub)).resolves.toBe(false); mkdtemp.mockRestore(); }); it('should leave directory in place if provided in the case of an error', async () => { - const stream = fs.createReadStream('/test-archive.tar.gz'); + const stream = fs.createReadStream( + sourceDir.resolve('test-archive.tar.gz'), + ); - const res = new TarArchiveResponse(stream, '', '/tmp', 'etag', () => { - throw new Error('NOPE'); - }); + const res = new TarArchiveResponse( + stream, + '', + targetDir.path, + 'etag', + () => { + throw new Error('NOPE'); + }, + ); - const tmpDir = await fs.mkdtemp('/tmp/test'); + targetDir.addContent({ sub: {} }); + const sub = targetDir.resolve('sub'); - await expect(fs.pathExists(tmpDir)).resolves.toBe(true); - await expect(res.dir({ targetDir: tmpDir })).rejects.toThrow('NOPE'); - await expect(fs.pathExists(tmpDir)).resolves.toBe(true); + await expect(fs.pathExists(sub)).resolves.toBe(true); + await expect(res.dir({ targetDir: sub })).rejects.toThrow('NOPE'); + await expect(fs.pathExists(sub)).resolves.toBe(true); }); }); diff --git a/packages/backend-common/src/reading/tree/ZipArchiveResponse.test.ts b/packages/backend-common/src/reading/tree/ZipArchiveResponse.test.ts index 0b010565dd..ccf53e7cff 100644 --- a/packages/backend-common/src/reading/tree/ZipArchiveResponse.test.ts +++ b/packages/backend-common/src/reading/tree/ZipArchiveResponse.test.ts @@ -15,11 +15,11 @@ */ import fs from 'fs-extra'; -import mockFs from 'mock-fs'; import { Readable } from 'stream'; import { create as createArchive } from 'archiver'; import { resolve as resolvePath } from 'path'; import { ZipArchiveResponse } from './ZipArchiveResponse'; +import { createMockDirectory } from '@backstage/backend-test-utils'; const archiveData = fs.readFileSync( resolvePath(__filename, '../../__fixtures__/mock-main.zip'), @@ -35,24 +35,36 @@ const archiveWithMaliciousEntry = fs.readFileSync( ); describe('ZipArchiveResponse', () => { - beforeEach(() => { - mockFs({ - '/test-archive.zip': archiveData, - '/test-archive-with-extra-root-dir.zip': archiveDataWithExtraDir, - '/test-archive-corrupted.zip': archiveDataCorrupted, - '/test-archive-malicious.zip': archiveWithMaliciousEntry, - '/tmp': mockFs.directory(), + const sourceDir = createMockDirectory(); + const targetDir = createMockDirectory(); + + beforeAll(() => { + sourceDir.setContent({ + 'test-archive.zip': archiveData, + 'test-archive-with-extra-root-dir.zip': archiveDataWithExtraDir, + 'test-archive-corrupted.zip': archiveDataCorrupted, + 'test-archive-malicious.zip': archiveWithMaliciousEntry, }); }); + beforeEach(() => { + targetDir.clear(); + }); + const openStreams = new Array<fs.ReadStream>(); + function createReadStream(filePath: string) { + const stream = fs.createReadStream(filePath); + openStreams.push(stream); + return stream; + } afterEach(() => { - mockFs.restore(); + openStreams.forEach(stream => stream.destroy()); + openStreams.length = 0; }); it('should read files', async () => { - const stream = fs.createReadStream('/test-archive.zip'); + const stream = createReadStream(sourceDir.resolve('test-archive.zip')); - const res = new ZipArchiveResponse(stream, '', '/tmp', 'etag'); + const res = new ZipArchiveResponse(stream, '', targetDir.path, 'etag'); const files = await res.files(); expect(files).toEqual([ @@ -76,10 +88,14 @@ describe('ZipArchiveResponse', () => { }); it('should read files with filter', async () => { - const stream = fs.createReadStream('/test-archive.zip'); + const stream = createReadStream(sourceDir.resolve('test-archive.zip')); - const res = new ZipArchiveResponse(stream, '', '/tmp', 'etag', path => - path.endsWith('.yml'), + const res = new ZipArchiveResponse( + stream, + '', + targetDir.path, + 'etag', + path => path.endsWith('.yml'), ); const files = await res.files(); @@ -95,16 +111,16 @@ describe('ZipArchiveResponse', () => { }); it('should read as archive and files', async () => { - const stream = fs.createReadStream('/test-archive.zip'); + const stream = createReadStream(sourceDir.resolve('test-archive.zip')); - const res = new ZipArchiveResponse(stream, '', '/tmp', 'etag'); + const res = new ZipArchiveResponse(stream, '', targetDir.path, 'etag'); const buffer = await res.archive(); await expect(res.archive()).rejects.toThrow( 'Response has already been read', ); - const res2 = new ZipArchiveResponse(buffer, '', '/tmp', 'etag'); + const res2 = new ZipArchiveResponse(buffer, '', targetDir.path, 'etag'); const files = await res2.files(); expect(files).toEqual([ @@ -127,9 +143,9 @@ describe('ZipArchiveResponse', () => { }); it('should extract entire archive into directory', async () => { - const stream = fs.createReadStream('/test-archive.zip'); + const stream = createReadStream(sourceDir.resolve('test-archive.zip')); - const res = new ZipArchiveResponse(stream, '', '/tmp', 'etag'); + const res = new ZipArchiveResponse(stream, '', targetDir.path, 'etag'); const dir = await res.dir(); await expect( @@ -141,38 +157,45 @@ describe('ZipArchiveResponse', () => { }); it('should extract archive into directory with a subpath', async () => { - const stream = fs.createReadStream('/test-archive.zip'); + const stream = createReadStream(sourceDir.resolve('test-archive.zip')); + + const res = new ZipArchiveResponse(stream, 'docs/', targetDir.path, 'etag'); - const res = new ZipArchiveResponse(stream, 'docs/', '/tmp', 'etag'); const dir = await res.dir(); - expect(dir).toMatch(/^[\/\\]tmp[\/\\].*$/); - await expect( - fs.readFile(resolvePath(dir, 'index.md'), 'utf8'), - ).resolves.toBe('# Test\n'); + expect(targetDir.content({ path: dir })).toEqual({ + 'index.md': '# Test\n', + }); }); it('should extract archive into directory with a subpath and filter', async () => { - const stream = fs.createReadStream('/test-archive.zip'); + const stream = createReadStream(sourceDir.resolve('test-archive.zip')); - const res = new ZipArchiveResponse(stream, '', '/tmp', 'etag', path => - path.endsWith('.yml'), + const res = new ZipArchiveResponse( + stream, + '', + targetDir.path, + 'etag', + path => path.endsWith('.yml'), ); - const dir = await res.dir({ targetDir: '/tmp' }); - expect(dir).toBe('/tmp'); - await expect(fs.pathExists(resolvePath(dir, 'mkdocs.yml'))).resolves.toBe( - true, - ); - await expect( - fs.pathExists(resolvePath(dir, 'docs/index.md')), - ).resolves.toBe(false); + targetDir.addContent({ sub: {} }); + const sub = targetDir.resolve('sub'); + const dir = await res.dir({ targetDir: sub }); + + expect(dir).toBe(sub); + + expect(targetDir.content()).toEqual({ + sub: { + 'mkdocs.yml': 'site_name: Test\n', + }, + }); }); it('should extract a large archive', async () => { const fileCount = 10; const fileSize = 1000 * 1000; const filePath = await new Promise<string>((resolve, reject) => { - const outFile = '/large-archive.zip'; + const outFile = targetDir.resolve('large-archive.zip'); const archive = createArchive('zip'); archive.on('error', reject); @@ -193,14 +216,16 @@ describe('ZipArchiveResponse', () => { archive.finalize(); }); - const stream = fs.createReadStream(filePath); + const stream = createReadStream(filePath); - const res = new ZipArchiveResponse(stream, '', '/tmp', 'etag'); + const res = new ZipArchiveResponse(stream, '', targetDir.path, 'etag'); + + targetDir.addContent({ sub: {} }); + const sub = targetDir.resolve('sub'); const dir = await res.dir({ - targetDir: '/out', + targetDir: sub, }); - expect(dir).toBe('/out'); const files = await fs.readdir(dir); expect(files).toHaveLength(fileCount); @@ -211,9 +236,11 @@ describe('ZipArchiveResponse', () => { }); it('should throw on invalid archive', async () => { - const stream = fs.createReadStream('/test-archive-corrupted.zip'); + const stream = createReadStream( + sourceDir.resolve('test-archive-corrupted.zip'), + ); - const res = new ZipArchiveResponse(stream, '', '/tmp', 'etag'); + const res = new ZipArchiveResponse(stream, '', targetDir.path, 'etag'); const filesPromise = res.files(); await expect(filesPromise).rejects.toThrow( @@ -222,18 +249,22 @@ describe('ZipArchiveResponse', () => { }); it('should throw on entries with a path outside the destination dir', async () => { - const stream = fs.createReadStream('/test-archive-malicious.zip'); + const stream = createReadStream( + sourceDir.resolve('test-archive-malicious.zip'), + ); - const res = new ZipArchiveResponse(stream, '', '/tmp', 'etag'); + const res = new ZipArchiveResponse(stream, '', targetDir.path, 'etag'); await expect(res.files()).rejects.toThrow( 'invalid relative path: ../side.txt', ); }); it('should throw on entries that attempt to write outside destination dir', async () => { - const stream = fs.createReadStream('/test-archive-malicious.zip'); + const stream = createReadStream( + sourceDir.resolve('test-archive-malicious.zip'), + ); - const res = new ZipArchiveResponse(stream, '', '/tmp', 'etag'); + const res = new ZipArchiveResponse(stream, '', targetDir.path, 'etag'); await expect(res.dir()).rejects.toThrow( 'invalid relative path: ../side.txt', ); diff --git a/packages/backend-common/src/reading/tree/ZipArchiveResponse.ts b/packages/backend-common/src/reading/tree/ZipArchiveResponse.ts index 1e55150310..a191163517 100644 --- a/packages/backend-common/src/reading/tree/ZipArchiveResponse.ts +++ b/packages/backend-common/src/reading/tree/ZipArchiveResponse.ts @@ -93,9 +93,13 @@ export class ZipArchiveResponse implements ReadTreeResponse { return new Promise((resolve, reject) => { writeStream.on('error', reject); - writeStream.on('finish', () => - resolve({ fileName: tmpFile, cleanup: () => fs.remove(tmpFile) }), - ); + writeStream.on('finish', () => { + writeStream.end(); + resolve({ + fileName: tmpFile, + cleanup: () => fs.rm(tmpDir, { recursive: true }), + }); + }); stream.pipe(writeStream); }); } @@ -152,7 +156,7 @@ export class ZipArchiveResponse implements ReadTreeResponse { }); }); - temporary.cleanup(); + await temporary.cleanup(); return files; } @@ -175,7 +179,7 @@ export class ZipArchiveResponse implements ReadTreeResponse { archive.finalize(); - temporary.cleanup(); + await temporary.cleanup(); return archive; } @@ -204,7 +208,7 @@ export class ZipArchiveResponse implements ReadTreeResponse { }); }); - temporary.cleanup(); + await temporary.cleanup(); return dir; } diff --git a/packages/backend-common/src/scm/git.test.ts b/packages/backend-common/src/scm/git.test.ts index 629173f96e..5ec960fc53 100644 --- a/packages/backend-common/src/scm/git.test.ts +++ b/packages/backend-common/src/scm/git.test.ts @@ -264,13 +264,14 @@ describe('Git', () => { }; const git = Git.fromAuth(auth); - await git.fetch({ remote, dir }); + await git.fetch({ remote, dir, tags: true }); expect(isomorphic.fetch).toHaveBeenCalledWith({ fs, http, remote, dir, + tags: true, onProgress: expect.any(Function), headers: { 'user-agent': 'git/@isomorphic-git', @@ -294,6 +295,7 @@ describe('Git', () => { http, remote, dir, + tags: false, onProgress: expect.any(Function), headers: { Authorization: 'Bearer test', diff --git a/packages/backend-common/src/scm/git.ts b/packages/backend-common/src/scm/git.ts index 234ae57d30..8ccdbeafbd 100644 --- a/packages/backend-common/src/scm/git.ts +++ b/packages/backend-common/src/scm/git.ts @@ -160,8 +160,12 @@ export class Git { } /** https://isomorphic-git.org/docs/en/fetch */ - async fetch(options: { dir: string; remote?: string }): Promise<void> { - const { dir, remote = 'origin' } = options; + async fetch(options: { + dir: string; + remote?: string; + tags?: boolean; + }): Promise<void> { + const { dir, remote = 'origin', tags = false } = options; this.config.logger?.info( `Fetching remote=${remote} for repository {dir=${dir}}`, ); @@ -172,6 +176,7 @@ export class Git { http, dir, remote, + tags, onProgress: this.onProgressHandler(), headers: this.headers, onAuth: this.onAuth, diff --git a/packages/backend-common/src/util/DockerContainerRunner.test.ts b/packages/backend-common/src/util/DockerContainerRunner.test.ts index 3208679d1f..737bf3d178 100644 --- a/packages/backend-common/src/util/DockerContainerRunner.test.ts +++ b/packages/backend-common/src/util/DockerContainerRunner.test.ts @@ -14,27 +14,24 @@ * limitations under the License. */ +import fs from 'fs-extra'; import Docker from 'dockerode'; -import mockFs from 'mock-fs'; -import os from 'os'; -import path from 'path'; import Stream, { PassThrough } from 'stream'; import { ContainerRunner } from './ContainerRunner'; import { DockerContainerRunner, UserOptions } from './DockerContainerRunner'; +import { createMockDirectory } from '@backstage/backend-test-utils'; const mockDocker = new Docker() as jest.Mocked<Docker>; -const rootDir = os.platform() === 'win32' ? 'C:\\rootDir' : '/rootDir'; describe('DockerContainerRunner', () => { let containerTaskApi: ContainerRunner; + const inputDir = createMockDirectory(); + const outputDir = createMockDirectory(); + beforeEach(() => { - mockFs({ - [rootDir]: { - input: mockFs.directory(), - output: mockFs.directory(), - }, - }); + inputDir.clear(); + outputDir.clear(); jest.spyOn(mockDocker, 'pull').mockImplementation((async ( _image: string, @@ -59,16 +56,15 @@ describe('DockerContainerRunner', () => { afterEach(() => { jest.clearAllMocks(); - mockFs.restore(); }); const imageName = 'dockerOrg/image'; const args = ['bash', '-c', 'echo test']; const mountDirs = { - [path.join(rootDir, 'input')]: '/input', - [path.join(rootDir, 'output')]: '/output', + [inputDir.path]: '/input', + [outputDir.path]: '/output', }; - const workingDir = path.join(rootDir, 'input'); + const workingDir = inputDir.path; const envVars = { HOME: '/tmp', LOG_LEVEL: 'debug' }; const envVarsArray = ['HOME=/tmp', 'LOG_LEVEL=debug']; @@ -117,8 +113,8 @@ describe('DockerContainerRunner', () => { HostConfig: { AutoRemove: true, Binds: expect.arrayContaining([ - `${path.join(rootDir, 'input')}:/input`, - `${path.join(rootDir, 'output')}:/output`, + `${await fs.realpath(inputDir.path)}:/input`, + `${await fs.realpath(outputDir.path)}:/output`, ]), }, Volumes: { diff --git a/packages/backend-defaults/CHANGELOG.md b/packages/backend-defaults/CHANGELOG.md index b70db2e92d..885ea4ced9 100644 --- a/packages/backend-defaults/CHANGELOG.md +++ b/packages/backend-defaults/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/backend-defaults +## 0.2.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-app-api@0.5.5-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + +## 0.2.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/backend-app-api@0.5.5-next.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + ## 0.2.3 ### Patch Changes diff --git a/packages/backend-defaults/package.json b/packages/backend-defaults/package.json index cff7d00bb9..00472e0a7d 100644 --- a/packages/backend-defaults/package.json +++ b/packages/backend-defaults/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-defaults", "description": "Backend defaults used by Backstage backend apps", - "version": "0.2.3", + "version": "0.2.5-next.1", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/backend-dev-utils/CHANGELOG.md b/packages/backend-dev-utils/CHANGELOG.md index 6b505e917e..3710cf3bd5 100644 --- a/packages/backend-dev-utils/CHANGELOG.md +++ b/packages/backend-dev-utils/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/backend-dev-utils +## 0.1.2-next.0 + +### Patch Changes + +- afa48341fb: Fix an issue where early IPC responses would be lost. + ## 0.1.1 ### Patch Changes diff --git a/packages/backend-dev-utils/package.json b/packages/backend-dev-utils/package.json index 0928032977..8d461b46cf 100644 --- a/packages/backend-dev-utils/package.json +++ b/packages/backend-dev-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-dev-utils", - "version": "0.1.1", + "version": "0.1.2-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/backend-dev-utils/src/ipcClient.ts b/packages/backend-dev-utils/src/ipcClient.ts index 87c1596a39..d9ec7821de 100644 --- a/packages/backend-dev-utils/src/ipcClient.ts +++ b/packages/backend-dev-utils/src/ipcClient.ts @@ -38,6 +38,8 @@ type Response = const requestType = '@backstage/cli/channel/request'; const responseType = '@backstage/cli/channel/response'; +const IPC_TIMEOUT_MS = 5000; + /** * The client side of an IPC communication channel. * @@ -78,43 +80,43 @@ export class BackstageIpcClient { body, }; - this.#sendMessage(request, (e: Error) => { - if (e) { - reject(e); + let timeout: NodeJS.Timeout | undefined = undefined; + + const messageHandler = (response: Response) => { + if (response?.type !== responseType) { + return; + } + if (response.id !== id) { return; } - let timeout: NodeJS.Timeout | undefined = undefined; + clearTimeout(timeout); + timeout = undefined; + process.removeListener('message', messageHandler); - const messageHandler = (response: Response) => { - if (response?.type !== responseType) { - return; - } - if (response.id !== id) { - return; + if ('error' in response) { + const error = new Error(response.error.message); + if (response.error.name) { + error.name = response.error.name; } + reject(error); + } else { + resolve(response.body as TResponseBody); + } + }; - if ('error' in response) { - const error = new Error(response.error.message); - if (response.error.name) { - error.name = response.error.name; - } - reject(error); - } else { - resolve(response.body as TResponseBody); - } + timeout = setTimeout(() => { + reject(new Error(`IPC request '${method}' with ID ${id} timed out`)); + process.removeListener('message', messageHandler); + }, IPC_TIMEOUT_MS); + timeout.unref(); - clearTimeout(timeout); - process.removeListener('message', messageHandler); - }; + process.addListener('message', messageHandler as () => void); - timeout = setTimeout(() => { - reject(new Error(`IPC request '${method}' with ID ${id} timed out`)); - process.removeListener('message', messageHandler); - }, 5000); - timeout.unref(); - - process.addListener('message', messageHandler as () => void); + this.#sendMessage(request, (e: Error) => { + if (e) { + reject(e); + } }); }); } diff --git a/packages/backend-next/CHANGELOG.md b/packages/backend-next/CHANGELOG.md index ab19eee8d9..8760f6cff2 100644 --- a/packages/backend-next/CHANGELOG.md +++ b/packages/backend-next/CHANGELOG.md @@ -1,5 +1,79 @@ # example-backend-next +## 0.0.16-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-backend@1.14.0-next.1 + - @backstage/plugin-scaffolder-backend@1.18.0-next.1 + - @backstage/plugin-badges-backend@0.3.2-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-lighthouse-backend@0.3.2-next.1 + - @backstage/plugin-linguist-backend@0.5.2-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.9-next.1 + - @backstage/plugin-search-backend-module-explore@0.1.9-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.9-next.1 + - @backstage/plugin-search-backend-node@1.2.9-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.2-next.1 + - @backstage/plugin-kubernetes-backend@0.12.2-next.1 + - @backstage/plugin-todo-backend@0.3.3-next.1 + - @backstage/backend-defaults@0.2.5-next.1 + - @backstage/plugin-adr-backend@0.4.2-next.1 + - @backstage/plugin-app-backend@0.3.53-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/plugin-azure-devops-backend@0.4.2-next.1 + - @backstage/plugin-devtools-backend@0.2.2-next.1 + - @backstage/plugin-entity-feedback-backend@0.2.2-next.1 + - @backstage/plugin-permission-backend@0.5.28-next.1 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.2-next.1 + - @backstage/plugin-permission-node@0.7.16-next.1 + - @backstage/plugin-playlist-backend@0.3.9-next.1 + - @backstage/plugin-proxy-backend@0.4.2-next.1 + - @backstage/plugin-search-backend@1.4.5-next.1 + - @backstage/plugin-sonarqube-backend@0.2.7-next.1 + - @backstage/plugin-techdocs-backend@1.7.2-next.1 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.2-next.1 + - @backstage/plugin-permission-common@0.7.8 + +## 0.0.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-sonarqube-backend@0.2.7-next.0 + - @backstage/plugin-playlist-backend@0.3.9-next.0 + - @backstage/plugin-catalog-backend@1.14.0-next.0 + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/plugin-adr-backend@0.4.2-next.0 + - @backstage/plugin-scaffolder-backend@1.17.3-next.0 + - @backstage/plugin-techdocs-backend@1.7.2-next.0 + - @backstage/plugin-todo-backend@0.3.3-next.0 + - @backstage/backend-defaults@0.2.5-next.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/plugin-app-backend@0.3.53-next.0 + - @backstage/plugin-azure-devops-backend@0.4.2-next.0 + - @backstage/plugin-badges-backend@0.3.2-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.2-next.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.2-next.0 + - @backstage/plugin-devtools-backend@0.2.2-next.0 + - @backstage/plugin-entity-feedback-backend@0.2.2-next.0 + - @backstage/plugin-kubernetes-backend@0.12.2-next.0 + - @backstage/plugin-lighthouse-backend@0.3.2-next.0 + - @backstage/plugin-linguist-backend@0.5.2-next.0 + - @backstage/plugin-permission-backend@0.5.28-next.0 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.2-next.0 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-permission-node@0.7.16-next.0 + - @backstage/plugin-proxy-backend@0.4.2-next.0 + - @backstage/plugin-search-backend@1.4.5-next.0 + - @backstage/plugin-search-backend-module-catalog@0.1.9-next.0 + - @backstage/plugin-search-backend-module-explore@0.1.9-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.9-next.0 + - @backstage/plugin-search-backend-node@1.2.9-next.0 + ## 0.0.15 ### Patch Changes diff --git a/packages/backend-next/package.json b/packages/backend-next/package.json index de0a19228c..3e5b4f8057 100644 --- a/packages/backend-next/package.json +++ b/packages/backend-next/package.json @@ -1,6 +1,6 @@ { "name": "example-backend-next", - "version": "0.0.15", + "version": "0.0.16-next.1", "main": "dist/index.cjs.js", "types": "src/index.ts", "license": "Apache-2.0", @@ -18,7 +18,7 @@ "backstage" ], "scripts": { - "start": "EXPERIMENTAL_BACKEND_START=1 backstage-cli package start", + "start": "backstage-cli package start", "build": "backstage-cli package build", "lint": "backstage-cli package lint", "test": "backstage-cli package test", @@ -41,10 +41,12 @@ "@backstage/plugin-kubernetes-backend": "workspace:^", "@backstage/plugin-lighthouse-backend": "workspace:^", "@backstage/plugin-linguist-backend": "workspace:^", + "@backstage/plugin-nomad-backend": "workspace:^", "@backstage/plugin-permission-backend": "workspace:^", "@backstage/plugin-permission-backend-module-allow-all-policy": "workspace:^", "@backstage/plugin-permission-common": "workspace:^", "@backstage/plugin-permission-node": "workspace:^", + "@backstage/plugin-playlist-backend": "workspace:^", "@backstage/plugin-proxy-backend": "workspace:^", "@backstage/plugin-scaffolder-backend": "workspace:^", "@backstage/plugin-search-backend": "workspace:^", @@ -52,6 +54,7 @@ "@backstage/plugin-search-backend-module-explore": "workspace:^", "@backstage/plugin-search-backend-module-techdocs": "workspace:^", "@backstage/plugin-search-backend-node": "workspace:^", + "@backstage/plugin-sonarqube-backend": "workspace:^", "@backstage/plugin-techdocs-backend": "workspace:^", "@backstage/plugin-todo-backend": "workspace:^" }, diff --git a/packages/backend-next/src/index.ts b/packages/backend-next/src/index.ts index 4e99732a11..1b4867c05e 100644 --- a/packages/backend-next/src/index.ts +++ b/packages/backend-next/src/index.ts @@ -32,6 +32,8 @@ backend.add(import('@backstage/plugin-entity-feedback-backend')); backend.add(import('@backstage/plugin-kubernetes-backend/alpha')); backend.add(import('@backstage/plugin-lighthouse-backend')); backend.add(import('@backstage/plugin-linguist-backend')); +backend.add(import('@backstage/plugin-playlist-backend')); +backend.add(import('@backstage/plugin-nomad-backend')); backend.add( import('@backstage/plugin-permission-backend-module-allow-all-policy'), ); @@ -44,5 +46,6 @@ backend.add(import('@backstage/plugin-search-backend-module-techdocs/alpha')); backend.add(import('@backstage/plugin-search-backend/alpha')); backend.add(import('@backstage/plugin-techdocs-backend/alpha')); backend.add(import('@backstage/plugin-todo-backend')); +backend.add(import('@backstage/plugin-sonarqube-backend')); backend.start(); diff --git a/packages/backend-openapi-utils/README.md b/packages/backend-openapi-utils/README.md index 1efab0e85b..ca3f03fcc1 100644 --- a/packages/backend-openapi-utils/README.md +++ b/packages/backend-openapi-utils/README.md @@ -61,6 +61,12 @@ export function createRouter() { } ``` +## FAQs + +### Why am I getting `unknown` as the type for a response? + +This can happen when you have a `charset` defined in your `response.content` section. Something like `response.content[ 'application/json; charset=utf-8:']` will cause this issue. + ## INTERNAL ### Limitations diff --git a/packages/backend-openapi-utils/api-report.md b/packages/backend-openapi-utils/api-report.md index 08ffa23a30..97ea0224d1 100644 --- a/packages/backend-openapi-utils/api-report.md +++ b/packages/backend-openapi-utils/api-report.md @@ -75,11 +75,18 @@ interface CookieObject extends ParameterObject { } // @public (undocumented) -type CookieSchema< +export type CookieParameters< Doc extends RequiredDoc, Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, + Method extends DocPathTemplateMethod<Doc, Path>, +> = CookieSchema<Doc, TemplateToDocPath<Doc, Path>, Method>; + +// @public (undocumented) +type CookieSchema< + Doc extends RequiredDoc, + Path extends DocPath<Doc>, Method extends DocPathMethod<Doc, Path>, -> = ParametersSchema<Doc, DocPath<Doc, Path>, Method, ImmutableCookieObject>; +> = ParametersSchema<Doc, Path, Method, ImmutableCookieObject>; // @public export function createValidatedOpenApiRouter<T extends RequiredDoc>( @@ -99,16 +106,16 @@ type DiscriminateUnion<T, K extends keyof T, V extends T[K]> = Extract< // @public (undocumented) type DocOperation< Doc extends RequiredDoc, - Path extends keyof Doc['paths'], + Path extends DocPath<Doc>, Method extends keyof Doc['paths'][Path], > = Doc['paths'][Path][Method]; // @public (undocumented) type DocParameter< Doc extends RequiredDoc, - Path extends Extract<keyof Doc['paths'], string>, - Method extends keyof Doc['paths'][Path], - Parameter extends keyof Doc['paths'][Path][Method]['parameters'], + Path extends DocPath<Doc>, + Method extends DocPathMethod<Doc, Path>, + Parameter extends keyof DocOperation<Doc, Path, Method>['parameters'], > = DocOperation< Doc, Path, @@ -142,32 +149,28 @@ type DocParameters< }; // @public -type DocPath< - Doc extends PathDoc, - Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, -> = ValueOf<{ - [Template in Extract< - keyof Doc['paths'], - string - >]: Path extends PathTemplate<Template> ? Template : never; -}>; +type DocPath<Doc extends PathDoc> = Extract<keyof Doc['paths'], string>; // @public (undocumented) type DocPathMethod< Doc extends Pick<RequiredDoc, 'paths'>, - Path extends DocPathTemplate<Doc>, -> = keyof Doc['paths'][DocPath<Doc, Path>]; + Path extends DocPath<Doc>, +> = keyof Doc['paths'][Path]; // @public (undocumented) -type DocPathTemplate<Doc extends PathDoc> = PathTemplate< - Extract<keyof Doc['paths'], string> ->; +type DocPathTemplate<Doc extends PathDoc> = PathTemplate<DocPath<Doc>>; + +// @public (undocumented) +type DocPathTemplateMethod< + Doc extends Pick<RequiredDoc, 'paths'>, + Path extends DocPathTemplate<Doc>, +> = keyof Doc['paths'][TemplateToDocPath<Doc, Path>]; // @public type DocRequestHandler< Doc extends RequiredDoc, - Path extends DocPathTemplate<Doc>, - Method extends keyof Doc['paths'][Path], + Path extends DocPath<Doc>, + Method extends DocPathMethod<Doc, Path>, > = core.RequestHandler< PathSchema<Doc, Path, Method>, ResponseBodyToJsonSchema<Doc, Path, Method>, @@ -179,8 +182,8 @@ type DocRequestHandler< // @public type DocRequestHandlerParams< Doc extends RequiredDoc, - Path extends DocPathTemplate<Doc>, - Method extends keyof Doc['paths'][Path], + Path extends DocPath<Doc>, + Method extends DocPathMethod<Doc, Path>, > = core.RequestHandlerParams< PathSchema<Doc, Path, Method>, ResponseBodyToJsonSchema<Doc, Path, Method>, @@ -204,14 +207,30 @@ interface DocRequestMatcher< | 'head', > { // (undocumented) - <Path extends MethodAwareDocPath<Doc, DocPathTemplate<Doc>, Method>>( + < + Path extends MethodAwareDocPath< + Doc, + PathTemplate<Extract<keyof Doc['paths'], string>>, + Method + >, + >( path: Path, - ...handlers: Array<DocRequestHandler<Doc, Path, Method>> + ...handlers: Array< + DocRequestHandler<Doc, TemplateToDocPath<Doc, Path>, Method> + > ): T; // (undocumented) - <Path extends MethodAwareDocPath<Doc, DocPathTemplate<Doc>, Method>>( + < + Path extends MethodAwareDocPath< + Doc, + PathTemplate<Extract<keyof Doc['paths'], string>>, + Method + >, + >( path: Path, - ...handlers: Array<DocRequestHandlerParams<Doc, Path, Method>> + ...handlers: Array< + DocRequestHandlerParams<Doc, TemplateToDocPath<Doc, Path>, Method> + > ): T; } @@ -238,11 +257,18 @@ interface HeaderObject extends ParameterObject { } // @public (undocumented) -type HeaderSchema< +export type HeaderParameters< Doc extends RequiredDoc, Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, + Method extends DocPathTemplateMethod<Doc, Path>, +> = HeaderSchema<Doc, TemplateToDocPath<Doc, Path>, Method>; + +// @public (undocumented) +type HeaderSchema< + Doc extends RequiredDoc, + Path extends DocPath<Doc>, Method extends DocPathMethod<Doc, Path>, -> = ParametersSchema<Doc, DocPath<Doc, Path>, Method, ImmutableHeaderObject>; +> = ParametersSchema<Doc, Path, Method, ImmutableHeaderObject>; // @public type Immutable<T> = T extends @@ -304,10 +330,12 @@ declare namespace internal { RequiredDoc, PathDoc, ValueOf, - PathTemplate, DocPath, + PathTemplate, + TemplateToDocPath, DocPathTemplate, DocPathMethod, + DocPathTemplateMethod, MethodAwareDocPath, DocOperation, ComponentTypes, @@ -362,7 +390,7 @@ declare namespace internal { RequestBody, RequestBodySchema, RequestBodyToJsonSchema, - Response_2 as Response, + Response_3 as Response, ResponseSchemas, ResponseBodyToJsonSchema, }; @@ -394,14 +422,11 @@ type MapToSchema< // @public (undocumented) type MethodAwareDocPath< Doc extends PathDoc, - Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, - Method extends keyof Doc['paths'][Path], + Path extends DocPathTemplate<Doc>, + Method extends DocPathTemplateMethod<Doc, Path>, > = ValueOf<{ - [Template in Extract< - keyof Doc['paths'], - string - >]: Path extends PathTemplate<Template> - ? Method extends DocPathMethod<Doc, Path> + [Template in DocPath<Doc>]: Path extends PathTemplate<Template> + ? Method extends DocPathTemplateMethod<Doc, Path> ? PathTemplate<Template> : never : never; @@ -466,11 +491,18 @@ interface PathObject extends ParameterObject { } // @public (undocumented) -type PathSchema< +export type PathParameters< Doc extends RequiredDoc, Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, + Method extends DocPathTemplateMethod<Doc, Path>, +> = PathSchema<Doc, TemplateToDocPath<Doc, Path>, Method>; + +// @public (undocumented) +type PathSchema< + Doc extends RequiredDoc, + Path extends DocPath<Doc>, Method extends DocPathMethod<Doc, Path>, -> = ParametersSchema<Doc, DocPath<Doc, Path>, Method, ImmutablePathObject>; +> = ParametersSchema<Doc, Path, Method, ImmutablePathObject>; // @public type PathTemplate<Path extends string> = @@ -508,11 +540,26 @@ interface QueryObject extends ParameterObject { } // @public (undocumented) -type QuerySchema< +export type QueryParameters< Doc extends RequiredDoc, Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, + Method extends DocPathTemplateMethod<Doc, Path>, +> = QuerySchema<Doc, TemplateToDocPath<Doc, Path>, Method>; + +// @public (undocumented) +type QuerySchema< + Doc extends RequiredDoc, + Path extends DocPath<Doc>, Method extends DocPathMethod<Doc, Path>, -> = ParametersSchema<Doc, DocPath<Doc, Path>, Method, ImmutableQueryObject>; +> = ParametersSchema<Doc, Path, Method, ImmutableQueryObject>; + +// @public (undocumented) +type Request_2< + Doc extends RequiredDoc, + Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, + Method extends DocPathTemplateMethod<Doc, Path>, +> = RequestBodyToJsonSchema<Doc, TemplateToDocPath<Doc, Path>, Method>; +export { Request_2 as Request }; // @public (undocumented) type RequestBody< @@ -536,20 +583,16 @@ type RequestBody< // @public (undocumented) type RequestBodySchema< Doc extends RequiredDoc, - Path extends DocPathTemplate<Doc>, + Path extends DocPath<Doc>, Method extends DocPathMethod<Doc, Path>, -> = RequestBody< - Doc, - DocPath<Doc, Path>, - Method -> extends ImmutableRequestBodyObject - ? ObjectWithContentSchema<Doc, RequestBody<Doc, DocPath<Doc, Path>, Method>> +> = RequestBody<Doc, Path, Method> extends ImmutableRequestBodyObject + ? ObjectWithContentSchema<Doc, RequestBody<Doc, Path, Method>> : never; // @public type RequestBodyToJsonSchema< Doc extends RequiredDoc, - Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, + Path extends DocPath<Doc>, Method extends DocPathMethod<Doc, Path>, > = ToTypeSafe<RequestBodySchema<Doc, Path, Method>>; @@ -568,8 +611,16 @@ type RequiredMap< // @public (undocumented) type Response_2< Doc extends RequiredDoc, - Path extends keyof Doc['paths'], - Method extends keyof Doc['paths'][Path], + Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, + Method extends DocPathTemplateMethod<Doc, Path>, +> = ResponseBodyToJsonSchema<Doc, TemplateToDocPath<Doc, Path>, Method>; +export { Response_2 as Response }; + +// @public (undocumented) +type Response_3< + Doc extends RequiredDoc, + Path extends DocPath<Doc>, + Method extends DocPathMethod<Doc, Path>, StatusCode extends keyof DocOperation<Doc, Path, Method>['responses'], > = DocOperation< Doc, @@ -588,27 +639,27 @@ type Response_2< // @public type ResponseBodyToJsonSchema< Doc extends RequiredDoc, - Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, + Path extends DocPath<Doc>, Method extends DocPathMethod<Doc, Path>, > = ToTypeSafe<ValueOf<ResponseSchemas<Doc, Path, Method>>>; // @public (undocumented) type ResponseSchemas< Doc extends RequiredDoc, - Path extends DocPathTemplate<Doc>, + Path extends DocPath<Doc>, Method extends DocPathMethod<Doc, Path>, > = { [StatusCode in keyof DocOperation< Doc, Path, Method - >['responses']]: Response_2< + >['responses']]: Response_3< Doc, Path, Method, StatusCode > extends ImmutableResponseObject - ? ObjectWithContentSchema<Doc, Response_2<Doc, Path, Method, StatusCode>> + ? ObjectWithContentSchema<Doc, Response_3<Doc, Path, Method, StatusCode>> : never; }; @@ -625,6 +676,16 @@ type SchemaRef<Doc extends RequiredDoc, Schema> = Schema extends { [Key in keyof Schema]: SchemaRef<Doc, Schema[Key]>; }; +// @public +type TemplateToDocPath< + Doc extends PathDoc, + Path extends DocPathTemplate<Doc>, +> = ValueOf<{ + [Template in DocPath<Doc>]: Path extends PathTemplate<Template> + ? Template + : never; +}>; + // @public (undocumented) type ToTypeSafe<T> = UnknownIfNever<ConvertAll<TuplifyUnion<T>>[number]>; diff --git a/packages/backend-openapi-utils/src/index.ts b/packages/backend-openapi-utils/src/index.ts index 3acdcbf6f0..2b612fd617 100644 --- a/packages/backend-openapi-utils/src/index.ts +++ b/packages/backend-openapi-utils/src/index.ts @@ -22,5 +22,13 @@ import * as internal from './types'; export { internal }; +export type { + Request, + Response, + QueryParameters, + HeaderParameters, + CookieParameters, + PathParameters, +} from './utility'; export type { ApiRouter } from './router'; export { createValidatedOpenApiRouter } from './stub'; diff --git a/packages/backend-openapi-utils/src/stub.test.ts b/packages/backend-openapi-utils/src/stub.test.ts index 678445c818..c9ec955e95 100644 --- a/packages/backend-openapi-utils/src/stub.test.ts +++ b/packages/backend-openapi-utils/src/stub.test.ts @@ -18,15 +18,23 @@ import { createValidatedOpenApiRouter } from './stub'; import express from 'express'; import request from 'supertest'; import singlePathSpec from './___fixtures__/single-path'; +import { Response } from './utility'; describe('createRouter', () => { + const pet: Response<typeof singlePathSpec, '/pet/:petId', 'get'> = { + id: 1, + name: 'rover', + status: 'available', + photoUrls: [], + }; + it('does NOT override originalUrl and basePath after execution', async () => { expect.assertions(2); const router = createValidatedOpenApiRouter(singlePathSpec); router.get('/pet/:petId', (req, res) => { expect(req.baseUrl).toBe('/pet-store'); expect(req.originalUrl).toBe(`/pet-store/pet/${req.params.petId}`); - res.send(''); + res.status(400).send(); }); const appRouter = express(); @@ -41,7 +49,7 @@ describe('createRouter', () => { const routerGetFn = jest.fn(); router.get('/pet/:petId', (_, res) => { routerGetFn(); - res.send(''); + res.json(pet); }); const apiRouter = express.Router(); @@ -58,7 +66,7 @@ describe('createRouter', () => { const router = createValidatedOpenApiRouter(singlePathSpec); router.get('/pet/:petId', (req, res) => { expect(typeof req.params.petId).toBe('integer'); - res.send(''); + res.json(pet); }); const apiRouter = express.Router(); diff --git a/packages/backend-openapi-utils/src/types/common.ts b/packages/backend-openapi-utils/src/types/common.ts index 5568ed795c..c3c7284369 100644 --- a/packages/backend-openapi-utils/src/types/common.ts +++ b/packages/backend-openapi-utils/src/types/common.ts @@ -42,6 +42,13 @@ export type PathDoc = Pick<ImmutableOpenAPIObject, 'paths'>; */ export type ValueOf<T> = T[keyof T]; +/** + * All paths for a given doc, + * @example `/pet/{petId}` | `/pet` + * @public + */ +export type DocPath<Doc extends PathDoc> = Extract<keyof Doc['paths'], string>; + /** * Validate a string against OpenAPI path template, {@link https://spec.openapis.org/oas/v3.1.0#path-templating-matching}. * @@ -74,44 +81,46 @@ export type PathTemplate<Path extends string> = * * @public */ -export type DocPath< +export type TemplateToDocPath< Doc extends PathDoc, - Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, + Path extends DocPathTemplate<Doc>, > = ValueOf<{ - [Template in Extract< - keyof Doc['paths'], - string - >]: Path extends PathTemplate<Template> ? Template : never; + [Template in DocPath<Doc>]: Path extends PathTemplate<Template> + ? Template + : never; }>; /** * @public */ -export type DocPathTemplate<Doc extends PathDoc> = PathTemplate< - Extract<keyof Doc['paths'], string> ->; +export type DocPathTemplate<Doc extends PathDoc> = PathTemplate<DocPath<Doc>>; /** * @public */ export type DocPathMethod< + Doc extends Pick<RequiredDoc, 'paths'>, + Path extends DocPath<Doc>, +> = keyof Doc['paths'][Path]; + +/** + * @public + */ +export type DocPathTemplateMethod< Doc extends Pick<RequiredDoc, 'paths'>, Path extends DocPathTemplate<Doc>, -> = keyof Doc['paths'][DocPath<Doc, Path>]; +> = keyof Doc['paths'][TemplateToDocPath<Doc, Path>]; /** * @public */ export type MethodAwareDocPath< Doc extends PathDoc, - Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, - Method extends keyof Doc['paths'][Path], + Path extends DocPathTemplate<Doc>, + Method extends DocPathTemplateMethod<Doc, Path>, > = ValueOf<{ - [Template in Extract< - keyof Doc['paths'], - string - >]: Path extends PathTemplate<Template> - ? Method extends DocPathMethod<Doc, Path> + [Template in DocPath<Doc>]: Path extends PathTemplate<Template> + ? Method extends DocPathTemplateMethod<Doc, Path> ? PathTemplate<Template> : never : never; @@ -122,7 +131,7 @@ export type MethodAwareDocPath< */ export type DocOperation< Doc extends RequiredDoc, - Path extends keyof Doc['paths'], + Path extends DocPath<Doc>, Method extends keyof Doc['paths'][Path], > = Doc['paths'][Path][Method]; diff --git a/packages/backend-openapi-utils/src/types/express.ts b/packages/backend-openapi-utils/src/types/express.ts index b0020dab37..127400099a 100644 --- a/packages/backend-openapi-utils/src/types/express.ts +++ b/packages/backend-openapi-utils/src/types/express.ts @@ -14,7 +14,14 @@ * limitations under the License. */ import type core from 'express-serve-static-core'; -import { DocPathTemplate, MethodAwareDocPath, RequiredDoc } from './common'; +import { + DocPath, + DocPathMethod, + MethodAwareDocPath, + PathTemplate, + RequiredDoc, + TemplateToDocPath, +} from './common'; import { PathSchema, QuerySchema } from './params'; import { RequestBodyToJsonSchema } from './requests'; import { ResponseBodyToJsonSchema } from './responses'; @@ -25,8 +32,8 @@ import { ResponseBodyToJsonSchema } from './responses'; */ export type DocRequestHandler< Doc extends RequiredDoc, - Path extends DocPathTemplate<Doc>, - Method extends keyof Doc['paths'][Path], + Path extends DocPath<Doc>, + Method extends DocPathMethod<Doc, Path>, > = core.RequestHandler< PathSchema<Doc, Path, Method>, ResponseBodyToJsonSchema<Doc, Path, Method>, @@ -41,8 +48,8 @@ export type DocRequestHandler< */ export type DocRequestHandlerParams< Doc extends RequiredDoc, - Path extends DocPathTemplate<Doc>, - Method extends keyof Doc['paths'][Path], + Path extends DocPath<Doc>, + Method extends DocPathMethod<Doc, Path>, > = core.RequestHandlerParams< PathSchema<Doc, Path, Method>, ResponseBodyToJsonSchema<Doc, Path, Method>, @@ -68,12 +75,28 @@ export interface DocRequestMatcher< | 'options' | 'head', > { - <Path extends MethodAwareDocPath<Doc, DocPathTemplate<Doc>, Method>>( + < + Path extends MethodAwareDocPath< + Doc, + PathTemplate<Extract<keyof Doc['paths'], string>>, + Method + >, + >( path: Path, - ...handlers: Array<DocRequestHandler<Doc, Path, Method>> + ...handlers: Array< + DocRequestHandler<Doc, TemplateToDocPath<Doc, Path>, Method> + > ): T; - <Path extends MethodAwareDocPath<Doc, DocPathTemplate<Doc>, Method>>( + < + Path extends MethodAwareDocPath< + Doc, + PathTemplate<Extract<keyof Doc['paths'], string>>, + Method + >, + >( path: Path, - ...handlers: Array<DocRequestHandlerParams<Doc, Path, Method>> + ...handlers: Array< + DocRequestHandlerParams<Doc, TemplateToDocPath<Doc, Path>, Method> + > ): T; } diff --git a/packages/backend-openapi-utils/src/types/params.ts b/packages/backend-openapi-utils/src/types/params.ts index 52d61a2683..208cbd4e9a 100644 --- a/packages/backend-openapi-utils/src/types/params.ts +++ b/packages/backend-openapi-utils/src/types/params.ts @@ -32,7 +32,6 @@ import { Filter, FullMap, MapDiscriminatedUnion, - PathTemplate, RequiredDoc, SchemaRef, ValueOf, @@ -44,9 +43,9 @@ import { FromSchema, JSONSchema7 } from 'json-schema-to-ts'; */ export type DocParameter< Doc extends RequiredDoc, - Path extends Extract<keyof Doc['paths'], string>, - Method extends keyof Doc['paths'][Path], - Parameter extends keyof Doc['paths'][Path][Method]['parameters'], + Path extends DocPath<Doc>, + Method extends DocPathMethod<Doc, Path>, + Parameter extends keyof DocOperation<Doc, Path, Method>['parameters'], > = DocOperation< Doc, Path, @@ -138,33 +137,33 @@ export type ParametersSchema< */ export type HeaderSchema< Doc extends RequiredDoc, - Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, + Path extends DocPath<Doc>, Method extends DocPathMethod<Doc, Path>, -> = ParametersSchema<Doc, DocPath<Doc, Path>, Method, ImmutableHeaderObject>; +> = ParametersSchema<Doc, Path, Method, ImmutableHeaderObject>; /** * @public */ export type CookieSchema< Doc extends RequiredDoc, - Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, + Path extends DocPath<Doc>, Method extends DocPathMethod<Doc, Path>, -> = ParametersSchema<Doc, DocPath<Doc, Path>, Method, ImmutableCookieObject>; +> = ParametersSchema<Doc, Path, Method, ImmutableCookieObject>; /** * @public */ export type PathSchema< Doc extends RequiredDoc, - Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, + Path extends DocPath<Doc>, Method extends DocPathMethod<Doc, Path>, -> = ParametersSchema<Doc, DocPath<Doc, Path>, Method, ImmutablePathObject>; +> = ParametersSchema<Doc, Path, Method, ImmutablePathObject>; /** * @public */ export type QuerySchema< Doc extends RequiredDoc, - Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, + Path extends DocPath<Doc>, Method extends DocPathMethod<Doc, Path>, -> = ParametersSchema<Doc, DocPath<Doc, Path>, Method, ImmutableQueryObject>; +> = ParametersSchema<Doc, Path, Method, ImmutableQueryObject>; diff --git a/packages/backend-openapi-utils/src/types/requests.ts b/packages/backend-openapi-utils/src/types/requests.ts index e6542e186d..99c09bc520 100644 --- a/packages/backend-openapi-utils/src/types/requests.ts +++ b/packages/backend-openapi-utils/src/types/requests.ts @@ -26,8 +26,6 @@ import type { DocOperation, DocPath, DocPathMethod, - DocPathTemplate, - PathTemplate, ToTypeSafe, } from './common'; import { @@ -61,14 +59,10 @@ export type RequestBody< */ export type RequestBodySchema< Doc extends RequiredDoc, - Path extends DocPathTemplate<Doc>, + Path extends DocPath<Doc>, Method extends DocPathMethod<Doc, Path>, -> = RequestBody< - Doc, - DocPath<Doc, Path>, - Method -> extends ImmutableRequestBodyObject - ? ObjectWithContentSchema<Doc, RequestBody<Doc, DocPath<Doc, Path>, Method>> +> = RequestBody<Doc, Path, Method> extends ImmutableRequestBodyObject + ? ObjectWithContentSchema<Doc, RequestBody<Doc, Path, Method>> : never; /** @@ -77,6 +71,6 @@ export type RequestBodySchema< */ export type RequestBodyToJsonSchema< Doc extends RequiredDoc, - Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, + Path extends DocPath<Doc>, Method extends DocPathMethod<Doc, Path>, > = ToTypeSafe<RequestBodySchema<Doc, Path, Method>>; diff --git a/packages/backend-openapi-utils/src/types/responses.ts b/packages/backend-openapi-utils/src/types/responses.ts index 01e4a12aba..9c58ba7035 100644 --- a/packages/backend-openapi-utils/src/types/responses.ts +++ b/packages/backend-openapi-utils/src/types/responses.ts @@ -25,10 +25,9 @@ import type { RequiredDoc, DocOperation, DocPathMethod, - DocPathTemplate, - PathTemplate, ToTypeSafe, ValueOf, + DocPath, } from './common'; import { ImmutableReferenceObject, ImmutableResponseObject } from './immutable'; @@ -37,8 +36,8 @@ import { ImmutableReferenceObject, ImmutableResponseObject } from './immutable'; */ export type Response< Doc extends RequiredDoc, - Path extends keyof Doc['paths'], - Method extends keyof Doc['paths'][Path], + Path extends DocPath<Doc>, + Method extends DocPathMethod<Doc, Path>, StatusCode extends keyof DocOperation<Doc, Path, Method>['responses'], > = DocOperation< Doc, @@ -59,7 +58,7 @@ export type Response< */ export type ResponseSchemas< Doc extends RequiredDoc, - Path extends DocPathTemplate<Doc>, + Path extends DocPath<Doc>, Method extends DocPathMethod<Doc, Path>, > = { [StatusCode in keyof DocOperation<Doc, Path, Method>['responses']]: Response< @@ -78,6 +77,6 @@ export type ResponseSchemas< */ export type ResponseBodyToJsonSchema< Doc extends RequiredDoc, - Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, + Path extends DocPath<Doc>, Method extends DocPathMethod<Doc, Path>, > = ToTypeSafe<ValueOf<ResponseSchemas<Doc, Path, Method>>>; diff --git a/packages/backend-openapi-utils/src/utility.ts b/packages/backend-openapi-utils/src/utility.ts new file mode 100644 index 0000000000..d20f615bbb --- /dev/null +++ b/packages/backend-openapi-utils/src/utility.ts @@ -0,0 +1,81 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { + CookieSchema, + DocPathTemplateMethod, + HeaderSchema, + PathSchema, + PathTemplate, + QuerySchema, + RequestBodyToJsonSchema, + RequiredDoc, + ResponseBodyToJsonSchema, + TemplateToDocPath, +} from './types'; + +/** + * @public + */ +export type Response< + Doc extends RequiredDoc, + Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, + Method extends DocPathTemplateMethod<Doc, Path>, +> = ResponseBodyToJsonSchema<Doc, TemplateToDocPath<Doc, Path>, Method>; + +/** + * @public + */ +export type Request< + Doc extends RequiredDoc, + Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, + Method extends DocPathTemplateMethod<Doc, Path>, +> = RequestBodyToJsonSchema<Doc, TemplateToDocPath<Doc, Path>, Method>; + +/** + * @public + */ +export type HeaderParameters< + Doc extends RequiredDoc, + Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, + Method extends DocPathTemplateMethod<Doc, Path>, +> = HeaderSchema<Doc, TemplateToDocPath<Doc, Path>, Method>; + +/** + * @public + */ +export type CookieParameters< + Doc extends RequiredDoc, + Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, + Method extends DocPathTemplateMethod<Doc, Path>, +> = CookieSchema<Doc, TemplateToDocPath<Doc, Path>, Method>; + +/** + * @public + */ +export type PathParameters< + Doc extends RequiredDoc, + Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, + Method extends DocPathTemplateMethod<Doc, Path>, +> = PathSchema<Doc, TemplateToDocPath<Doc, Path>, Method>; + +/** + * @public + */ +export type QueryParameters< + Doc extends RequiredDoc, + Path extends PathTemplate<Extract<keyof Doc['paths'], string>>, + Method extends DocPathTemplateMethod<Doc, Path>, +> = QuerySchema<Doc, TemplateToDocPath<Doc, Path>, Method>; diff --git a/packages/backend-plugin-api/CHANGELOG.md b/packages/backend-plugin-api/CHANGELOG.md index 5f78bb435d..ce19f9a798 100644 --- a/packages/backend-plugin-api/CHANGELOG.md +++ b/packages/backend-plugin-api/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/backend-plugin-api +## 0.6.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/config@1.1.0 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.8 + +## 0.6.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.8 + ## 0.6.3 ### Patch Changes diff --git a/packages/backend-plugin-api/package.json b/packages/backend-plugin-api/package.json index 9ca71972e1..8374a002b8 100644 --- a/packages/backend-plugin-api/package.json +++ b/packages/backend-plugin-api/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-plugin-api", "description": "Core API used by Backstage backend plugins", - "version": "0.6.3", + "version": "0.6.5-next.1", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/backend-plugin-manager/CHANGELOG.md b/packages/backend-plugin-manager/CHANGELOG.md index 71443041d2..6e1499eb1b 100644 --- a/packages/backend-plugin-manager/CHANGELOG.md +++ b/packages/backend-plugin-manager/CHANGELOG.md @@ -1,5 +1,51 @@ # @backstage/backend-plugin-manager +## 0.0.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-backend@1.14.0-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-search-backend-node@1.2.9-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/plugin-events-backend@0.2.14-next.1 + - @backstage/plugin-permission-node@0.7.16-next.1 + - @backstage/plugin-scaffolder-node@0.2.5-next.1 + - @backstage/config@1.1.0 + - @backstage/cli-common@0.1.13-next.0 + - @backstage/cli-node@0.1.5-next.0 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.2.14-next.1 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-search-common@1.2.6 + +## 0.0.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.14.0-next.0 + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/cli-common@0.1.13-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/plugin-scaffolder-node@0.2.5-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/cli-node@0.1.5-next.0 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-events-backend@0.2.14-next.0 + - @backstage/plugin-events-node@0.2.14-next.0 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-permission-node@0.7.16-next.0 + - @backstage/plugin-search-backend-node@1.2.9-next.0 + - @backstage/plugin-search-common@1.2.6 + ## 0.0.1 ### Patch Changes diff --git a/packages/backend-plugin-manager/package.json b/packages/backend-plugin-manager/package.json index e4d737a328..67697981a1 100644 --- a/packages/backend-plugin-manager/package.json +++ b/packages/backend-plugin-manager/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-plugin-manager", "description": "Backstage plugin management backend", - "version": "0.0.1", + "version": "0.0.2-next.1", "private": true, "main": "src/index.ts", "types": "src/index.ts", diff --git a/packages/backend-tasks/CHANGELOG.md b/packages/backend-tasks/CHANGELOG.md index efcfa0c702..bd1284aaf5 100644 --- a/packages/backend-tasks/CHANGELOG.md +++ b/packages/backend-tasks/CHANGELOG.md @@ -1,5 +1,33 @@ # @backstage/backend-tasks +## 0.5.10-next.1 + +### Patch Changes + +- 5db102bfdf: Instrument `backend-tasks` with some counters and histograms for duration. + + `backend_tasks.task.runs.count`: Counter with the total number of times a task has been run. + `backend_tasks.task.runs.duration`: Histogram with the run durations for each task. + + Both these metrics have come with `result` `taskId` and `scope` labels for finer grained grouping. + +- ddd76ac98d: Fix bug where backend tasks that are defined with HumanDuration are immediately triggered on application startup +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + +## 0.5.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + ## 0.5.8 ### Patch Changes diff --git a/packages/backend-tasks/package.json b/packages/backend-tasks/package.json index a8d52d0b00..9a42aab169 100644 --- a/packages/backend-tasks/package.json +++ b/packages/backend-tasks/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-tasks", "description": "Common distributed task management library for Backstage backends", - "version": "0.5.8", + "version": "0.5.10-next.1", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { @@ -36,6 +36,7 @@ "@backstage/config": "workspace:^", "@backstage/errors": "workspace:^", "@backstage/types": "workspace:^", + "@opentelemetry/api": "^1.3.0", "@types/luxon": "^3.0.0", "cron": "^2.0.0", "knex": "^2.0.0", diff --git a/packages/backend-tasks/src/tasks/PluginTaskSchedulerImpl.ts b/packages/backend-tasks/src/tasks/PluginTaskSchedulerImpl.ts index b9ac80cb47..38561c7a8c 100644 --- a/packages/backend-tasks/src/tasks/PluginTaskSchedulerImpl.ts +++ b/packages/backend-tasks/src/tasks/PluginTaskSchedulerImpl.ts @@ -28,6 +28,8 @@ import { TaskSettingsV2, } from './types'; import { validateId } from './util'; +import { TaskFunction } from './types'; +import { metrics, Counter, Histogram } from '@opentelemetry/api'; /** * Implements the actual task management. @@ -36,10 +38,22 @@ export class PluginTaskSchedulerImpl implements PluginTaskScheduler { private readonly localTasksById = new Map<string, LocalTaskWorker>(); private readonly allScheduledTasks: TaskDescriptor[] = []; + private readonly counter: Counter; + private readonly duration: Histogram; + constructor( private readonly databaseFactory: () => Promise<Knex>, private readonly logger: Logger, - ) {} + ) { + const meter = metrics.getMeter('default'); + this.counter = meter.createCounter('backend_tasks.task.runs.count', { + description: 'Total number of times a task has been run', + }); + this.duration = meter.createHistogram('backend_tasks.task.runs.duration', { + description: 'Histogram of task run durations', + unit: 'seconds', + }); + } async triggerTask(id: string): Promise<void> { const localTask = this.localTasksById.get(id); @@ -70,7 +84,7 @@ export class PluginTaskSchedulerImpl implements PluginTaskScheduler { const knex = await this.databaseFactory(); const worker = new TaskWorker( task.id, - task.fn, + this.wrapInMetrics(task.fn, { labels: { taskId: task.id, scope } }), knex, this.logger.child({ task: task.id }), ); @@ -78,7 +92,7 @@ export class PluginTaskSchedulerImpl implements PluginTaskScheduler { } else { const worker = new LocalTaskWorker( task.id, - task.fn, + this.wrapInMetrics(task.fn, { labels: { taskId: task.id, scope } }), this.logger.child({ task: task.id }), ); worker.start(settings, { signal: task.signal }); @@ -103,6 +117,33 @@ export class PluginTaskSchedulerImpl implements PluginTaskScheduler { async getScheduledTasks(): Promise<TaskDescriptor[]> { return this.allScheduledTasks; } + + private wrapInMetrics( + fn: TaskFunction, + opts: { labels: Record<string, string> }, + ): TaskFunction { + return async abort => { + const labels = { + ...opts.labels, + }; + this.counter.add(1, { ...labels, result: 'started' }); + + const startTime = process.hrtime(); + + try { + await fn(abort); + labels.result = 'completed'; + } catch (ex) { + labels.result = 'failed'; + throw ex; + } finally { + const delta = process.hrtime(startTime); + const endTime = delta[0] + delta[1] / 1e9; + this.counter.add(1, labels); + this.duration.record(endTime, labels); + } + }; + } } export function parseDuration( diff --git a/packages/backend-tasks/src/tasks/TaskWorker.test.ts b/packages/backend-tasks/src/tasks/TaskWorker.test.ts index 3022f59060..efad4e649b 100644 --- a/packages/backend-tasks/src/tasks/TaskWorker.test.ts +++ b/packages/backend-tasks/src/tasks/TaskWorker.test.ts @@ -16,7 +16,7 @@ import { getVoidLogger } from '@backstage/backend-common'; import { TestDatabases } from '@backstage/backend-test-utils'; -import { Duration } from 'luxon'; +import { Duration, DateTime } from 'luxon'; import waitForExpect from 'wait-for-expect'; import { migrateBackendTasks } from '../database/migrateBackendTasks'; import { DbTasksRow, DB_TASKS_TABLE } from '../database/tables'; @@ -338,7 +338,7 @@ describe('TaskWorker', () => { ); it.each(databases.eachSupportedId())( - 'next_run_start_at is always the min between schedule changes, %p', + 'next_run_start_at is always the min between schedule changes from cron frequency, %p', async databaseId => { const knex = await databases.init(databaseId); await migrateBackendTasks(knex); @@ -376,4 +376,127 @@ describe('TaskWorker', () => { await knex.destroy(); }, ); + + it.each(databases.eachSupportedId())( + 'next_run_start_at is always the min between schedule changes when using human duration frequency, %p', + async databaseId => { + const knex = await databases.init(databaseId); + await migrateBackendTasks(knex); + + const fn = jest.fn( + async () => new Promise<void>(resolve => setTimeout(resolve, 50)), + ); + + const initialSettings: TaskSettingsV2 = { + version: 2, + cadence: 'PT120M', + timeoutAfterDuration: 'PT1M', + }; + + const worker = new TaskWorker('task99', fn, knex, logger); + await worker.persistTask(initialSettings); + // replicate task running, sets next_run_start_at based on cadence + await worker.tryClaimTask('ticket', initialSettings); + await worker.tryReleaseTask('ticket', initialSettings); + + // grab initial row for comparisons later + const rowAfterClaimAndRelease = ( + await knex<DbTasksRow>(DB_TASKS_TABLE) + )[0]; + + const settings: TaskSettingsV2 = { + ...initialSettings, + cadence: 'PT60M', + }; + await worker.persistTask(settings); + const row1 = (await knex<DbTasksRow>(DB_TASKS_TABLE))[0]; + + const rowAfterClaimAndReleaseNextStartAt = DateTime.fromJSDate( + new Date(rowAfterClaimAndRelease.next_run_start_at), + ); + const row1NextStartAt = DateTime.fromJSDate( + new Date(row1.next_run_start_at), + ); + const now = DateTime.now(); + expect( + rowAfterClaimAndReleaseNextStartAt.diff(row1NextStartAt).as('minutes'), + ).toBeCloseTo(60, 1); // ensure that next start at is sooner than initial by one hour + expect(row1NextStartAt.diff(now).as('minutes')).toBeCloseTo(60, 1); // ensure that next start at is later than now by one hour + expect( + rowAfterClaimAndReleaseNextStartAt.diff(now).as('minutes'), + ).toBeCloseTo(120, 1); + + const settings2 = { + ...settings, + }; + await worker.persistTask(settings2); + const row2 = (await knex<DbTasksRow>(DB_TASKS_TABLE))[0]; + + expect(row2.next_run_start_at).toStrictEqual(row1.next_run_start_at); + + await knex.destroy(); + }, + ); + + it.each(databases.eachSupportedId())( + 'next_run_start_at is always the min between schedule changes when using human duration frequency with initial start delay, %p', + async databaseId => { + const knex = await databases.init(databaseId); + await migrateBackendTasks(knex); + + const fn = jest.fn( + async () => new Promise<void>(resolve => setTimeout(resolve, 50)), + ); + + const initialSettings: TaskSettingsV2 = { + version: 2, + cadence: 'PT120M', + initialDelayDuration: 'PT2M', + timeoutAfterDuration: 'PT1M', + }; + + const worker = new TaskWorker('task99', fn, knex, logger); + await worker.persistTask(initialSettings); + // replicate task running, sets next_run_start_at based on cadence + await worker.tryClaimTask('ticket', initialSettings); + await worker.tryReleaseTask('ticket', initialSettings); + + // grab initial row for comparisons later + const rowAfterClaimAndRelease = ( + await knex<DbTasksRow>(DB_TASKS_TABLE) + )[0]; + + const settings: TaskSettingsV2 = { + ...initialSettings, + cadence: 'PT60M', + }; + await worker.persistTask(settings); + const row1 = (await knex<DbTasksRow>(DB_TASKS_TABLE))[0]; + + const rowAfterClaimAndReleaseNextStartAt = DateTime.fromJSDate( + new Date(rowAfterClaimAndRelease.next_run_start_at), + ); + const row1NextStartAt = DateTime.fromJSDate( + new Date(row1.next_run_start_at), + ); + const now = DateTime.now(); + expect( + rowAfterClaimAndReleaseNextStartAt.diff(row1NextStartAt).as('minutes'), + ).toBeCloseTo(62, 1); // ensure that next start at is sooner than initial by one hour, plus the 2 minute delay (set my tryReleaseTask) + expect(row1NextStartAt.diff(now).as('minutes')).toBeCloseTo(60, 1); // ensure that next start at is later than now by one hour (2 minute delay doesn't take effect here) + expect( + rowAfterClaimAndReleaseNextStartAt.diff(now).as('minutes'), + ).toBeCloseTo(122, 1); // includes 2 minute start delay (which is persisted from tryReleaseTask) + + const settings2 = { + ...settings, + }; + await worker.persistTask(settings2); + const row2 = (await knex<DbTasksRow>(DB_TASKS_TABLE))[0]; + + expect(row2.next_run_start_at).toStrictEqual(row1.next_run_start_at); + + await knex.destroy(); + }, + ); }); diff --git a/packages/backend-tasks/src/tasks/TaskWorker.ts b/packages/backend-tasks/src/tasks/TaskWorker.ts index c1007b4964..4e10f0b5b2 100644 --- a/packages/backend-tasks/src/tasks/TaskWorker.ts +++ b/packages/backend-tasks/src/tasks/TaskWorker.ts @@ -50,6 +50,7 @@ export class TaskWorker { this.logger.info( `Task worker starting: ${this.taskId}, ${JSON.stringify(settings)}`, ); + let attemptNum = 1; (async () => { for (;;) { @@ -63,6 +64,7 @@ export class TaskWorker { while (!options?.signal?.aborted) { const runResult = await this.runOnce(options?.signal); + if (runResult.result === 'abort') { break; } @@ -165,27 +167,26 @@ export class TaskWorker { const isCron = !settings?.cadence.startsWith('P'); - let startAt: Knex.Raw; + let startAt: Knex.Raw | undefined; + let nextStartAt: Knex.Raw | undefined; if (settings.initialDelayDuration) { startAt = nowPlus( Duration.fromISO(settings.initialDelayDuration), this.knex, ); - } else if (isCron) { + } + + if (isCron) { const time = new CronTime(settings.cadence) .sendAt() .minus({ seconds: 1 }) // immediately, if "* * * * * *" .toUTC(); - if (this.knex.client.config.client.includes('sqlite3')) { - startAt = this.knex.raw('datetime(?)', [time.toISO()]); - } else if (this.knex.client.config.client.includes('mysql')) { - startAt = this.knex.raw(`?`, [time.toSQL({ includeOffset: false })]); - } else { - startAt = this.knex.raw(`?`, [time.toISO()]); - } + nextStartAt = this.nextRunAtRaw(time); + startAt ||= nextStartAt; } else { - startAt = this.knex.fn.now(); + startAt ||= this.knex.fn.now(); + nextStartAt = nowPlus(Duration.fromISO(settings.cadence), this.knex); } this.logger.debug(`task: ${this.taskId} configured to run at: ${startAt}`); @@ -206,7 +207,12 @@ export class TaskWorker { settings_json: settingsJson, next_run_start_at: this.knex.raw( `CASE WHEN ?? < ?? THEN ?? ELSE ?? END`, - [startAt, 'next_run_start_at', startAt, 'next_run_start_at'], + [ + nextStartAt, + 'next_run_start_at', + nextStartAt, + 'next_run_start_at', + ], ), } : { @@ -214,9 +220,9 @@ export class TaskWorker { next_run_start_at: this.knex.raw( `CASE WHEN ?? < ?? THEN ?? ELSE ?? END`, [ - 'excluded.next_run_start_at', + nextStartAt, `${DB_TASKS_TABLE}.next_run_start_at`, - 'excluded.next_run_start_at', + nextStartAt, `${DB_TASKS_TABLE}.next_run_start_at`, ], ), @@ -308,13 +314,7 @@ export class TaskWorker { const time = new CronTime(settings.cadence).sendAt().toUTC(); this.logger.debug(`task: ${this.taskId} will next occur around ${time}`); - if (this.knex.client.config.client.includes('sqlite3')) { - nextRun = this.knex.raw('datetime(?)', [time.toISO()]); - } else if (this.knex.client.config.client.includes('mysql')) { - nextRun = this.knex.raw(`?`, [time.toSQL({ includeOffset: false })]); - } else { - nextRun = this.knex.raw(`?`, [time.toISO()]); - } + nextRun = this.nextRunAtRaw(time); } else { const dt = Duration.fromISO(settings.cadence).as('seconds'); this.logger.debug( @@ -351,4 +351,13 @@ export class TaskWorker { return rows === 1; } + + private nextRunAtRaw(time: DateTime): Knex.Raw { + if (this.knex.client.config.client.includes('sqlite3')) { + return this.knex.raw('datetime(?)', [time.toISO()]); + } else if (this.knex.client.config.client.includes('mysql')) { + return this.knex.raw(`?`, [time.toSQL({ includeOffset: false })]); + } + return this.knex.raw(`?`, [time.toISO()]); + } } diff --git a/packages/backend-test-utils/CHANGELOG.md b/packages/backend-test-utils/CHANGELOG.md index a725f8037b..5bd1c6d498 100644 --- a/packages/backend-test-utils/CHANGELOG.md +++ b/packages/backend-test-utils/CHANGELOG.md @@ -1,5 +1,30 @@ # @backstage/backend-test-utils +## 0.2.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-app-api@0.5.5-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/config@1.1.0 + - @backstage/types@1.1.1 + +## 0.2.6-next.0 + +### Patch Changes + +- 5ddc03813e: Remove third type parameter used for `MockInstance`, in order to be compatible with older versions of `@types/jest`. +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-app-api@0.5.5-next.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/types@1.1.1 + ## 0.2.3 ### Patch Changes diff --git a/packages/backend-test-utils/api-report.md b/packages/backend-test-utils/api-report.md index 4a27ac21a9..a477f70298 100644 --- a/packages/backend-test-utils/api-report.md +++ b/packages/backend-test-utils/api-report.md @@ -4,6 +4,7 @@ ```ts /// <reference types="jest" /> +/// <reference types="node" /> import { Backend } from '@backstage/backend-app-api'; import { BackendFeature } from '@backstage/backend-plugin-api'; @@ -30,9 +31,44 @@ import { ServiceRef } from '@backstage/backend-plugin-api'; import { TokenManagerService } from '@backstage/backend-plugin-api'; import { UrlReaderService } from '@backstage/backend-plugin-api'; +// @public +export function createMockDirectory( + options?: MockDirectoryOptions, +): MockDirectory; + // @public (undocumented) export function isDockerDisabledForTests(): boolean; +// @public +export interface MockDirectory { + addContent(root: MockDirectoryContent): void; + clear(): void; + content( + options?: MockDirectoryContentOptions, + ): MockDirectoryContent | undefined; + readonly path: string; + remove(): void; + resolve(...paths: string[]): string; + setContent(root: MockDirectoryContent): void; +} + +// @public +export type MockDirectoryContent = { + [name in string]: MockDirectoryContent | string | Buffer; +}; + +// @public +export interface MockDirectoryContentOptions { + path?: string; + shouldReadAsText?: boolean | ((path: string, buffer: Buffer) => boolean); +} + +// @public +export interface MockDirectoryOptions { + content?: MockDirectoryContent; + mockOsTmpDir?: boolean; +} + // @public (undocumented) export namespace mockServices { // (undocumented) diff --git a/packages/backend-test-utils/package.json b/packages/backend-test-utils/package.json index 8777439e64..691f0a921b 100644 --- a/packages/backend-test-utils/package.json +++ b/packages/backend-test-utils/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-test-utils", "description": "Test helpers library for Backstage backends", - "version": "0.2.3", + "version": "0.2.6-next.1", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { @@ -46,15 +46,18 @@ "@backstage/backend-common": "workspace:^", "@backstage/backend-plugin-api": "workspace:^", "@backstage/config": "workspace:^", + "@backstage/errors": "workspace:^", "@backstage/plugin-auth-node": "workspace:^", "@backstage/types": "workspace:^", "better-sqlite3": "^8.0.0", "express": "^4.17.1", + "fs-extra": "^10.0.1", "knex": "^2.0.0", "msw": "^1.0.0", "mysql2": "^2.2.5", "pg": "^8.3.0", "testcontainers": "^8.1.2", + "textextensions": "^5.16.0", "uuid": "^8.0.0" }, "peerDependencies": { diff --git a/packages/backend-test-utils/src/filesystem/MockDirectory.test.ts b/packages/backend-test-utils/src/filesystem/MockDirectory.test.ts new file mode 100644 index 0000000000..9e3efdaec0 --- /dev/null +++ b/packages/backend-test-utils/src/filesystem/MockDirectory.test.ts @@ -0,0 +1,293 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import fs from 'fs-extra'; +import os from 'os'; +import { join as joinPath, relative as relativePath } from 'path'; +import { createMockDirectory, MockDirectory } from './MockDirectory'; + +describe('createMockDirectory', () => { + const mockDir = createMockDirectory(); + + beforeEach(mockDir.clear); + + it('should resolve paths', () => { + expect(mockDir.path).toEqual(expect.any(String)); + expect(relativePath(mockDir.path, mockDir.resolve('a'))).toBe('a'); + expect(relativePath(mockDir.path, mockDir.resolve('a/b/c'))).toBe( + joinPath('a', 'b', 'c'), + ); + }); + + it('should remove itself', async () => { + await expect(fs.pathExists(mockDir.path)).resolves.toBe(true); + mockDir.remove(); + await expect(fs.pathExists(mockDir.path)).resolves.toBe(false); + }); + + it('should populate a directory with text files', () => { + mockDir.setContent({ + 'a.txt': 'a', + 'a/b.txt': 'b', + 'a/b/c.txt': 'c', + 'a/b/d.txt': 'd', + }); + + expect(mockDir.content()).toEqual({ + 'a.txt': 'a', + a: { + 'b.txt': 'b', + b: { + 'c.txt': 'c', + 'd.txt': 'd', + }, + }, + }); + }); + + it('should mix text and binary files', () => { + mockDir.setContent({ + 'a.txt': 'a', + 'a/b.txt': 'b', + 'a/b/c.bin': Buffer.from([0xc]), + 'a/b/d.bin': Buffer.from([0xd]), + }); + + expect(mockDir.content()).toEqual({ + 'a.txt': 'a', + a: { + 'b.txt': 'b', + b: { + 'c.bin': Buffer.from([0xc]), + 'd.bin': Buffer.from([0xd]), + }, + }, + }); + }); + + it('should be able to add content', () => { + mockDir.setContent({ + 'a.txt': 'a', + b: {}, + }); + + expect(mockDir.content()).toEqual({ + 'a.txt': 'a', + b: {}, + }); + + mockDir.addContent({ + 'b.txt': 'b', + b: { + 'c.txt': 'c', + }, + }); + + expect(mockDir.content()).toEqual({ + 'a.txt': 'a', + 'b.txt': 'b', + b: { + 'c.txt': 'c', + }, + }); + }); + + it('should replace existing files', () => { + mockDir.setContent({ + 'a.txt': 'a', + }); + + mockDir.addContent({ + 'a.txt': 'a2', + }); + + expect(mockDir.content()).toEqual({ + 'a.txt': 'a2', + }); + }); + + it('should read content from sub dirs', () => { + mockDir.setContent({ + 'a.txt': 'a', + 'b/b.txt': 'b', + 'b/c/c.txt': 'c', + }); + + const expected = { + 'a.txt': 'a', + b: { + 'b.txt': 'b', + c: { + 'c.txt': 'c', + }, + }, + }; + + expect(mockDir.content()).toEqual(expected); + expect(mockDir.content({ path: mockDir.path })).toEqual(expected); + expect(mockDir.content({ path: mockDir.resolve('.') })).toEqual(expected); + expect(mockDir.content({ path: 'b' })).toEqual(expected.b); + expect(mockDir.content({ path: './b' })).toEqual(expected.b); + expect(mockDir.content({ path: mockDir.resolve('b') })).toEqual(expected.b); + expect(mockDir.content({ path: 'b/c' })).toEqual(expected.b.c); + expect(mockDir.content({ path: './b/c' })).toEqual(expected.b.c); + expect(mockDir.content({ path: mockDir.resolve('b/c') })).toEqual( + expected.b.c, + ); + expect(mockDir.content({ path: mockDir.resolve('b', 'c') })).toEqual( + expected.b.c, + ); + }); + + it('should allow text reading to be configured', () => { + const text = 'a'; + const binary = Buffer.from('a', 'utf8'); + + mockDir.setContent({ + a: binary, + 'a.txt': text, + 'a.bin': binary, + }); + + expect(mockDir.content()).toEqual({ + a: binary, + 'a.txt': text, + 'a.bin': binary, + }); + + expect(mockDir.content({ shouldReadAsText: false })).toEqual({ + a: binary, + 'a.txt': binary, + 'a.bin': binary, + }); + + expect(mockDir.content({ shouldReadAsText: true })).toEqual({ + a: text, + 'a.txt': text, + 'a.bin': text, + }); + + expect( + mockDir.content({ shouldReadAsText: path => path.length > 3 }), + ).toEqual({ + a: binary, + 'a.txt': text, + 'a.bin': text, + }); + }); + + it('should provide a posix path to shouldReadAsText', () => { + const shouldReadAsText = jest.fn().mockReturnValue(true); + + mockDir.setContent({ 'a/b/c': 'c' }); + + expect(mockDir.content({ shouldReadAsText })).toEqual({ + a: { b: { c: 'c' } }, + }); + expect(shouldReadAsText).toHaveBeenCalledWith( + 'a/b/c', + Buffer.from('c', 'utf8'), + ); + }); + + it('should not override directories', () => { + mockDir.setContent({ + 'a.txt': 'a', + b: {}, + }); + + expect(() => + mockDir.addContent({ + 'a.txt': {}, + }), + ).toThrow('EEXIST'); + + expect(() => + mockDir.addContent({ + b: 'b', + }), + ).toThrow('EISDIR'); + }); + + it('examples should work', () => { + mockDir.setContent({ + 'test.txt': 'content', + 'sub-dir': { + 'file.txt': 'content', + 'nested-dir/file.txt': 'content', + }, + 'empty-dir': {}, + 'binary-file': Buffer.from([0, 1, 2]), + }); + + mockDir.addContent({ + 'test.txt': 'content', + 'sub-dir': { + 'file.txt': 'content', + 'nested-dir/file.txt': 'content', + }, + 'empty-dir': {}, + 'binary-file': Buffer.from([0, 1, 2]), + }); + + expect(mockDir.content()).toEqual({ + 'test.txt': 'content', + 'sub-dir': { + 'file.txt': 'content', + 'nested-dir': { + 'file.txt': 'content', + }, + }, + 'empty-dir': {}, + 'binary-file': Buffer.from([0, 1, 2]), + }); + }); + + it('should reject non-child paths', () => { + const path = mockDir.resolve('/root/a.txt'); + expect(() => mockDir.setContent({ '/root/a.txt': 'a' })).toThrow( + `Provided path must resolve to a child path of the mock directory, got '${path}'`, + ); + expect(() => mockDir.addContent({ '/root/a.txt': 'a' })).toThrow( + `Provided path must resolve to a child path of the mock directory, got '${path}'`, + ); + expect(() => mockDir.content({ path: '/root/a.txt' })).toThrow( + `Provided path must resolve to a child path of the mock directory, got '${path}'`, + ); + }); + + describe('tmpdir mock', () => { + let tmpDirMock: MockDirectory; + + describe('inner', () => { + tmpDirMock = createMockDirectory({ mockOsTmpDir: true }); + + it('should mock os.tmpdir()', () => { + expect(os.tmpdir()).toBe(tmpDirMock.path); + }); + + it('should refuce to mock os.tmpdir() again', () => { + expect(() => createMockDirectory({ mockOsTmpDir: true })).toThrow( + 'Cannot mock os.tmpdir() when it has already been mocked', + ); + }); + }); + + it('should restore os.tmpdir()', () => { + expect(os.tmpdir()).not.toBe(tmpDirMock.path); + }); + }); +}); diff --git a/packages/backend-test-utils/src/filesystem/MockDirectory.ts b/packages/backend-test-utils/src/filesystem/MockDirectory.ts new file mode 100644 index 0000000000..20345e4ff9 --- /dev/null +++ b/packages/backend-test-utils/src/filesystem/MockDirectory.ts @@ -0,0 +1,391 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import os from 'os'; +import { isChildPath } from '@backstage/backend-common'; +import fs from 'fs-extra'; +import textextensions from 'textextensions'; +import { + dirname, + extname, + join as joinPath, + resolve as resolvePath, + relative as relativePath, + win32, + posix, +} from 'path'; + +const tmpdirMarker = Symbol('os-tmpdir-mock'); + +/** + * The content of a mock directory represented by a nested object structure. + * + * @remarks + * + * When used as input, the keys may contain forward slashes to indicate nested directories. + * Then returned as output, each directory will always be represented as a separate object. + * + * @example + * ```ts + * { + * 'test.txt': 'content', + * 'sub-dir': { + * 'file.txt': 'content', + * 'nested-dir/file.txt': 'content', + * }, + * 'empty-dir': {}, + * 'binary-file': Buffer.from([0, 1, 2]), + * } + * ``` + * + * @public + */ +export type MockDirectoryContent = { + [name in string]: MockDirectoryContent | string | Buffer; +}; + +/** + * Options for {@link MockDirectory.content}. + * + * @public + */ +export interface MockDirectoryContentOptions { + /** + * The path to read content from. Defaults to the root of the mock directory. + * + * An absolute path can also be provided, as long as it is a child path of the mock directory. + */ + path?: string; + + /** + * Whether or not to return files as text rather than buffers. + * + * Defaults to checking the file extension against a list of known text extensions. + */ + shouldReadAsText?: boolean | ((path: string, buffer: Buffer) => boolean); +} + +/** + * A utility for creating a mock directory that is automatically cleaned up. + * + * @public + */ +export interface MockDirectory { + /** + * The path to the root of the mock directory + */ + readonly path: string; + + /** + * Resolves a path relative to the root of the mock directory. + */ + resolve(...paths: string[]): string; + + /** + * Sets the content of the mock directory. This will remove any existing content. + * + * @example + * ```ts + * mockDir.setContent({ + * 'test.txt': 'content', + * 'sub-dir': { + * 'file.txt': 'content', + * 'nested-dir/file.txt': 'content', + * }, + * 'empty-dir': {}, + * 'binary-file': Buffer.from([0, 1, 2]), + * }); + * ``` + */ + setContent(root: MockDirectoryContent): void; + + /** + * Adds content of the mock directory. This will overwrite existing files. + * + * @example + * ```ts + * mockDir.addContent({ + * 'test.txt': 'content', + * 'sub-dir': { + * 'file.txt': 'content', + * 'nested-dir/file.txt': 'content', + * }, + * 'empty-dir': {}, + * 'binary-file': Buffer.from([0, 1, 2]), + * }); + * ``` + */ + addContent(root: MockDirectoryContent): void; + + /** + * Reads the content of the mock directory. + * + * @remarks + * + * Text files will be returned as strings, while binary files will be returned as buffers. + * By default the file extension is used to determine whether a file should be read as text. + * + * @example + * ```ts + * expect(mockDir.content()).toEqual({ + * 'test.txt': 'content', + * 'sub-dir': { + * 'file.txt': 'content', + * 'nested-dir': { + * 'file.txt': 'content', + * }, + * }, + * 'empty-dir': {}, + * 'binary-file': Buffer.from([0, 1, 2]), + * }); + * ``` + */ + content( + options?: MockDirectoryContentOptions, + ): MockDirectoryContent | undefined; + + /** + * Clears the content of the mock directory, ensuring that the directory itself exists. + */ + clear(): void; + + /** + * Removes the mock directory and all its contents. + */ + remove(): void; +} + +/** @internal */ +type MockEntry = + | { + type: 'file'; + path: string; + content: Buffer; + } + | { + type: 'dir'; + path: string; + }; + +/** @internal */ +class MockDirectoryImpl { + readonly #root: string; + + constructor(root: string) { + this.#root = root; + } + + get path(): string { + return this.#root; + } + + resolve(...paths: string[]): string { + return resolvePath(this.#root, ...paths); + } + + setContent(root: MockDirectoryContent): void { + this.remove(); + + return this.addContent(root); + } + + addContent(root: MockDirectoryContent): void { + const entries = this.#transformInput(root); + + for (const entry of entries) { + const fullPath = resolvePath(this.#root, entry.path); + if (!isChildPath(this.#root, fullPath)) { + throw new Error( + `Provided path must resolve to a child path of the mock directory, got '${fullPath}'`, + ); + } + + if (entry.type === 'dir') { + fs.ensureDirSync(fullPath, { mode: 0o777 }); + } else if (entry.type === 'file') { + fs.ensureDirSync(dirname(fullPath), { mode: 0o777 }); + fs.writeFileSync(fullPath, entry.content, { mode: 0o666 }); + } + } + } + + content( + options?: MockDirectoryContentOptions, + ): MockDirectoryContent | undefined { + const shouldReadAsText = + (typeof options?.shouldReadAsText === 'boolean' + ? () => options?.shouldReadAsText + : options?.shouldReadAsText) ?? + ((path: string) => textextensions.includes(extname(path).slice(1))); + + const root = resolvePath(this.#root, options?.path ?? ''); + if (!isChildPath(this.#root, root)) { + throw new Error( + `Provided path must resolve to a child path of the mock directory, got '${root}'`, + ); + } + + function read(path: string): MockDirectoryContent | undefined { + if (!fs.pathExistsSync(path)) { + return undefined; + } + + const entries = fs.readdirSync(path, { withFileTypes: true }); + return Object.fromEntries( + entries.map(entry => { + const fullPath = resolvePath(path, entry.name); + + if (entry.isDirectory()) { + return [entry.name, read(fullPath)]; + } + const content = fs.readFileSync(fullPath); + const relativePosixPath = relativePath(root, fullPath) + .split(win32.sep) + .join(posix.sep); + + if (shouldReadAsText(relativePosixPath, content)) { + return [entry.name, content.toString('utf8')]; + } + return [entry.name, content]; + }), + ); + } + + return read(root); + } + + clear = (): void => { + this.setContent({}); + }; + + remove = (): void => { + fs.removeSync(this.#root); + }; + + #transformInput(input: MockDirectoryContent[string]): MockEntry[] { + const entries: MockEntry[] = []; + + function traverse(node: MockDirectoryContent[string], path: string) { + const trimmedPath = path.startsWith('/') ? path.slice(1) : path; // trim leading slash + if (typeof node === 'string') { + entries.push({ + type: 'file', + path: trimmedPath, + content: Buffer.from(node, 'utf8'), + }); + } else if (node instanceof Buffer) { + entries.push({ type: 'file', path: trimmedPath, content: node }); + } else { + entries.push({ type: 'dir', path: trimmedPath }); + for (const [name, child] of Object.entries(node)) { + traverse(child, `${trimmedPath}/${name}`); + } + } + } + + traverse(input, ''); + + return entries; + } +} + +/** + * Options for {@link createMockDirectory}. + * + * @public + */ +export interface MockDirectoryOptions { + /** + * In addition to creating a temporary directory, also mock `os.tmpdir()` to return the + * mock directory path until the end of the test suite. + * + * @returns + */ + mockOsTmpDir?: boolean; + + /** + * Initializes the directory with the given content, see {@link MockDirectory.setContent}. + */ + content?: MockDirectoryContent; +} + +/** + * Creates a new temporary mock directory that will be removed after the tests have completed. + * + * @public + * @remarks + * + * This method is intended to be called outside of any test, either at top-level or + * within a `describe` block. It will call `afterAll` to make sure that the mock directory + * is removed after the tests have run. + * + * @example + * ```ts + * describe('MySubject', () => { + * const mockDir = createMockDirectory(); + * + * beforeEach(mockDir.clear); + * + * it('should work', () => { + * // ... use mockDir + * }) + * }) + * ``` + */ +export function createMockDirectory( + options?: MockDirectoryOptions, +): MockDirectory { + const tmpDir = process.env.RUNNER_TEMP || os.tmpdir(); // GitHub Actions + const root = fs.mkdtempSync(joinPath(tmpDir, 'backstage-tmp-test-dir-')); + + const mocker = new MockDirectoryImpl(root); + + const origTmpdir = options?.mockOsTmpDir ? os.tmpdir : undefined; + if (origTmpdir) { + if (Object.hasOwn(origTmpdir, tmpdirMarker)) { + throw new Error( + 'Cannot mock os.tmpdir() when it has already been mocked', + ); + } + const mock = Object.assign(() => mocker.path, { [tmpdirMarker]: true }); + os.tmpdir = mock; + } + + // In CI we expect there to be no need to clean up temporary directories + const needsCleanup = !process.env.CI; + if (needsCleanup) { + process.on('beforeExit', mocker.remove); + } + + try { + afterAll(() => { + if (origTmpdir) { + os.tmpdir = origTmpdir; + } + if (needsCleanup) { + mocker.remove(); + } + }); + } catch { + /* ignore */ + } + + if (options?.content) { + mocker.setContent(options.content); + } + + return mocker; +} diff --git a/packages/core-plugin-api/src/plugin-options/index.ts b/packages/backend-test-utils/src/filesystem/index.ts similarity index 72% rename from packages/core-plugin-api/src/plugin-options/index.ts rename to packages/backend-test-utils/src/filesystem/index.ts index 1737a1c836..0a4d8c7d00 100644 --- a/packages/core-plugin-api/src/plugin-options/index.ts +++ b/packages/backend-test-utils/src/filesystem/index.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Backstage Authors + * Copyright 2023 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,5 +14,10 @@ * limitations under the License. */ -export { usePluginOptions, PluginProvider } from './usePluginOptions'; -export type { PluginOptionsProviderProps } from './usePluginOptions'; +export { + createMockDirectory, + type MockDirectory, + type MockDirectoryOptions, + type MockDirectoryContent, + type MockDirectoryContentOptions, +} from './MockDirectory'; diff --git a/packages/backend-test-utils/src/index.ts b/packages/backend-test-utils/src/index.ts index ae937d2fc8..ff1f2ee460 100644 --- a/packages/backend-test-utils/src/index.ts +++ b/packages/backend-test-utils/src/index.ts @@ -22,5 +22,6 @@ export * from './database'; export * from './msw'; +export * from './filesystem'; export * from './next'; export * from './util'; diff --git a/packages/backend-test-utils/src/next/wiring/TestBackend.ts b/packages/backend-test-utils/src/next/wiring/TestBackend.ts index 59b5906eb4..21ae6159c9 100644 --- a/packages/backend-test-utils/src/next/wiring/TestBackend.ts +++ b/packages/backend-test-utils/src/next/wiring/TestBackend.ts @@ -20,9 +20,9 @@ import { MiddlewareFactory, createHttpServer, ExtendedHttpServer, + HostDiscovery, DefaultRootHttpRouter, } from '@backstage/backend-app-api'; -import { HostDiscovery } from '@backstage/backend-common'; import { createServiceFactory, BackendFeature, diff --git a/packages/backend/CHANGELOG.md b/packages/backend/CHANGELOG.md index 880eb33270..07105a0417 100644 --- a/packages/backend/CHANGELOG.md +++ b/packages/backend/CHANGELOG.md @@ -1,5 +1,123 @@ # example-backend +## 0.2.88-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-backend@1.14.0-next.1 + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/plugin-scaffolder-backend@1.18.0-next.1 + - @backstage/plugin-badges-backend@0.3.2-next.1 + - @backstage/plugin-lighthouse-backend@0.3.2-next.1 + - @backstage/plugin-linguist-backend@0.5.2-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.9-next.1 + - @backstage/plugin-search-backend-module-explore@0.1.9-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.9-next.1 + - @backstage/plugin-search-backend-node@1.2.9-next.1 + - @backstage/plugin-tech-insights-backend@0.5.19-next.1 + - @backstage/plugin-tech-insights-node@0.4.11-next.1 + - example-app@0.2.88-next.1 + - @backstage/plugin-auth-backend@0.19.2-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.2-next.1 + - @backstage/plugin-kubernetes-backend@0.12.2-next.1 + - @backstage/plugin-todo-backend@0.3.3-next.1 + - @backstage/plugin-adr-backend@0.4.2-next.1 + - @backstage/plugin-app-backend@0.3.53-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/plugin-azure-devops-backend@0.4.2-next.1 + - @backstage/plugin-azure-sites-backend@0.1.15-next.1 + - @backstage/plugin-code-coverage-backend@0.2.19-next.1 + - @backstage/plugin-devtools-backend@0.2.2-next.1 + - @backstage/plugin-entity-feedback-backend@0.2.2-next.1 + - @backstage/plugin-events-backend@0.2.14-next.1 + - @backstage/plugin-explore-backend@0.0.15-next.1 + - @backstage/plugin-graphql-backend@0.1.43-next.1 + - @backstage/plugin-jenkins-backend@0.2.8-next.1 + - @backstage/plugin-kafka-backend@0.3.2-next.1 + - @backstage/plugin-nomad-backend@0.1.7-next.1 + - @backstage/plugin-permission-backend@0.5.28-next.1 + - @backstage/plugin-permission-node@0.7.16-next.1 + - @backstage/plugin-playlist-backend@0.3.9-next.1 + - @backstage/plugin-proxy-backend@0.4.2-next.1 + - @backstage/plugin-rollbar-backend@0.1.50-next.1 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.6-next.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.22-next.1 + - @backstage/plugin-search-backend@1.4.5-next.1 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.8-next.1 + - @backstage/plugin-search-backend-module-pg@0.5.14-next.1 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.37-next.1 + - @backstage/plugin-techdocs-backend@1.7.2-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.2-next.1 + - @backstage/plugin-events-node@0.2.14-next.1 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-search-common@1.2.6 + +## 0.2.88-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-backend-module-elasticsearch@1.3.8-next.0 + - @backstage/integration@1.7.1-next.0 + - @backstage/plugin-playlist-backend@0.3.9-next.0 + - @backstage/plugin-rollbar-backend@0.1.50-next.0 + - @backstage/plugin-catalog-backend@1.14.0-next.0 + - @backstage/plugin-tech-insights-backend@0.5.19-next.0 + - @backstage/plugin-code-coverage-backend@0.2.19-next.0 + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.22-next.0 + - @backstage/backend-common@0.19.7-next.0 + - example-app@0.2.88-next.0 + - @backstage/plugin-adr-backend@0.4.2-next.0 + - @backstage/plugin-scaffolder-backend@1.17.3-next.0 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.6-next.0 + - @backstage/plugin-techdocs-backend@1.7.2-next.0 + - @backstage/plugin-todo-backend@0.3.3-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/plugin-app-backend@0.3.53-next.0 + - @backstage/plugin-auth-backend@0.19.2-next.0 + - @backstage/plugin-azure-devops-backend@0.4.2-next.0 + - @backstage/plugin-azure-sites-backend@0.1.15-next.0 + - @backstage/plugin-badges-backend@0.3.2-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.2-next.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.2-next.0 + - @backstage/plugin-catalog-node@1.4.6-next.0 + - @backstage/plugin-devtools-backend@0.2.2-next.0 + - @backstage/plugin-entity-feedback-backend@0.2.2-next.0 + - @backstage/plugin-events-backend@0.2.14-next.0 + - @backstage/plugin-events-node@0.2.14-next.0 + - @backstage/plugin-explore-backend@0.0.15-next.0 + - @backstage/plugin-graphql-backend@0.1.43-next.0 + - @backstage/plugin-jenkins-backend@0.2.8-next.0 + - @backstage/plugin-kafka-backend@0.3.2-next.0 + - @backstage/plugin-kubernetes-backend@0.12.2-next.0 + - @backstage/plugin-lighthouse-backend@0.3.2-next.0 + - @backstage/plugin-linguist-backend@0.5.2-next.0 + - @backstage/plugin-nomad-backend@0.1.7-next.0 + - @backstage/plugin-permission-backend@0.5.28-next.0 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-permission-node@0.7.16-next.0 + - @backstage/plugin-proxy-backend@0.4.2-next.0 + - @backstage/plugin-search-backend@1.4.5-next.0 + - @backstage/plugin-search-backend-module-catalog@0.1.9-next.0 + - @backstage/plugin-search-backend-module-explore@0.1.9-next.0 + - @backstage/plugin-search-backend-module-pg@0.5.14-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.1.9-next.0 + - @backstage/plugin-search-backend-node@1.2.9-next.0 + - @backstage/plugin-search-common@1.2.6 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.37-next.0 + - @backstage/plugin-tech-insights-node@0.4.11-next.0 + ## 0.2.87 ### Patch Changes diff --git a/packages/backend/Dockerfile b/packages/backend/Dockerfile index 24ede0e866..5667209330 100644 --- a/packages/backend/Dockerfile +++ b/packages/backend/Dockerfile @@ -9,7 +9,7 @@ # # Once the commands have been run, you can build the image using `yarn build-image` -FROM node:18-bullseye-slim +FROM node:18-bookworm-slim # Install sqlite3 dependencies. You can skip this if you don't use sqlite3 in the image, # in which case you should also move better-sqlite3 to "devDependencies" in package.json. @@ -18,9 +18,15 @@ FROM node:18-bullseye-slim RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ --mount=type=cache,target=/var/lib/apt,sharing=locked \ apt-get update && \ - apt-get install -y --no-install-recommends libsqlite3-dev python3 python3-pip build-essential && \ - yarn config set python /usr/bin/python3 && \ - pip3 install mkdocs-techdocs-core==1.1.7 + apt-get install -y --no-install-recommends libsqlite3-dev python3 python3-pip python3-venv build-essential && \ + yarn config set python /usr/bin/python3 + +# Set up a virtual environment for mkdocs-techdocs-core. +ENV VIRTUAL_ENV=/opt/venv +RUN python3 -m venv $VIRTUAL_ENV +ENV PATH="$VIRTUAL_ENV/bin:$PATH" + +RUN pip3 install mkdocs-techdocs-core==1.1.7 # From here on we use the least-privileged `node` user to run the backend. WORKDIR /app diff --git a/packages/backend/package.json b/packages/backend/package.json index 362f0d1201..8519a5ed71 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -1,6 +1,6 @@ { "name": "example-backend", - "version": "0.2.87", + "version": "0.2.88-next.1", "main": "dist/index.cjs.js", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/cli-common/CHANGELOG.md b/packages/cli-common/CHANGELOG.md index bb6e2756a0..30b9670251 100644 --- a/packages/cli-common/CHANGELOG.md +++ b/packages/cli-common/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/cli-common +## 0.1.13-next.0 + +### Patch Changes + +- de42eebaaf: Bumped dev dependencies `@types/node` and `mock-fs`. + ## 0.1.12 ### Patch Changes diff --git a/packages/cli-common/package.json b/packages/cli-common/package.json index 55e6e1f792..8aed6881e2 100644 --- a/packages/cli-common/package.json +++ b/packages/cli-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/cli-common", "description": "Common functionality used by cli, backend, and create-app", - "version": "0.1.12", + "version": "0.1.13-next.0", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/cli-node/CHANGELOG.md b/packages/cli-node/CHANGELOG.md index 153bf1a5af..ab16a5d036 100644 --- a/packages/cli-node/CHANGELOG.md +++ b/packages/cli-node/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/cli-node +## 0.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/cli-common@0.1.13-next.0 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + ## 0.1.4 ### Patch Changes diff --git a/packages/cli-node/package.json b/packages/cli-node/package.json index 95c69284eb..a1062c2783 100644 --- a/packages/cli-node/package.json +++ b/packages/cli-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/cli-node", "description": "Node.js library for Backstage CLIs", - "version": "0.1.4", + "version": "0.1.5-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index 3e97228116..d9d7c426e3 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,5 +1,48 @@ # @backstage/cli +## 0.23.0-next.1 + +### Patch Changes + +- d0f26cfa4f: Fixed an issue where the new backend start command would not gracefully shut down the backend process on Windows. +- Updated dependencies + - @backstage/config@1.1.0 + - @backstage/release-manifests@0.0.10 + - @backstage/catalog-model@1.4.2 + - @backstage/cli-common@0.1.13-next.0 + - @backstage/cli-node@0.1.5-next.0 + - @backstage/config-loader@1.5.1-next.0 + - @backstage/errors@1.2.2 + - @backstage/eslint-plugin@0.1.3 + - @backstage/integration@1.7.1-next.0 + - @backstage/types@1.1.1 + +## 0.23.0-next.0 + +### Minor Changes + +- 7077dbf131: The new backend start command that used to be enabled by setting `EXPERIMENTAL_BACKEND_START` is now the default. To revert to the old behavior, set `LEGACY_BACKEND_START` instead. + + This new command is no longer based on Webpack, but instead uses Node.js loaders to transpile on the fly. Rather than hot reloading modules the entire backend is now restarted on change, but the SQLite database state is still maintained across restarts via a parent process. + +### Patch Changes + +- 68158034e8: Fix for the new backend `start` command to make it work on Windows. +- 21cd3b1b24: Added a template for creating `node-library` packages with `yarn new`. +- de42eebaaf: Bumped dev dependencies `@types/node` and `mock-fs`. +- 3ef18f8c06: Explicitly set `exports: 'named'` for CJS builds, ensuring that they have e.g. `exports["default"] = catalogPlugin;` +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/config-loader@1.5.1-next.0 + - @backstage/cli-common@0.1.13-next.0 + - @backstage/config@1.1.0 + - @backstage/release-manifests@0.0.10 + - @backstage/catalog-model@1.4.2 + - @backstage/cli-node@0.1.5-next.0 + - @backstage/errors@1.2.2 + - @backstage/eslint-plugin@0.1.3 + - @backstage/types@1.1.1 + ## 0.22.13 ### Patch Changes diff --git a/packages/cli/package.json b/packages/cli/package.json index 45d7c8468d..ee1eb52a2c 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.22.13", + "version": "0.23.0-next.1", "publishConfig": { "access": "public" }, @@ -78,6 +78,7 @@ "cross-fetch": "^3.1.5", "cross-spawn": "^7.0.3", "css-loader": "^6.5.1", + "ctrlc-windows": "^2.1.0", "diff": "^5.0.0", "esbuild": "^0.19.0", "esbuild-loader": "^2.18.0", diff --git a/packages/cli/src/commands/start/startBackend.ts b/packages/cli/src/commands/start/startBackend.ts index 622eeb9d1b..967a1108a0 100644 --- a/packages/cli/src/commands/start/startBackend.ts +++ b/packages/cli/src/commands/start/startBackend.ts @@ -36,7 +36,7 @@ export async function startBackend(options: StartBackendOptions) { }); await waitForExit(); - } else if (process.env.EXPERIMENTAL_BACKEND_START) { + } else if (!process.env.LEGACY_BACKEND_START) { const waitForExit = await startBackendExperimental({ entry: 'src/index', checksEnabled: false, // not supported diff --git a/packages/cli/src/lib/experimental/startBackendExperimental.ts b/packages/cli/src/lib/experimental/startBackendExperimental.ts index 3bc603a9da..578fd1c747 100644 --- a/packages/cli/src/lib/experimental/startBackendExperimental.ts +++ b/packages/cli/src/lib/experimental/startBackendExperimental.ts @@ -18,10 +18,11 @@ import { FSWatcher, watch } from 'chokidar'; import { BackendServeOptions } from '../bundler/types'; import type { ChildProcess } from 'child_process'; +import { ctrlc } from 'ctrlc-windows'; import { IpcServer } from './IpcServer'; import { ServerDataStore } from './ServerDataStore'; import debounce from 'lodash/debounce'; -import { fileURLToPath } from 'url'; +import { fileURLToPath, pathToFileURL } from 'url'; import { isAbsolute as isAbsolutePath } from 'path'; import { paths } from '../paths'; import spawn from 'cross-spawn'; @@ -30,7 +31,7 @@ const loaderArgs = [ '--require', require.resolve('@esbuild-kit/cjs-loader'), '--loader', - require.resolve('@esbuild-kit/esm-loader'), + pathToFileURL(require.resolve('@esbuild-kit/esm-loader')).toString(), // Windows prefers a URL here ]; export async function startBackendExperimental(options: BackendServeOptions) { @@ -57,7 +58,11 @@ export async function startBackendExperimental(options: BackendServeOptions) { if (child && !child.killed && child.exitCode === null) { // We always wait for the existing process to exit, to make sure we don't get IPC conflicts shutdownPromise = new Promise(resolve => child!.once('exit', resolve)); - child.kill(); + if (process.platform === 'win32' && child.pid) { + ctrlc(child.pid); + } else { + child.kill(); + } await shutdownPromise; shutdownPromise = undefined; } diff --git a/packages/codemods/CHANGELOG.md b/packages/codemods/CHANGELOG.md index 9bb738e4e8..7db642945f 100644 --- a/packages/codemods/CHANGELOG.md +++ b/packages/codemods/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/codemods +## 0.1.46-next.0 + +### Patch Changes + +- de42eebaaf: Bumped dev dependencies `@types/node` and `mock-fs`. +- Updated dependencies + - @backstage/cli-common@0.1.13-next.0 + ## 0.1.45 ### Patch Changes diff --git a/packages/codemods/package.json b/packages/codemods/package.json index 484127928a..34f4b5d748 100644 --- a/packages/codemods/package.json +++ b/packages/codemods/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/codemods", "description": "A collection of codemods for Backstage projects", - "version": "0.1.45", + "version": "0.1.46-next.0", "publishConfig": { "access": "public", "main": "dist/index.cjs.js" diff --git a/packages/config-loader/CHANGELOG.md b/packages/config-loader/CHANGELOG.md index 625ee8c36e..1ee39cb9c6 100644 --- a/packages/config-loader/CHANGELOG.md +++ b/packages/config-loader/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/config-loader +## 1.5.1-next.0 + +### Patch Changes + +- 773ea341d2: The `FileConfigSource` will now retry file reading after a short delay if it reads an empty file. This is to avoid flakiness during watch mode where change events can trigger before the file content has been written. +- Updated dependencies + - @backstage/cli-common@0.1.13-next.0 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + ## 1.5.0 ### Minor Changes diff --git a/packages/config-loader/package.json b/packages/config-loader/package.json index 51c7d4a599..fb17d00378 100644 --- a/packages/config-loader/package.json +++ b/packages/config-loader/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/config-loader", "description": "Config loading functionality used by Backstage backend, and CLI", - "version": "1.5.0", + "version": "1.5.1-next.0", "publishConfig": { "access": "public", "main": "dist/index.cjs.js", diff --git a/packages/config-loader/src/sources/FileConfigSource.ts b/packages/config-loader/src/sources/FileConfigSource.ts index da31c128a0..1de0fbf2d8 100644 --- a/packages/config-loader/src/sources/FileConfigSource.ts +++ b/packages/config-loader/src/sources/FileConfigSource.ts @@ -47,7 +47,15 @@ export interface FileConfigSourceOptions { async function readFile(path: string): Promise<string | undefined> { try { - return await fs.readFile(path, 'utf8'); + const content = await fs.readFile(path, 'utf8'); + // During watching we may sometimes read files too early before the file content has been written. + // We never expect the writing to take a long time, but if we encounter an empty file then check + // again after a short delay for safety. + if (content === '') { + await new Promise(resolve => setTimeout(resolve, 10)); + return await fs.readFile(path, 'utf8'); + } + return content; } catch (error) { if (error.code === 'ENOENT') { return undefined; diff --git a/packages/core-app-api/CHANGELOG.md b/packages/core-app-api/CHANGELOG.md index 48241f0d22..20c6013ee0 100644 --- a/packages/core-app-api/CHANGELOG.md +++ b/packages/core-app-api/CHANGELOG.md @@ -1,5 +1,26 @@ # @backstage/core-app-api +## 1.10.1-next.1 + +### Patch Changes + +- 1a0616fa10: Add missing resource and template app icons +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.5 + +## 1.10.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.5 + ## 1.10.0 ### Minor Changes @@ -194,7 +215,7 @@ ### Minor Changes -- 7908d72e033: Introduce a new global config parameter, `auth.enableExperimentalRedirectFlow`. When enabled, auth will happen with an in-window redirect flow rather than through a popup window. +- 7908d72e033: Introduce a new global config parameter, `enableExperimentalRedirectFlow`. When enabled, auth will happen with an in-window redirect flow rather than through a popup window. - c15e0cedbe1: The `AuthConnector` interface now supports specifying a set of scopes when refreshing a session. The `DefaultAuthConnector` implementation passes the `scope` query parameter to the auth-backend plugin appropriately. The @@ -255,7 +276,7 @@ ### Minor Changes -- 7908d72e033: Introduce a new global config parameter, `auth.enableExperimentalRedirectFlow`. When enabled, auth will happen with an in-window redirect flow rather than through a popup window. +- 7908d72e033: Introduce a new global config parameter, `enableExperimentalRedirectFlow`. When enabled, auth will happen with an in-window redirect flow rather than through a popup window. ### Patch Changes diff --git a/packages/core-app-api/api-report.md b/packages/core-app-api/api-report.md index 6824dbcf4c..05071255ba 100644 --- a/packages/core-app-api/api-report.md +++ b/packages/core-app-api/api-report.md @@ -179,6 +179,8 @@ export type AppIcons = { 'kind:location': IconComponent; 'kind:system': IconComponent; 'kind:user': IconComponent; + 'kind:resource': IconComponent; + 'kind:template': IconComponent; brokenImage: IconComponent; catalog: IconComponent; chat: IconComponent; diff --git a/packages/core-app-api/package.json b/packages/core-app-api/package.json index 5a687708e6..5852076136 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.10.0", + "version": "1.10.1-next.1", "publishConfig": { "access": "public" }, @@ -50,6 +50,7 @@ "@types/react": "^16.13.1 || ^17.0.0", "history": "^5.0.0", "i18next": "^22.4.15", + "lodash": "^4.17.21", "prop-types": "^15.7.2", "react-use": "^17.2.4", "zen-observable": "^0.10.0", diff --git a/packages/core-app-api/src/app/AppManager.test.tsx b/packages/core-app-api/src/app/AppManager.test.tsx index 98ce0b93e2..3d0c47c4d5 100644 --- a/packages/core-app-api/src/app/AppManager.test.tsx +++ b/packages/core-app-api/src/app/AppManager.test.tsx @@ -35,16 +35,34 @@ import { createRoutableExtension, analyticsApiRef, useApi, + errorApiRef, } from '@backstage/core-plugin-api'; import { AppManager } from './AppManager'; import { AppComponents, AppIcons } from './types'; import { FeatureFlagged } from '../routing/FeatureFlagged'; +import { + createTranslationRef, + useTranslationRef, +} from '@backstage/core-plugin-api/alpha'; describe('Integration Test', () => { const noOpAnalyticsApi = createApiFactory( analyticsApiRef, new NoOpAnalyticsApi(), ); + const noopErrorApi = createApiFactory(errorApiRef, { + error$() { + return { + subscribe() { + return { unsubscribe() {}, closed: true }; + }, + [Symbol.observable]() { + return this; + }, + }; + }, + post() {}, + }); const plugin1RouteRef = createRouteRef({ id: 'ref-1' }); const plugin1RouteRef2 = createRouteRef({ id: 'ref-1-2' }); const plugin2RouteRef = createRouteRef({ id: 'ref-2', params: ['x'] }); @@ -175,6 +193,10 @@ describe('Integration Test', () => { }, ]; + afterEach(() => { + localStorage.clear(); + }); + it('runs happy paths', async () => { const app = new AppManager({ apis: [noOpAnalyticsApi], @@ -262,7 +284,7 @@ describe('Integration Test', () => { it('runs success with __experimentalTranslations', async () => { const app = new AppManager({ - apis: [noOpAnalyticsApi], + apis: [noOpAnalyticsApi, noopErrorApi], defaultApis: [], themes, icons, @@ -277,27 +299,41 @@ describe('Integration Test', () => { }, __experimentalTranslations: { availableLanguages: ['en', 'de'], + defaultLanguage: 'de', }, }); const Provider = app.getProvider(); const Router = app.getRouter(); + const translationRef = createTranslationRef({ + id: 'test', + messages: { + foo: 'Foo', + }, + translations: { + de: () => Promise.resolve({ default: { foo: 'Bar' } }), + }, + }); + + const TranslatedComponent = () => { + const { t } = useTranslationRef(translationRef); + return <div>translation: {t('foo')}</div>; + }; + await renderWithEffects( <Provider> <Router> <Routes> - <Route path="/" element={<ExposedComponent />} /> - <Route path="/foo" element={<HiddenComponent />} /> + <Route path="/" element={<TranslatedComponent />} /> </Routes> </Router> </Provider>, ); - expect(screen.getByText('extLink1: /')).toBeInTheDocument(); - expect(screen.getByText('extLink2: /foo')).toBeInTheDocument(); - expect(screen.getByText('extLink3: <none>')).toBeInTheDocument(); - expect(screen.getByText('extLink4: <none>')).toBeInTheDocument(); + await expect( + screen.findByText('translation: Bar'), + ).resolves.toBeInTheDocument(); }); it('should wait for the config to load before calling feature flags', async () => { diff --git a/packages/core-app-api/src/app/AppManager.tsx b/packages/core-app-api/src/app/AppManager.tsx index 7a941b7986..37407283b5 100644 --- a/packages/core-app-api/src/app/AppManager.tsx +++ b/packages/core-app-api/src/app/AppManager.tsx @@ -18,6 +18,7 @@ import { Config } from '@backstage/config'; import React, { ComponentType, PropsWithChildren, + Suspense, useMemo, useRef, } from 'react'; @@ -341,7 +342,7 @@ export class AppManager implements BackstageApp { } } - const { ThemeProvider = AppThemeProvider } = this.components; + const { ThemeProvider = AppThemeProvider, Progress } = this.components; return ( <ApiProvider apis={this.getApiHolder()}> @@ -360,7 +361,7 @@ export class AppManager implements BackstageApp { appIdentityProxy: this.appIdentityProxy, }} > - {children} + <Suspense fallback={<Progress />}>{children}</Suspense> </InternalAppContext.Provider> </RoutingProvider> </ThemeProvider> diff --git a/packages/core-app-api/src/app/types.ts b/packages/core-app-api/src/app/types.ts index 523e35e9cb..9d2c77292c 100644 --- a/packages/core-app-api/src/app/types.ts +++ b/packages/core-app-api/src/app/types.ts @@ -18,13 +18,13 @@ import { ComponentType, PropsWithChildren } from 'react'; import { AnyApiFactory, AppTheme, - IconComponent, BackstagePlugin, + ExternalRouteRef, + FeatureFlag, + IconComponent, + IdentityApi, RouteRef, SubRouteRef, - ExternalRouteRef, - IdentityApi, - FeatureFlag, } from '@backstage/core-plugin-api'; import { AppConfig } from '@backstage/config'; @@ -99,7 +99,8 @@ export type AppIcons = { 'kind:location': IconComponent; 'kind:system': IconComponent; 'kind:user': IconComponent; - + 'kind:resource': IconComponent; + 'kind:template': IconComponent; brokenImage: IconComponent; catalog: IconComponent; chat: IconComponent; diff --git a/packages/core-app-api/src/routing/RouteResolver.beta.test.ts b/packages/core-app-api/src/routing/RouteResolver.beta.test.ts index 7cd9eae021..c0ee452d28 100644 --- a/packages/core-app-api/src/routing/RouteResolver.beta.test.ts +++ b/packages/core-app-api/src/routing/RouteResolver.beta.test.ts @@ -364,4 +364,31 @@ describe('RouteResolver', () => { /^Cannot route.*with parent.*as it has parameters$/, ); }); + + it('should encode some characters in params', () => { + const r = new RouteResolver( + new Map<RouteRef, string>([ + [ref2, 'my-parent/:x'], + [ref1, 'my-route'], + ]), + new Map<RouteRef, RouteRef>([[ref1, ref2]]), + [ + { + routeRefs: new Set([ref2]), + path: 'my-parent/:x', + ...rest, + children: [ + MATCH_ALL_ROUTE, + { routeRefs: new Set([ref1]), path: 'my-route', ...rest }, + ], + }, + ], + new Map(), + '/base', + ); + + expect(r.resolve(ref2, '/')?.({ x: 'a/#&?b' })).toBe( + '/base/my-parent/a%2F%23%26%3Fb', + ); + }); }); diff --git a/packages/core-app-api/src/routing/RouteResolver.compat.test.ts b/packages/core-app-api/src/routing/RouteResolver.compat.test.ts index 41e5aba712..0b4bf588a2 100644 --- a/packages/core-app-api/src/routing/RouteResolver.compat.test.ts +++ b/packages/core-app-api/src/routing/RouteResolver.compat.test.ts @@ -390,4 +390,33 @@ describe.each(['beta', 'stable'])('react-router %s', rrVersion => { /^Cannot route.*with parent.*as it has parameters$/, ); }); + + it('should encode some characters in params', () => { + const { RouteResolver } = + require('./RouteResolver') as typeof import('./RouteResolver'); + const r = new RouteResolver( + new Map<RouteRef, string>([ + [ref2, 'my-parent/:x'], + [ref1, 'my-route'], + ]), + new Map<RouteRef, RouteRef>([[ref1, ref2]]), + [ + { + routeRefs: new Set([ref2]), + path: 'my-parent/:x', + ...rest, + children: [ + MATCH_ALL_ROUTE, + { routeRefs: new Set([ref1]), path: 'my-route', ...rest }, + ], + }, + ], + new Map(), + '/base', + ); + + expect(r.resolve(ref2, '/')?.({ x: 'a/#&?b' })).toBe( + '/base/my-parent/a%2F%23%26%3Fb', + ); + }); }); diff --git a/packages/core-app-api/src/routing/RouteResolver.stable.test.ts b/packages/core-app-api/src/routing/RouteResolver.stable.test.ts index 8c484effae..05f7678078 100644 --- a/packages/core-app-api/src/routing/RouteResolver.stable.test.ts +++ b/packages/core-app-api/src/routing/RouteResolver.stable.test.ts @@ -364,4 +364,31 @@ describe('RouteResolver', () => { /^Cannot route.*with parent.*as it has parameters$/, ); }); + + it('should encode some characters in params', () => { + const r = new RouteResolver( + new Map<RouteRef, string>([ + [ref2, 'my-parent/:x'], + [ref1, 'my-route'], + ]), + new Map<RouteRef, RouteRef>([[ref1, ref2]]), + [ + { + routeRefs: new Set([ref2]), + path: 'my-parent/:x', + ...rest, + children: [ + MATCH_ALL_ROUTE, + { routeRefs: new Set([ref1]), path: 'my-route', ...rest }, + ], + }, + ], + new Map(), + '/base', + ); + + expect(r.resolve(ref2, '/')?.({ x: 'a/#&?b' })).toBe( + '/base/my-parent/a%2F%23%26%3Fb', + ); + }); }); diff --git a/packages/core-app-api/src/routing/RouteResolver.ts b/packages/core-app-api/src/routing/RouteResolver.ts index f17c549bc6..11eb753bc6 100644 --- a/packages/core-app-api/src/routing/RouteResolver.ts +++ b/packages/core-app-api/src/routing/RouteResolver.ts @@ -31,6 +31,7 @@ import { SubRouteRef, } from '@backstage/core-plugin-api'; import { joinPaths } from './helpers'; +import mapValues from 'lodash/mapValues'; /** * Resolves the absolute route ref that our target route ref is pointing pointing to, as well @@ -225,7 +226,23 @@ export class RouteResolver { ); const routeFunc: RouteFunc<Params> = (...[params]) => { - return joinPaths(basePath, generatePath(targetPath, params)); + // We selectively encode some some known-dangerous characters in the + // params. The reason that we don't perform a blanket `encodeURIComponent` + // here is that this encoding was added defensively long after the initial + // release of this code. There's likely to be many users of this code that + // already encode their parameters knowing that this code didn't do this + // for them in the past. Therefore, we are extra careful NOT to include + // the percent character in this set, even though that might seem like a + // bad idea. + const encodedParams = + params && + mapValues(params, value => { + if (typeof value === 'string') { + return value.replaceAll(/[&?#;\/]/g, c => encodeURIComponent(c)); + } + return value; + }); + return joinPaths(basePath, generatePath(targetPath, encodedParams)); }; return routeFunc; } diff --git a/packages/core-components/CHANGELOG.md b/packages/core-components/CHANGELOG.md index 28d1b95677..1cab780f55 100644 --- a/packages/core-components/CHANGELOG.md +++ b/packages/core-components/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/core-components +## 0.13.6-next.1 + +### Patch Changes + +- 4eab5cf901: The `TabbedLayout` component will now also navigate when clicking the active tab, which allows for navigation back from any sub routes. +- 997a71850c: Changed SupportButton menuitems to support text wrap +- 16126dbe6a: Change overlay header colors in the mobile menu to use navigation color from the theme +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/version-bridge@1.0.5 + +## 0.13.6-next.0 + +### Patch Changes + +- d19a827ef1: MissingAnnotationEmptyState component can now dynamically generate a YAML example based off the current entity being used. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/version-bridge@1.0.5 + ## 0.13.5 ### Patch Changes @@ -273,7 +303,7 @@ - 67140d9f96f: Upgrade `react-virtualized-auto-sizer´ to version `^1.0.11` - 6e0b71493df: Switched internal declaration of `DependencyGraphTypes` to use `namespace`. - c8779cc1d09: Updated `LogLine` component, which is used by the `LogViewer`, to turn URLs into clickable links. This feature is on by default -- 7908d72e033: Introduce a new global config parameter, `auth.enableExperimentalRedirectFlow`. When enabled, auth will happen with an in-window redirect flow rather than through a popup window. +- 7908d72e033: Introduce a new global config parameter, `enableExperimentalRedirectFlow`. When enabled, auth will happen with an in-window redirect flow rather than through a popup window. - 1e4f5e91b8e: Bump `zod` and `zod-to-json-schema` dependencies. - 29ba8267d69: Updated dependency `@material-ui/lab` to `4.0.0-alpha.61`. - 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) @@ -351,7 +381,7 @@ ### Patch Changes -- 7908d72e033: Introduce a new global config parameter, `auth.enableExperimentalRedirectFlow`. When enabled, auth will happen with an in-window redirect flow rather than through a popup window. +- 7908d72e033: Introduce a new global config parameter, `enableExperimentalRedirectFlow`. When enabled, auth will happen with an in-window redirect flow rather than through a popup window. - 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) - 7245e744ab1: Fixed the font color on `BackstageHeaderLabel` to respect the active page theme. - Updated dependencies diff --git a/packages/core-components/package.json b/packages/core-components/package.json index d8cc5057ff..155f0a09c4 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.13.5", + "version": "0.13.6-next.1", "publishConfig": { "access": "public", "main": "dist/index.esm.js", @@ -33,9 +33,11 @@ "start": "backstage-cli package start" }, "dependencies": { + "@backstage/catalog-model": "workspace:^", "@backstage/config": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/errors": "workspace:^", + "@backstage/plugin-catalog-react": "workspace:^", "@backstage/theme": "workspace:^", "@backstage/version-bridge": "workspace:^", "@date-io/core": "^1.3.13", diff --git a/packages/core-components/src/components/EmptyState/MissingAnnotationEmptyState.tsx b/packages/core-components/src/components/EmptyState/MissingAnnotationEmptyState.tsx index 9fc9eee959..c89129670a 100644 --- a/packages/core-components/src/components/EmptyState/MissingAnnotationEmptyState.tsx +++ b/packages/core-components/src/components/EmptyState/MissingAnnotationEmptyState.tsx @@ -25,23 +25,8 @@ import { CodeSnippet } from '../CodeSnippet'; import { Link } from '../Link'; import { EmptyState } from './EmptyState'; -const COMPONENT_YAML_TEMPLATE = `apiVersion: backstage.io/v1alpha1 -kind: Component -metadata: - name: example - description: example.com - annotations: - ANNOTATION: value -spec: - type: website - lifecycle: production - owner: user:guest`; - -const ANNOTATION_REGEXP = /^.*ANNOTATION.*$/m; -const ANNOTATION_YAML = COMPONENT_YAML_TEMPLATE.match(ANNOTATION_REGEXP)![0]; -const ANNOTATION_LINE = COMPONENT_YAML_TEMPLATE.split('\n').findIndex(line => - ANNOTATION_REGEXP.test(line), -); +import { useEntity } from '@backstage/plugin-catalog-react'; +import { Entity } from '@backstage/catalog-model'; type Props = { annotation: string | string[]; @@ -62,19 +47,38 @@ const useStyles = makeStyles<BackstageTheme>( { name: 'BackstageMissingAnnotationEmptyState' }, ); -function generateLineNumbers(lineCount: number) { - return Array.from(Array(lineCount + 1).keys(), i => i + ANNOTATION_LINE); +function generateYamlExample( + annotations: string[], + entity?: Entity, +): { yamlText: string; lineNumbers: number[] } { + const kind = entity?.kind || 'Component'; + const name = entity?.metadata.name || 'example'; + const type = entity?.spec?.type || 'website'; + const owner = entity?.spec?.owner || 'user:default/guest'; + + const yamlText = `apiVersion: backstage.io/v1alpha1 +kind: ${kind} +metadata: + name: ${name} + annotations:${annotations.map(ann => `\n ${ann}: value`).join('')} +spec: + type: ${type} + owner: ${owner}`; + + let line = 6; // Line 6 is the line number that annotations are added to. + const lineNumbers: number[] = []; + annotations.forEach(() => { + lineNumbers.push(line); + line++; + }); + + return { + yamlText, + lineNumbers, + }; } -function generateComponentYaml(annotations: string[]) { - const annotationYaml = annotations - .map(ann => ANNOTATION_YAML.replace('ANNOTATION', ann)) - .join('\n'); - - return COMPONENT_YAML_TEMPLATE.replace(ANNOTATION_YAML, annotationYaml); -} - -function generateDescription(annotations: string[]) { +function generateDescription(annotations: string[], entityKind = 'Component') { const isSingular = annotations.length <= 1; return ( <> @@ -87,13 +91,21 @@ function generateDescription(annotations: string[]) { </> ))}{' '} {isSingular ? 'is' : 'are'} missing. You need to add the{' '} - {isSingular ? 'annotation' : 'annotations'} to your component if you want - to enable this tool. + {isSingular ? 'annotation' : 'annotations'} to your {entityKind} if you + want to enable this tool. </> ); } export function MissingAnnotationEmptyState(props: Props) { + let entity: Entity | undefined; + try { + const entityContext = useEntity(); + entity = entityContext.entity; + } catch (err) { + // ignore when entity context doesnt exist + } + const { annotation, readMoreUrl } = props; const annotations = Array.isArray(annotation) ? annotation : [annotation]; const url = @@ -101,23 +113,25 @@ export function MissingAnnotationEmptyState(props: Props) { 'https://backstage.io/docs/features/software-catalog/well-known-annotations'; const classes = useStyles(); + const entityKind = entity?.kind || 'Component'; + const { yamlText, lineNumbers } = generateYamlExample(annotations, entity); return ( <EmptyState missing="field" title="Missing Annotation" - description={generateDescription(annotations)} + description={generateDescription(annotations, entityKind)} action={ <> <Typography variant="body1"> - Add the annotation to your component YAML as shown in the + Add the annotation to your {entityKind} YAML as shown in the highlighted example below: </Typography> <Box className={classes.code}> <CodeSnippet - text={generateComponentYaml(annotations)} + text={yamlText} language="yaml" showLineNumbers - highlightedNumbers={generateLineNumbers(annotations.length)} + highlightedNumbers={lineNumbers} customStyle={{ background: 'inherit', fontSize: '115%' }} /> </Box> diff --git a/packages/core-components/src/components/SupportButton/SupportButton.tsx b/packages/core-components/src/components/SupportButton/SupportButton.tsx index dcd4ead321..a07c03b7d2 100644 --- a/packages/core-components/src/components/SupportButton/SupportButton.tsx +++ b/packages/core-components/src/components/SupportButton/SupportButton.tsx @@ -46,6 +46,9 @@ const useStyles = makeStyles( minWidth: 260, maxWidth: 400, }, + menuItem: { + whiteSpace: 'normal', + }, }, { name: 'BackstageSupportButton' }, ); @@ -145,12 +148,16 @@ export function SupportButton(props: SupportButtonProps) { autoFocusItem={Boolean(anchorEl)} > {title && ( - <MenuItem alignItems="flex-start"> + <MenuItem alignItems="flex-start" className={classes.menuItem}> <Typography variant="subtitle1">{title}</Typography> </MenuItem> )} {React.Children.map(children, (child, i) => ( - <MenuItem alignItems="flex-start" key={`child-${i}`}> + <MenuItem + alignItems="flex-start" + key={`child-${i}`} + className={classes.menuItem} + > {child} </MenuItem> ))} diff --git a/packages/core-components/src/components/TabbedLayout/TabbedLayout.test.tsx b/packages/core-components/src/components/TabbedLayout/TabbedLayout.test.tsx index b84a7f262d..f5a059d615 100644 --- a/packages/core-components/src/components/TabbedLayout/TabbedLayout.test.tsx +++ b/packages/core-components/src/components/TabbedLayout/TabbedLayout.test.tsx @@ -17,6 +17,7 @@ import { renderInTestApp, withLogCollector } from '@backstage/test-utils'; import { act, fireEvent } from '@testing-library/react'; import React from 'react'; import { TabbedLayout } from './TabbedLayout'; +import { Link, Route, Routes } from 'react-router-dom'; describe('TabbedLayout', () => { it('renders simplest case', async () => { @@ -81,4 +82,41 @@ describe('TabbedLayout', () => { expect(getByText('tabbed-test-title-2')).toBeInTheDocument(); expect(getByText('tabbed-test-content-2')).toBeInTheDocument(); }); + + it('navigates when user clicks the same tab', async () => { + const { getByText, queryByText, queryAllByRole } = await renderInTestApp( + <TabbedLayout> + <TabbedLayout.Route path="/" title="tabbed-test-title"> + <div> + tabbed-test-content + <div> + <Link to="test">tabbed-test-sub-link</Link> + <Routes> + <Route + path="test" + element={<div>tabbed-test-sub-content</div>} + /> + </Routes> + </div> + </div> + </TabbedLayout.Route> + <TabbedLayout.Route path="/some-other-path" title="tabbed-test-title-2"> + <div>tabbed-test-content-2</div> + </TabbedLayout.Route> + </TabbedLayout>, + ); + + const subLink = getByText('tabbed-test-sub-link'); + expect(subLink).toBeInTheDocument(); + act(() => { + fireEvent.click(subLink); + }); + + expect(queryByText('tabbed-test-sub-content')).toBeInTheDocument(); + const [firstTab] = queryAllByRole('tab'); + act(() => { + fireEvent.click(firstTab); + }); + expect(queryByText('tabbed-test-sub-content')).not.toBeInTheDocument(); + }); }); diff --git a/packages/core-components/src/layout/HeaderTabs/HeaderTabs.tsx b/packages/core-components/src/layout/HeaderTabs/HeaderTabs.tsx index 48e0a8906a..704df67374 100644 --- a/packages/core-components/src/layout/HeaderTabs/HeaderTabs.tsx +++ b/packages/core-components/src/layout/HeaderTabs/HeaderTabs.tsx @@ -85,7 +85,7 @@ export function HeaderTabs(props: HeaderTabsProps) { if (selectedIndex === undefined) { setSelectedTab(index); } - if (onChange && selectedIndex !== index) onChange(index); + if (onChange) onChange(index); }, [selectedIndex, onChange], ); diff --git a/packages/core-components/src/layout/Sidebar/MobileSidebar.tsx b/packages/core-components/src/layout/Sidebar/MobileSidebar.tsx index 5dcf31d884..e124036648 100644 --- a/packages/core-components/src/layout/Sidebar/MobileSidebar.tsx +++ b/packages/core-components/src/layout/Sidebar/MobileSidebar.tsx @@ -79,14 +79,14 @@ const useStyles = makeStyles<BackstageTheme, { sidebarConfig: SidebarConfig }>( overlayHeader: { display: 'flex', - color: theme.palette.text.primary, + color: theme.palette.navigation.color, alignItems: 'center', justifyContent: 'space-between', padding: theme.spacing(2, 3), }, overlayHeaderClose: { - color: theme.palette.text.primary, + color: theme.palette.navigation.color, }, marginMobileSidebar: props => ({ diff --git a/packages/core-plugin-api/CHANGELOG.md b/packages/core-plugin-api/CHANGELOG.md index 0c9728434b..d206487074 100644 --- a/packages/core-plugin-api/CHANGELOG.md +++ b/packages/core-plugin-api/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/core-plugin-api +## 1.7.0-next.0 + +### Minor Changes + +- 322bbcae24: Removed the exprimental plugin configuration API. The `__experimentalReconfigure()` from the plugin options as well as the `__experimentalConfigure()` method on plugin instances have both been removed. + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.1.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.5 + ## 1.6.0 ### Minor Changes diff --git a/packages/core-plugin-api/alpha-api-report.md b/packages/core-plugin-api/alpha-api-report.md index d50bb0abd6..ba3583142f 100644 --- a/packages/core-plugin-api/alpha-api-report.md +++ b/packages/core-plugin-api/alpha-api-report.md @@ -4,9 +4,7 @@ ```ts import { ApiRef } from '@backstage/core-plugin-api'; -import { BackstagePlugin } from '@backstage/core-plugin-api'; import { Observable } from '@backstage/types'; -import { ReactNode } from 'react'; import { TranslationMessages as TranslationMessages_2 } from '@backstage/core-plugin-api/alpha'; import { TranslationRef as TranslationRef_2 } from '@backstage/core-plugin-api/alpha'; @@ -74,17 +72,6 @@ export function createTranslationResource< options: TranslationResourceOptions<TId, TMessages, TTranslations>, ): TranslationResource<TId>; -// @alpha -export interface PluginOptionsProviderProps { - // (undocumented) - children: ReactNode; - // (undocumented) - plugin?: BackstagePlugin; -} - -// @alpha -export const PluginProvider: (props: PluginOptionsProviderProps) => JSX.Element; - // @alpha (undocumented) export type TranslationApi = { getTranslation< @@ -245,11 +232,6 @@ export type TranslationSnapshot< t: TranslationFunction<TMessages>; }; -// @alpha -export function usePluginOptions< - TPluginOptions extends {} = {}, ->(): TPluginOptions; - // @alpha (undocumented) export const useTranslationRef: < TMessages extends { diff --git a/packages/core-plugin-api/api-report.md b/packages/core-plugin-api/api-report.md index 930f1f979d..7873b23f13 100644 --- a/packages/core-plugin-api/api-report.md +++ b/packages/core-plugin-api/api-report.md @@ -222,7 +222,7 @@ export type BackstageIdentityResponse = { export type BackstagePlugin< Routes extends AnyRoutes = {}, ExternalRoutes extends AnyExternalRoutes = {}, - PluginInputOptions extends {} = {}, + _Ignored extends {} = {}, > = { getId(): string; getApis(): Iterable<AnyApiFactory>; @@ -230,7 +230,6 @@ export type BackstagePlugin< provide<T>(extension: Extension<T>): T; routes: Routes; externalRoutes: ExternalRoutes; - __experimentalReconfigure(options: PluginInputOptions): void; }; // @public @@ -318,10 +317,9 @@ export function createExternalRouteRef< export function createPlugin< Routes extends AnyRoutes = {}, ExternalRoutes extends AnyExternalRoutes = {}, - PluginInputOptions extends {} = {}, >( - config: PluginConfig<Routes, ExternalRoutes, PluginInputOptions>, -): BackstagePlugin<Routes, ExternalRoutes, PluginInputOptions>; + config: PluginConfig<Routes, ExternalRoutes>, +): BackstagePlugin<Routes, ExternalRoutes>; // @public export function createReactExtension< @@ -647,14 +645,12 @@ export type PendingOAuthRequest = { export type PluginConfig< Routes extends AnyRoutes, ExternalRoutes extends AnyExternalRoutes, - PluginInputOptions extends {}, > = { id: string; apis?: Iterable<AnyApiFactory>; routes?: Routes; externalRoutes?: ExternalRoutes; featureFlags?: PluginFeatureFlagConfig[]; - __experimentalConfigure?(options?: PluginInputOptions): {}; }; // @public diff --git a/packages/core-plugin-api/package.json b/packages/core-plugin-api/package.json index 34e2491ed5..64fdd00915 100644 --- a/packages/core-plugin-api/package.json +++ b/packages/core-plugin-api/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/core-plugin-api", "description": "Core API used by Backstage plugins", - "version": "1.6.0", + "version": "1.7.0-next.0", "publishConfig": { "access": "public" }, diff --git a/packages/core-plugin-api/src/alpha.ts b/packages/core-plugin-api/src/alpha.ts index 505fd9b818..ebcbcf34c0 100644 --- a/packages/core-plugin-api/src/alpha.ts +++ b/packages/core-plugin-api/src/alpha.ts @@ -14,6 +14,5 @@ * limitations under the License. */ -export * from './plugin-options'; export * from './translation'; export * from './apis/alpha'; diff --git a/packages/core-plugin-api/src/extensions/extensions.tsx b/packages/core-plugin-api/src/extensions/extensions.tsx index a9a3127aee..b94354fa2c 100644 --- a/packages/core-plugin-api/src/extensions/extensions.tsx +++ b/packages/core-plugin-api/src/extensions/extensions.tsx @@ -21,7 +21,6 @@ import { RouteRef, useRouteRef } from '../routing'; import { attachComponentData } from './componentData'; import { Extension, BackstagePlugin } from '../plugin'; import { PluginErrorBoundary } from './PluginErrorBoundary'; -import { PluginProvider } from '../plugin-options'; import { routableExtensionRenderedEvent } from '../analytics/Tracker'; /** @@ -258,9 +257,7 @@ export function createReactExtension< ...(mountPoint && { routeRef: mountPoint.id }), }} > - <PluginProvider plugin={plugin}> - <Component {...props} /> - </PluginProvider> + <Component {...props} /> </AnalyticsContext> </PluginErrorBoundary> </Suspense> diff --git a/packages/core-plugin-api/src/plugin-options/usePluginOptions.test.tsx b/packages/core-plugin-api/src/plugin-options/usePluginOptions.test.tsx deleted file mode 100644 index 96691d503b..0000000000 --- a/packages/core-plugin-api/src/plugin-options/usePluginOptions.test.tsx +++ /dev/null @@ -1,53 +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 { renderHook } from '@testing-library/react-hooks'; -import { usePluginOptions, PluginProvider } from './usePluginOptions'; -import { createPlugin } from '../plugin'; - -describe('usePluginOptions', () => { - it('should provide a versioned value to hook', () => { - type TestInputPluginOptions = { - 'key-1': string; - }; - - type TestPluginOptions = { - 'key-1': string; - 'key-2': string; - }; - - const plugin = createPlugin({ - id: 'my-plugin', - __experimentalConfigure(_: TestInputPluginOptions): TestPluginOptions { - return { 'key-1': 'value-1', 'key-2': 'value-2' }; - }, - }); - - const rendered = renderHook(() => usePluginOptions(), { - wrapper: ({ children }: React.PropsWithChildren<{}>) => ( - <PluginProvider plugin={plugin}>{children}</PluginProvider> - ), - }); - - const config = rendered.result.current; - - expect(config).toEqual({ - 'key-1': 'value-1', - 'key-2': 'value-2', - }); - }); -}); diff --git a/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx b/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx deleted file mode 100644 index 8b3f7c109c..0000000000 --- a/packages/core-plugin-api/src/plugin-options/usePluginOptions.tsx +++ /dev/null @@ -1,93 +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 { - createVersionedContext, - createVersionedValueMap, - useVersionedContext, -} from '@backstage/version-bridge'; -import { BackstagePlugin } from '@backstage/core-plugin-api'; -import React, { ReactNode } from 'react'; - -const contextKey: string = 'plugin-context'; - -/** - * Properties for the PluginProvider component. - * - * @alpha - */ -export interface PluginOptionsProviderProps { - children: ReactNode; - plugin?: BackstagePlugin; -} - -/** - * Contains the plugin configuration. - * - * @alpha - */ -export const PluginProvider = ( - props: PluginOptionsProviderProps, -): JSX.Element => { - const { children, plugin } = props; - - const { Provider } = createVersionedContext<{ - 1: { plugin: BackstagePlugin | undefined }; - }>(contextKey); - - return ( - <Provider - value={createVersionedValueMap({ - 1: { - plugin, - }, - })} - > - {children} - </Provider> - ); -}; - -/** - * Grab the current entity from the context, throws if the entity has not yet been loaded - * or is not available. - * - * @alpha - */ -export function usePluginOptions< - TPluginOptions extends {} = {}, ->(): TPluginOptions { - const versionedHolder = useVersionedContext<{ 1: TPluginOptions }>( - contextKey, - ); - - if (!versionedHolder) { - throw new Error('Plugin Options context is not available'); - } - - const value = versionedHolder.atVersion(1); - if (!value) { - throw new Error('Plugin Options v1 is not available'); - } - - return ( - value as unknown as { - plugin: { - getPluginOptions(): {}; - }; - } - ).plugin.getPluginOptions() as TPluginOptions; -} diff --git a/packages/core-plugin-api/src/plugin/Plugin.tsx b/packages/core-plugin-api/src/plugin/Plugin.tsx index da26cd4db0..d97554b27b 100644 --- a/packages/core-plugin-api/src/plugin/Plugin.tsx +++ b/packages/core-plugin-api/src/plugin/Plugin.tsx @@ -30,18 +30,9 @@ import { AnyApiFactory } from '../apis'; export class PluginImpl< Routes extends AnyRoutes, ExternalRoutes extends AnyExternalRoutes, - PluginInputOptions extends {}, -> implements BackstagePlugin<Routes, ExternalRoutes, PluginInputOptions> +> implements BackstagePlugin<Routes, ExternalRoutes> { - constructor( - private readonly config: PluginConfig< - Routes, - ExternalRoutes, - PluginInputOptions - >, - ) {} - - private options: {} | undefined = undefined; + constructor(private readonly config: PluginConfig<Routes, ExternalRoutes>) {} getId(): string { return this.config.id; @@ -67,19 +58,6 @@ export class PluginImpl< return extension.expose(this); } - __experimentalReconfigure(options: PluginInputOptions): void { - if (this.config.__experimentalConfigure) { - this.options = this.config.__experimentalConfigure(options); - } - } - - getPluginOptions(): {} { - if (this.config.__experimentalConfigure && !this.options) { - this.options = this.config.__experimentalConfigure(); - } - return this.options ?? {}; - } - toString() { return `plugin{${this.config.id}}`; } @@ -94,9 +72,8 @@ export class PluginImpl< export function createPlugin< Routes extends AnyRoutes = {}, ExternalRoutes extends AnyExternalRoutes = {}, - PluginInputOptions extends {} = {}, >( - config: PluginConfig<Routes, ExternalRoutes, PluginInputOptions>, -): BackstagePlugin<Routes, ExternalRoutes, PluginInputOptions> { + config: PluginConfig<Routes, ExternalRoutes>, +): BackstagePlugin<Routes, ExternalRoutes> { return new PluginImpl(config); } diff --git a/packages/core-plugin-api/src/plugin/types.ts b/packages/core-plugin-api/src/plugin/types.ts index 37ce6c9e7c..3ba7706e16 100644 --- a/packages/core-plugin-api/src/plugin/types.ts +++ b/packages/core-plugin-api/src/plugin/types.ts @@ -52,7 +52,7 @@ export type AnyExternalRoutes = { [name: string]: ExternalRouteRef }; export type BackstagePlugin< Routes extends AnyRoutes = {}, ExternalRoutes extends AnyExternalRoutes = {}, - PluginInputOptions extends {} = {}, + _Ignored extends {} = {}, > = { getId(): string; getApis(): Iterable<AnyApiFactory>; @@ -63,7 +63,6 @@ export type BackstagePlugin< provide<T>(extension: Extension<T>): T; routes: Routes; externalRoutes: ExternalRoutes; - __experimentalReconfigure(options: PluginInputOptions): void; }; /** @@ -84,14 +83,12 @@ export type PluginFeatureFlagConfig = { export type PluginConfig< Routes extends AnyRoutes, ExternalRoutes extends AnyExternalRoutes, - PluginInputOptions extends {}, > = { id: string; apis?: Iterable<AnyApiFactory>; routes?: Routes; externalRoutes?: ExternalRoutes; featureFlags?: PluginFeatureFlagConfig[]; - __experimentalConfigure?(options?: PluginInputOptions): {}; }; /** diff --git a/packages/create-app/CHANGELOG.md b/packages/create-app/CHANGELOG.md index 6b7276679c..fed5a6b936 100644 --- a/packages/create-app/CHANGELOG.md +++ b/packages/create-app/CHANGELOG.md @@ -1,5 +1,45 @@ # @backstage/create-app +## 0.5.6-next.1 + +### Patch Changes + +- 8d2e640af4: Added missing `.eslintignore` file + + To apply this change to an existing app, create a new `.eslintignore` file at the root of your project with the following content: + + ```diff + + playwright.config.ts + ``` + +- Updated dependencies + - @backstage/cli-common@0.1.13-next.0 + +## 0.5.6-next.0 + +### Patch Changes + +- ba6a3b59c1: Removed duplicate `apple-touch-icon` link from `packages/app/public/index.html` that linked to nonexistent icon. +- c8ec0dea4a: Create unique temp directory for each `create-app` execution. +- b665f2ce65: Change base node image from node:18-bullseye-slim to node:18-bookworm-slim due to Docker build error on bullseye. + + You can apply these change to your own `Dockerfile` by replacing `node:18-bullseye-slim` with `node:18-bookworm-slim` + +- deed089a3d: Bump `cypress` to fix the end-to-end tests +- de42eebaaf: Bumped dev dependencies `@types/node` and `mock-fs`. +- 04a3f65e15: Bump Docker base images to `node:18-bookworm-slim` to fix node compatibility issues raised during image build. + + You can apply these change to your own `Dockerfile` by replacing `node:16-bullseye-slim` with `node:18-bookworm-slim` + +- 5eacd5d213: The E2E test setup based on Cypress has been replaced with one based on [Playwright](https://playwright.dev/). Migrating existing apps is not required as this is a standalone setup, only do so if you also want to switch from Cypress to Playwright. + + The scripts to run the E2E tests have been removed from `packages/app/package.json`, as they are now instead run from the root. Instead, a new script has been added to the root `package.json`, `yarn test:e2e`, which runs the E2E tests in development mode, unless `CI` is set in the environment. + + The Playwright setup uses utilities from the new `@backstage/e2e-test-utils` package to find and include all packages in the monorepo that have an `e2e-tests` folder. + +- Updated dependencies + - @backstage/cli-common@0.1.13-next.0 + ## 0.5.5 ### Patch Changes diff --git a/packages/create-app/package.json b/packages/create-app/package.json index 15db38b1c5..6ae88a8e4c 100644 --- a/packages/create-app/package.json +++ b/packages/create-app/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/create-app", "description": "A CLI that helps you create your own Backstage app", - "version": "0.5.5", + "version": "0.5.6-next.1", "publishConfig": { "access": "public" }, diff --git a/packages/create-app/src/createApp.test.ts b/packages/create-app/src/createApp.test.ts index 47c62520e0..7cb9733567 100644 --- a/packages/create-app/src/createApp.test.ts +++ b/packages/create-app/src/createApp.test.ts @@ -36,10 +36,6 @@ const templatingMock = jest.spyOn(tasks, 'templatingTask'); const checkAppExistsMock = jest.spyOn(tasks, 'checkAppExistsTask'); const tryInitGitRepositoryMock = jest.spyOn(tasks, 'tryInitGitRepository'); const readGitConfig = jest.spyOn(tasks, 'readGitConfig'); -const createTemporaryAppFolderMock = jest.spyOn( - tasks, - 'createTemporaryAppFolderTask', -); const moveAppMock = jest.spyOn(tasks, 'moveAppTask'); const buildAppMock = jest.spyOn(tasks, 'buildAppTask'); @@ -73,7 +69,6 @@ describe('command entrypoint', () => { const cmd = {} as unknown as Command; await createApp(cmd); expect(checkAppExistsMock).toHaveBeenCalled(); - expect(createTemporaryAppFolderMock).toHaveBeenCalled(); expect(tryInitGitRepositoryMock).toHaveBeenCalled(); expect(templatingMock).toHaveBeenCalled(); expect(templatingMock.mock.lastCall?.[0]).toEqual( @@ -85,7 +80,7 @@ describe('command entrypoint', () => { 'default-app', ), ); - expect(templatingMock.mock.lastCall?.[1]).toEqual( + expect(templatingMock.mock.lastCall?.[1]).toContain( path.join(tmpdir(), 'MyApp'), ); expect(moveAppMock).toHaveBeenCalled(); diff --git a/packages/create-app/src/createApp.ts b/packages/create-app/src/createApp.ts index efa299a3c9..09cede933d 100644 --- a/packages/create-app/src/createApp.ts +++ b/packages/create-app/src/createApp.ts @@ -20,12 +20,12 @@ import inquirer, { Answers } from 'inquirer'; import { resolve as resolvePath } from 'path'; import { findPaths } from '@backstage/cli-common'; import os from 'os'; +import fs from 'fs-extra'; import { Task, buildAppTask, checkAppExistsTask, checkPathExistsTask, - createTemporaryAppFolderTask, moveAppTask, templatingTask, tryInitGitRepository, @@ -37,7 +37,6 @@ const DEFAULT_BRANCH = 'master'; export default async (opts: OptionValues): Promise<void> => { /* eslint-disable-next-line no-restricted-syntax */ const paths = findPaths(__dirname); - const answers: Answers = await inquirer.prompt([ { type: 'input', @@ -68,7 +67,6 @@ export default async (opts: OptionValues): Promise<void> => { const templateDir = opts.templatePath ? paths.resolveTarget(opts.templatePath) : paths.resolveOwn('templates/default-app'); - const tempDir = resolvePath(os.tmpdir(), answers.name); // Use `--path` argument as application directory when specified, otherwise // create a directory using `answers.name` @@ -100,7 +98,7 @@ export default async (opts: OptionValues): Promise<void> => { await checkAppExistsTask(paths.targetDir, answers.name); Task.section('Creating a temporary app directory'); - await createTemporaryAppFolderTask(tempDir); + const tempDir = await fs.mkdtemp(resolvePath(os.tmpdir(), answers.name)); Task.section('Preparing files'); await templatingTask(templateDir, tempDir, { diff --git a/packages/create-app/src/lib/tasks.test.ts b/packages/create-app/src/lib/tasks.test.ts index c94bf43598..68afdc9222 100644 --- a/packages/create-app/src/lib/tasks.test.ts +++ b/packages/create-app/src/lib/tasks.test.ts @@ -24,7 +24,6 @@ import { buildAppTask, checkAppExistsTask, checkPathExistsTask, - createTemporaryAppFolderTask, moveAppTask, templatingTask, tryInitGitRepository, @@ -66,6 +65,7 @@ jest.mock('./versions', () => ({ '@backstage/core-app-api': '1.0.0', '@backstage/core-components': '1.0.0', '@backstage/core-plugin-api': '1.0.0', + '@backstage/e2e-test-utils': '1.0.0', '@backstage/integration-react': '1.0.0', '@backstage/plugin-api-docs': '1.0.0', '@backstage/plugin-catalog': '1.0.0', @@ -162,30 +162,6 @@ describe('tasks', () => { }); }); - describe('createTemporaryAppFolderTask', () => { - it('should create a directory at a given path', async () => { - const tempDir = 'projects/tmpFolder'; - await expect( - createTemporaryAppFolderTask(tempDir), - ).resolves.not.toThrow(); - expect(fs.existsSync(tempDir)).toBe(true); - }); - - it('should fail if a directory of the same name exists', async () => { - const tempDir = 'projects/dir'; - await expect(createTemporaryAppFolderTask(tempDir)).rejects.toThrow( - 'file already exists', - ); - }); - - it('should fail if a file of the same name exists', async () => { - const tempDir = 'projects/dir/my-file.txt'; - await expect(createTemporaryAppFolderTask(tempDir)).rejects.toThrow( - 'file already exists', - ); - }); - }); - describe('buildAppTask', () => { it('should change to `appDir` and run `yarn install` and `yarn tsc`', async () => { const mockChdir = jest.spyOn(process, 'chdir'); diff --git a/packages/create-app/src/lib/tasks.ts b/packages/create-app/src/lib/tasks.ts index 1943b0c3cc..90e6f6ae53 100644 --- a/packages/create-app/src/lib/tasks.ts +++ b/packages/create-app/src/lib/tasks.ts @@ -178,22 +178,6 @@ export async function checkPathExistsTask(path: string) { }); } -/** - * Create a folder to store templated files - * - * @param tempDir - target temporary directory - * @throws if `fs.mkdir` fails - */ -export async function createTemporaryAppFolderTask(tempDir: string) { - await Task.forItem('creating', 'temporary directory', async () => { - try { - await fs.mkdir(tempDir); - } catch (error) { - throw new Error(`Failed to create temporary app directory, ${error}`); - } - }); -} - /** * Run `yarn install` and `run tsc` in application directory * diff --git a/packages/create-app/src/lib/versions.ts b/packages/create-app/src/lib/versions.ts index 72f5c2c9d5..67db8b4a78 100644 --- a/packages/create-app/src/lib/versions.ts +++ b/packages/create-app/src/lib/versions.ts @@ -41,6 +41,7 @@ import { version as config } from '../../../config/package.json'; import { version as coreAppApi } from '../../../core-app-api/package.json'; import { version as coreComponents } from '../../../core-components/package.json'; import { version as corePluginApi } from '../../../core-plugin-api/package.json'; +import { version as e2eTestUtils } from '../../../e2e-test-utils/package.json'; import { version as errors } from '../../../errors/package.json'; import { version as integrationReact } from '../../../integration-react/package.json'; import { version as testUtils } from '../../../test-utils/package.json'; @@ -92,6 +93,7 @@ export const packageVersions = { '@backstage/core-app-api': coreAppApi, '@backstage/core-components': coreComponents, '@backstage/core-plugin-api': corePluginApi, + '@backstage/e2e-test-utils': e2eTestUtils, '@backstage/errors': errors, '@backstage/integration-react': integrationReact, '@backstage/plugin-api-docs': pluginApiDocs, diff --git a/packages/create-app/templates/default-app/.eslintignore b/packages/create-app/templates/default-app/.eslintignore new file mode 100644 index 0000000000..e5b19947ff --- /dev/null +++ b/packages/create-app/templates/default-app/.eslintignore @@ -0,0 +1 @@ +playwright.config.ts diff --git a/packages/create-app/templates/default-app/.gitignore.hbs b/packages/create-app/templates/default-app/.gitignore.hbs index d452ac2932..fbf813909c 100644 --- a/packages/create-app/templates/default-app/.gitignore.hbs +++ b/packages/create-app/templates/default-app/.gitignore.hbs @@ -49,3 +49,6 @@ site # vscode database functionality support files *.session.sql + +# E2E test reports +e2e-test-report/ diff --git a/packages/create-app/templates/default-app/package.json.hbs b/packages/create-app/templates/default-app/package.json.hbs index 9715331d8f..844a7bca9d 100644 --- a/packages/create-app/templates/default-app/package.json.hbs +++ b/packages/create-app/templates/default-app/package.json.hbs @@ -17,6 +17,7 @@ "clean": "backstage-cli repo clean", "test": "backstage-cli repo test", "test:all": "backstage-cli repo test --coverage", + "test:e2e": "playwright test", "fix": "backstage-cli repo fix", "lint": "backstage-cli repo lint --since origin/{{defaultBranch}}", "lint:all": "backstage-cli repo lint", @@ -31,6 +32,8 @@ }, "devDependencies": { "@backstage/cli": "^{{version '@backstage/cli'}}", + "@backstage/e2e-test-utils": "^{{version '@backstage/e2e-test-utils'}}", + "@playwright/test": "^1.32.3", "@spotify/prettier-config": "^12.0.0", "concurrently": "^8.0.0", "lerna": "^4.0.0", diff --git a/packages/create-app/templates/default-app/packages/app/cypress.json b/packages/create-app/templates/default-app/packages/app/cypress.json deleted file mode 100644 index 0cb845a86d..0000000000 --- a/packages/create-app/templates/default-app/packages/app/cypress.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "baseUrl": "http://localhost:3001", - "fixturesFolder": false, - "pluginsFile": false, - "retries": 3 -} diff --git a/packages/create-app/templates/default-app/packages/app/cypress/.eslintrc.json b/packages/create-app/templates/default-app/packages/app/cypress/.eslintrc.json deleted file mode 100644 index b903ff250a..0000000000 --- a/packages/create-app/templates/default-app/packages/app/cypress/.eslintrc.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "plugins": ["cypress"], - "extends": ["plugin:cypress/recommended"], - "rules": { - "jest/expect-expect": [ - "error", - { - "assertFunctionNames": ["expect", "cy.contains", "cy.**.should"] - } - ] - } -} diff --git a/packages/create-app/templates/default-app/packages/app/cypress/integration/app.js b/packages/create-app/templates/default-app/packages/app/cypress/integration/app.js deleted file mode 100644 index 43fb2e32de..0000000000 --- a/packages/create-app/templates/default-app/packages/app/cypress/integration/app.js +++ /dev/null @@ -1,6 +0,0 @@ -describe('App', () => { - it('should render the catalog', () => { - cy.visit('/'); - cy.contains('My Company Catalog'); - }); -}); diff --git a/plugins/catalog-customized/src/plugin.ts b/packages/create-app/templates/default-app/packages/app/e2e-tests/app.test.ts similarity index 74% rename from plugins/catalog-customized/src/plugin.ts rename to packages/create-app/templates/default-app/packages/app/e2e-tests/app.test.ts index ce729d5226..d45bc0dbf0 100644 --- a/plugins/catalog-customized/src/plugin.ts +++ b/packages/create-app/templates/default-app/packages/app/e2e-tests/app.test.ts @@ -14,9 +14,10 @@ * limitations under the License. */ -import { catalogPlugin } from '@backstage/plugin-catalog'; +import { test, expect } from '@playwright/test'; -// id: 'catalog-customized' -catalogPlugin.__experimentalReconfigure({ - createButtonTitle: 'New', +test('App should render the welcome page', async ({ page }) => { + await page.goto('/'); + + await expect(page.getByText('My Company Catalog')).toBeVisible(); }); diff --git a/packages/create-app/templates/default-app/packages/app/package.json.hbs b/packages/create-app/templates/default-app/packages/app/package.json.hbs index 6793a91dd0..598f049a4c 100644 --- a/packages/create-app/templates/default-app/packages/app/package.json.hbs +++ b/packages/create-app/templates/default-app/packages/app/package.json.hbs @@ -11,11 +11,7 @@ "build": "backstage-cli package build", "clean": "backstage-cli package clean", "test": "backstage-cli package test", - "lint": "backstage-cli package lint", - "test:e2e": "cross-env PORT=3001 start-server-and-test start http://localhost:3001 cy:dev", - "test:e2e:ci": "cross-env PORT=3001 start-server-and-test start http://localhost:3001 cy:run", - "cy:dev": "cypress open", - "cy:run": "cypress run --browser chrome" + "lint": "backstage-cli package lint" }, "dependencies": { "@backstage/app-defaults": "^{{version '@backstage/app-defaults'}}", @@ -54,15 +50,13 @@ }, "devDependencies": { "@backstage/test-utils": "^{{version '@backstage/test-utils'}}", + "@playwright/test": "^1.32.3", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "@testing-library/dom": "^8.0.0", "@types/react-dom": "*", - "cross-env": "^7.0.0", - "cypress": "^9.7.0", - "eslint-plugin-cypress": "^2.10.3", - "start-server-and-test": "^1.10.11" + "cross-env": "^7.0.0" }, "browserslist": { "production": [ diff --git a/packages/create-app/templates/default-app/packages/app/public/index.html b/packages/create-app/templates/default-app/packages/app/public/index.html index c6083b3dd2..fc758eee32 100644 --- a/packages/create-app/templates/default-app/packages/app/public/index.html +++ b/packages/create-app/templates/default-app/packages/app/public/index.html @@ -8,7 +8,6 @@ name="description" content="Backstage is an open platform for building developer portals" /> - <link rel="apple-touch-icon" href="<%= publicPath %>/logo192.png" /> <!-- manifest.json provides metadata used when your web app is installed on a user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/ diff --git a/packages/create-app/templates/default-app/packages/backend/Dockerfile b/packages/create-app/templates/default-app/packages/backend/Dockerfile index 373ee7f40a..18548e9337 100644 --- a/packages/create-app/templates/default-app/packages/backend/Dockerfile +++ b/packages/create-app/templates/default-app/packages/backend/Dockerfile @@ -9,7 +9,7 @@ # # Once the commands have been run, you can build the image using `yarn build-image` -FROM node:18-bullseye-slim +FROM node:18-bookworm-slim # Install isolate-vm dependencies, these are needed by the @backstage/plugin-scaffolder-backend. RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ diff --git a/packages/create-app/templates/default-app/playwright.config.ts b/packages/create-app/templates/default-app/playwright.config.ts new file mode 100644 index 0000000000..37c7fb14c7 --- /dev/null +++ b/packages/create-app/templates/default-app/playwright.config.ts @@ -0,0 +1,60 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { defineConfig } from '@playwright/test'; +import { generateProjects } from '@backstage/e2e-test-utils/playwright'; + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + timeout: 60_000, + + expect: { + timeout: 5_000, + }, + + // Run your local dev server before starting the tests + webServer: process.env.CI + ? [] + : [ + { + command: 'yarn start', + port: 3000, + reuseExistingServer: true, + timeout: 60_000, + }, + ], + + forbidOnly: !!process.env.CI, + + retries: process.env.CI ? 2 : 0, + + reporter: [['html', { open: 'never', outputFolder: 'e2e-test-report' }]], + + use: { + actionTimeout: 0, + baseURL: + process.env.PLAYWRIGHT_URL ?? + (process.env.CI ? 'http://localhost:7007' : 'http://localhost:3000'), + screenshot: 'only-on-failure', + trace: 'on-first-retry', + }, + + outputDir: 'node_modules/.cache/e2e-test-results', + + projects: generateProjects(), // Find all packages with e2e-test folders +}); diff --git a/packages/dev-utils/CHANGELOG.md b/packages/dev-utils/CHANGELOG.md index 434ede5d73..300d3dad2f 100644 --- a/packages/dev-utils/CHANGELOG.md +++ b/packages/dev-utils/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/dev-utils +## 1.0.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-app-api@1.10.1-next.1 + - @backstage/app-defaults@1.4.4-next.1 + - @backstage/test-utils@1.4.4-next.1 + - @backstage/integration-react@1.1.20-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## 1.0.22-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/test-utils@1.4.4-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/integration-react@1.1.20-next.0 + - @backstage/app-defaults@1.4.4-next.0 + - @backstage/core-app-api@1.10.1-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + ## 1.0.21 ### Patch Changes diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json index 0bf405772f..dec37f3cea 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.21", + "version": "1.0.22-next.1", "publishConfig": { "access": "public", "main": "dist/index.esm.js", diff --git a/plugins/catalog-customized/.eslintrc.js b/packages/e2e-test-utils/.eslintrc.js similarity index 100% rename from plugins/catalog-customized/.eslintrc.js rename to packages/e2e-test-utils/.eslintrc.js diff --git a/packages/e2e-test-utils/CHANGELOG.md b/packages/e2e-test-utils/CHANGELOG.md new file mode 100644 index 0000000000..de15b39751 --- /dev/null +++ b/packages/e2e-test-utils/CHANGELOG.md @@ -0,0 +1,7 @@ +# @backstage/e2e-test-utils + +## 0.1.0-next.0 + +### Minor Changes + +- f5b41b27a9: Initial release. diff --git a/packages/e2e-test-utils/README.md b/packages/e2e-test-utils/README.md new file mode 100644 index 0000000000..d9459dc64a --- /dev/null +++ b/packages/e2e-test-utils/README.md @@ -0,0 +1,12 @@ +# @backstage/e2e-test-utils + +_This package was created through the Backstage CLI_. + +## Installation + +Install the package via Yarn: + +```sh +cd <package-dir> # if within a monorepo +yarn add --dev @backstage/e2e-test-utils +``` diff --git a/packages/e2e-test-utils/catalog-info.yaml b/packages/e2e-test-utils/catalog-info.yaml new file mode 100644 index 0000000000..d1dea51dc5 --- /dev/null +++ b/packages/e2e-test-utils/catalog-info.yaml @@ -0,0 +1,10 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: backstage-e2e-test-utils + title: '@backstage/e2e-test-utils' + description: Shared end-to-end test utilities Backstage +spec: + lifecycle: experimental + type: backstage-node-library + owner: maintainers diff --git a/packages/e2e-test-utils/package.json b/packages/e2e-test-utils/package.json new file mode 100644 index 0000000000..fcbae56796 --- /dev/null +++ b/packages/e2e-test-utils/package.json @@ -0,0 +1,57 @@ +{ + "name": "@backstage/e2e-test-utils", + "description": "Shared end-to-end test utilities Backstage", + "version": "0.1.0-next.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public" + }, + "exports": { + "./playwright": "./src/playwright/index.ts", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "playwright": [ + "src/playwright/index.ts" + ], + "package.json": [ + "package.json" + ] + } + }, + "backstage": { + "role": "node-library" + }, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "dependencies": { + "@manypkg/get-packages": "^1.1.3", + "fs-extra": "^10.1.0" + }, + "devDependencies": { + "@backstage/cli": "workspace:^", + "@backstage/cli-node": "workspace:^", + "@types/fs-extra": "^9.0.1" + }, + "peerDependencies": { + "@playwright/test": "^1.32.3" + }, + "peerDependenciesMeta": { + "@playwright/test": { + "optional": true + } + }, + "files": [ + "dist" + ] +} diff --git a/packages/e2e-test-utils/playwright-api-report.md b/packages/e2e-test-utils/playwright-api-report.md new file mode 100644 index 0000000000..7153f2e578 --- /dev/null +++ b/packages/e2e-test-utils/playwright-api-report.md @@ -0,0 +1,15 @@ +## API Report File for "@backstage/e2e-test-utils" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { PlaywrightTestConfig } from '@playwright/test'; + +// @public +export function failOnBrowserErrors(): void; + +// @public +export function generateProjects(): PlaywrightTestConfig['projects']; + +// (No @packageDocumentation comment for this package) +``` diff --git a/plugins/adr/src/alpha.ts b/packages/e2e-test-utils/src/index.ts similarity index 94% rename from plugins/adr/src/alpha.ts rename to packages/e2e-test-utils/src/index.ts index 587cfce3d6..4b9026cde5 100644 --- a/plugins/adr/src/alpha.ts +++ b/packages/e2e-test-utils/src/index.ts @@ -13,4 +13,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export * from './translations'; +export {}; diff --git a/packages/e2e-test-utils/src/playwright.ts b/packages/e2e-test-utils/src/playwright.ts new file mode 100644 index 0000000000..63599d30db --- /dev/null +++ b/packages/e2e-test-utils/src/playwright.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './playwright/index'; diff --git a/packages/e2e-test-utils/src/playwright/failOnBrowserErrors.ts b/packages/e2e-test-utils/src/playwright/failOnBrowserErrors.ts new file mode 100644 index 0000000000..af7baa9540 --- /dev/null +++ b/packages/e2e-test-utils/src/playwright/failOnBrowserErrors.ts @@ -0,0 +1,37 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { test } from '@playwright/test'; + +/** + * Calling this at the top of your test file will ensure that tests fail if the browser + * logs any errors or if there are any uncaught exceptions. + * + * @public + */ +export function failOnBrowserErrors(): void { + test.beforeEach(async ({ page }) => { + page.on('pageerror', error => { + throw new Error(`Uncaught exception on page, ${error}`); + }); + + page.on('console', msg => { + if (msg.type() === 'error') { + throw new Error(`Unexpected console error message "${msg.text()}"`); + } + }); + }); +} diff --git a/packages/e2e-test-utils/src/playwright/generateProjects.ts b/packages/e2e-test-utils/src/playwright/generateProjects.ts new file mode 100644 index 0000000000..b6f3d159c5 --- /dev/null +++ b/packages/e2e-test-utils/src/playwright/generateProjects.ts @@ -0,0 +1,42 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import fs from 'fs-extra'; +import { resolve as resolvePath } from 'path'; +import { PlaywrightTestConfig } from '@playwright/test'; +import { getPackagesSync } from '@manypkg/get-packages'; +import type { BackstagePackage } from '@backstage/cli-node'; + +/** + * Generates a list of playwright projects by scanning the monorepo for packages with an `e2e-tests/` folder. + * + * @public + */ +export function generateProjects(): PlaywrightTestConfig['projects'] { + // TODO(Rugvip): Switch this over to use @backstage/cli-node once released, and support SINCE=origin/main + const { root, packages } = getPackagesSync(process.cwd()); + const e2eTestPackages = [...(root ? [root] : []), ...packages].filter(pkg => { + return fs.pathExistsSync(resolvePath(pkg.dir, 'e2e-tests')); + }) as BackstagePackage[]; + + return e2eTestPackages.map(pkg => ({ + name: pkg.packageJson.name, + testDir: resolvePath(pkg.dir, 'e2e-tests'), + use: { + channel: 'chrome', + }, + })); +} diff --git a/packages/e2e-test-utils/src/playwright/index.ts b/packages/e2e-test-utils/src/playwright/index.ts new file mode 100644 index 0000000000..c5750581d7 --- /dev/null +++ b/packages/e2e-test-utils/src/playwright/index.ts @@ -0,0 +1,18 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { generateProjects } from './generateProjects'; +export { failOnBrowserErrors } from './failOnBrowserErrors'; diff --git a/packages/e2e-test-utils/src/setupTests.ts b/packages/e2e-test-utils/src/setupTests.ts new file mode 100644 index 0000000000..4b9026cde5 --- /dev/null +++ b/packages/e2e-test-utils/src/setupTests.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export {}; diff --git a/packages/e2e-test/CHANGELOG.md b/packages/e2e-test/CHANGELOG.md index cee3b7cc56..4c47b33e86 100644 --- a/packages/e2e-test/CHANGELOG.md +++ b/packages/e2e-test/CHANGELOG.md @@ -1,5 +1,23 @@ # e2e-test +## 0.2.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.6-next.1 + - @backstage/cli-common@0.1.13-next.0 + - @backstage/errors@1.2.2 + +## 0.2.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.6-next.0 + - @backstage/cli-common@0.1.13-next.0 + - @backstage/errors@1.2.2 + ## 0.2.7 ### Patch Changes diff --git a/packages/e2e-test/package.json b/packages/e2e-test/package.json index 10e4cb3c47..8b1499446a 100644 --- a/packages/e2e-test/package.json +++ b/packages/e2e-test/package.json @@ -1,7 +1,7 @@ { "name": "e2e-test", "description": "E2E test for verifying Backstage packages", - "version": "0.2.7", + "version": "0.2.8-next.1", "private": true, "backstage": { "role": "cli" @@ -37,7 +37,6 @@ "handlebars": "^4.7.3", "mysql2": "^2.2.5", "pgtools": "^1.0.0", - "puppeteer": "^17.0.0", "tree-kill": "^1.2.2" }, "devDependencies": { diff --git a/packages/e2e-test/src/commands/run.ts b/packages/e2e-test/src/commands/run.ts index 6cca0fb987..5d373b24cf 100644 --- a/packages/e2e-test/src/commands/run.ts +++ b/packages/e2e-test/src/commands/run.ts @@ -20,13 +20,11 @@ import fetch from 'cross-fetch'; import handlebars from 'handlebars'; import killTree from 'tree-kill'; import { resolve as resolvePath, join as joinPath } from 'path'; -import puppeteer from 'puppeteer'; import path from 'path'; import { spawnPiped, runPlain, - waitForPageWithText, waitFor, waitForExit, print, @@ -42,6 +40,7 @@ const paths = findPaths(__dirname); const templatePackagePaths = [ 'packages/cli/templates/default-plugin/package.json.hbs', + 'packages/create-app/templates/default-app/package.json.hbs', 'packages/create-app/templates/default-app/packages/app/package.json.hbs', 'packages/create-app/templates/default-app/packages/backend/package.json.hbs', ]; @@ -66,8 +65,11 @@ export async function run() { print('Creating a Backstage Backend Plugin'); await createPlugin({ appDir, pluginId, select: 'backend-plugin' }); - print('Starting the app'); - await testAppServe(pluginId, appDir); + print(`Running 'yarn test:e2e' in newly created app with new plugin`); + await runPlain(['yarn', 'test:e2e'], { + cwd: appDir, + env: { ...process.env, CI: undefined }, + }); if ( Boolean(process.env.POSTGRES_USER) || @@ -297,15 +299,6 @@ async function createApp( await runPlain(['yarn', cmd], { cwd: appDir }); } - print(`Running 'yarn test:e2e:ci' in newly created app`); - await runPlain(['yarn', 'test:e2e:ci'], { - cwd: resolvePath(appDir, 'packages', 'app'), - env: { - ...process.env, - APP_CONFIG_app_baseUrl: '"http://localhost:3001"', - }, - }); - return appDir; } finally { child.kill(); @@ -381,63 +374,6 @@ async function createPlugin(options: { } } -/** - * Start serving the newly created app and make sure that the create plugin is rendering correctly - */ -async function testAppServe(pluginId: string, appDir: string) { - const startApp = spawnPiped(['yarn', 'start'], { - cwd: appDir, - env: { - ...process.env, - GITHUB_TOKEN: 'abc', - }, - }); - - let successful = false; - - let browser; - try { - for (let attempts = 1; ; attempts++) { - try { - browser = await puppeteer.launch(); - const page = await browser.newPage(); - - await page.goto('http://localhost:3000', { waitUntil: 'networkidle0' }); - - await waitForPageWithText(page, '/', 'My Company Catalog'); - await waitForPageWithText( - page, - `/${pluginId}`, - `Welcome to ${pluginId}!`, - ); - - print('Both App and Plugin loaded correctly'); - successful = true; - break; - } catch (error) { - if (attempts >= 20) { - throw new Error(`App serve test failed, ${error}`); - } - print(`App serve failed, trying again, ${error}`); - await new Promise(resolve => setTimeout(resolve, 1000)); - } - } - } finally { - // Kill entire process group, otherwise we'll end up with hanging serve processes - await new Promise<void>((res, rej) => { - killTree(startApp.pid!, err => (err ? rej(err) : res())); - }); - } - - try { - await waitForExit(startApp); - } catch (error) { - if (!successful) { - throw error; - } - } -} - /** Drops PG databases */ async function dropDB(database: string, client: string) { try { @@ -507,37 +443,35 @@ async function testBackendStart(appDir: string, ...args: string[]) { }); let successful = false; - const stdErrorHasErrors = (input: string) => { + const filterStderr = (input: string) => { const lines = input.split('\n').filter(Boolean); - return ( - lines.filter( - l => - !l.includes('Use of deprecated folder mapping') && - !l.includes('Update this package.json to use a subpath') && - !l.includes( - '(Use `node --trace-deprecation ...` to show where the warning was created)', - ) && - // These 4 are all for the AWS SDK v2 deprecation - !l.includes( - 'The AWS SDK for JavaScript (v2) will be put into maintenance mode', - ) && - !l.includes( - 'Please migrate your code to use AWS SDK for JavaScript', - ) && - !l.includes('check the migration guide at https://a.co/7PzMCcy') && - !l.includes( - '(Use `node --trace-warnings ...` to show where the warning was created)', - ), - ).length !== 0 + return lines.filter( + l => + !l.includes( + 'ExperimentalWarning: Custom ESM Loaders is an experimental feature', // Node 16 + ) && + !l.includes( + 'ExperimentalWarning: `--experimental-loader` may be removed in the future;', // Node 18 + ) && + !l.includes("--import 'data:text/javascript,import") && // the new --experimental-loader replacement warning, printed after the above, Node 18 + !l.includes( + 'ExperimentalWarning: `globalPreload` is planned for removal in favor of `initialize`.', // Node 18 + ) && + !l.includes('node --trace-warnings ...'), ); }; try { await waitFor( - () => stdout.includes('Listening on ') || stdErrorHasErrors(stderr), + () => stdout.includes('Listening on ') || filterStderr(stderr).length > 0, ); - if (stdErrorHasErrors(stderr)) { - print(`Expected stderr to be clean, got ${stderr}`); + const stderrLines = filterStderr(stderr); + if (stderrLines.length > 0) { + print( + `Expected stderr to be clean, got ${stderr} \n\nThe following lines were unexpected:\n${stderrLines.join( + '\n', + )}`, + ); // Skipping the whole block throw new Error(stderr); } diff --git a/packages/e2e-test/src/lib/helpers.ts b/packages/e2e-test/src/lib/helpers.ts index b3fd665fd2..fc5aefcff9 100644 --- a/packages/e2e-test/src/lib/helpers.ts +++ b/packages/e2e-test/src/lib/helpers.ts @@ -22,7 +22,6 @@ import { ChildProcess, } from 'child_process'; import { promisify } from 'util'; -import puppeteer from 'puppeteer'; const execFile = promisify(execFileCb); @@ -125,50 +124,6 @@ export async function waitForExit(child: ChildProcess) { ); } -export async function waitForPageWithText( - page: puppeteer.Page, - path: string, - text: string, - { intervalMs = 1000, maxFindAttempts = 50 } = {}, -) { - let findAttempts = 0; - for (;;) { - try { - const waitTimeMs = intervalMs * (findAttempts + 1); - console.log(`Attempting to load page at ${path}, waiting ${waitTimeMs}`); - await new Promise(resolve => setTimeout(resolve, waitTimeMs)); - - await page.goto(`http://localhost:3000${path}`, { - waitUntil: 'networkidle0', - }); - - const match = await page.evaluate( - textContent => - Array.from(document.querySelectorAll('*')).some( - el => el.textContent === textContent, - ), - text, - ); - - if (!match) { - throw new Error(`Expected to find text ${text}`); - } - - break; - } catch (error) { - console.log(error); - assertError(error); - - findAttempts++; - if (findAttempts >= maxFindAttempts) { - throw new Error( - `Failed to load page '${path}', max number of attempts reached`, - ); - } - } - } -} - export function print(msg: string) { return process.stdout.write(`${msg}\n`); } diff --git a/packages/frontend-app-api/CHANGELOG.md b/packages/frontend-app-api/CHANGELOG.md index f944dd1e27..90d7ba70d2 100644 --- a/packages/frontend-app-api/CHANGELOG.md +++ b/packages/frontend-app-api/CHANGELOG.md @@ -1,5 +1,40 @@ # @backstage/frontend-app-api +## 0.2.0-next.1 + +### Patch Changes + +- 52366db5b3: Make themes configurable through extensions, and switched default themes to use extensions instead. +- e5a2956dd2: Register default api implementations when creating declarative integrated apps. +- Updated dependencies + - @backstage/frontend-plugin-api@0.1.1-next.1 + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-app-api@1.10.1-next.1 + - @backstage/plugin-graphiql@0.2.55-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + +## 0.2.0-next.0 + +### Minor Changes + +- 9d03dfe5e3: The `createApp` config option has been replaced by a new `configLoader` option. There is now also a `pluginLoader` option that can be used to dynamically load plugins into the app. + +### Patch Changes + +- 322bbcae24: Internal update for removal of experimental plugin configuration API. +- 66d51a4827: Prevents root extension override and duplicated plugin extensions. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/frontend-plugin-api@0.1.1-next.0 + - @backstage/config@1.1.0 + - @backstage/core-app-api@1.10.1-next.0 + - @backstage/plugin-graphiql@0.2.55-next.0 + - @backstage/types@1.1.1 + ## 0.1.0 ### Minor Changes diff --git a/packages/frontend-app-api/api-report.md b/packages/frontend-app-api/api-report.md index 12cf853f9d..2e77ef904b 100644 --- a/packages/frontend-app-api/api-report.md +++ b/packages/frontend-app-api/api-report.md @@ -12,7 +12,8 @@ import { JSX as JSX_2 } from 'react'; // @public (undocumented) export function createApp(options: { plugins: BackstagePlugin[]; - config?: ConfigApi; + configLoader?: () => Promise<ConfigApi>; + pluginLoader?: (ctx: { config: ConfigApi }) => Promise<BackstagePlugin[]>; }): { createRoot(): JSX_2.Element; }; diff --git a/packages/frontend-app-api/package.json b/packages/frontend-app-api/package.json index 772dd62a36..5fb84070d4 100644 --- a/packages/frontend-app-api/package.json +++ b/packages/frontend-app-api/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/frontend-app-api", - "version": "0.1.0", + "version": "0.2.0-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -24,7 +24,9 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", - "@testing-library/jest-dom": "^5.10.1" + "@backstage/test-utils": "workspace:^", + "@testing-library/jest-dom": "^5.10.1", + "@testing-library/react": "^12.1.3" }, "configSchema": "config.d.ts", "files": [ @@ -38,8 +40,10 @@ "@backstage/core-plugin-api": "workspace:^", "@backstage/frontend-plugin-api": "workspace:^", "@backstage/plugin-graphiql": "workspace:^", + "@backstage/theme": "workspace:^", "@backstage/types": "workspace:^", "@material-ui/core": "^4.12.4", + "@material-ui/icons": "^4.11.3", "@types/react": "^16.13.1 || ^17.0.0", "lodash": "^4.17.21" }, diff --git a/packages/frontend-app-api/src/extensions/CoreNav.tsx b/packages/frontend-app-api/src/extensions/CoreNav.tsx index e66bee8212..71ab71a6aa 100644 --- a/packages/frontend-app-api/src/extensions/CoreNav.tsx +++ b/packages/frontend-app-api/src/extensions/CoreNav.tsx @@ -19,6 +19,8 @@ import { createExtension, coreExtensionData, createExtensionInput, + useRouteRef, + NavTarget, } from '@backstage/frontend-plugin-api'; import { makeStyles } from '@material-ui/core'; import { @@ -29,7 +31,6 @@ import { SidebarDivider, SidebarItem, } from '@backstage/core-components'; -import { GraphiQLIcon } from '@backstage/plugin-graphiql'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports import LogoIcon from '../../../app/src/components/Root/LogoIcon'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports @@ -63,25 +64,33 @@ const SidebarLogo = () => { ); }; +const SidebarNavItem = (props: NavTarget) => { + const { icon: Icon, title, routeRef } = props; + const to = useRouteRef(routeRef)(); + // TODO: Support opening modal, for example, the search one + return <SidebarItem to={to} icon={Icon} text={title} />; +}; + export const CoreNav = createExtension({ id: 'core.nav', at: 'core.layout/nav', inputs: { items: createExtensionInput({ - path: coreExtensionData.navTarget, + target: coreExtensionData.navTarget, }), }, output: { element: coreExtensionData.reactElement, }, - factory({ bind }) { + factory({ bind, inputs }) { bind({ - // TODO: set base path using the logic from AppRouter element: ( <Sidebar> <SidebarLogo /> <SidebarDivider /> - <SidebarItem icon={GraphiQLIcon} to="graphiql" text="GraphiQL" /> + {inputs.items.map((item, index) => ( + <SidebarNavItem {...item.target} key={index} /> + ))} </Sidebar> ), }); diff --git a/packages/frontend-app-api/src/extensions/themes.tsx b/packages/frontend-app-api/src/extensions/themes.tsx new file mode 100644 index 0000000000..ea11b6a638 --- /dev/null +++ b/packages/frontend-app-api/src/extensions/themes.tsx @@ -0,0 +1,44 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { + UnifiedThemeProvider, + themes as builtinThemes, +} from '@backstage/theme'; +import DarkIcon from '@material-ui/icons/Brightness2'; +import LightIcon from '@material-ui/icons/WbSunny'; +import { createThemeExtension } from '@backstage/frontend-plugin-api'; + +export const LightTheme = createThemeExtension({ + id: 'light', + title: 'Light Theme', + variant: 'light', + icon: <LightIcon />, + Provider: ({ children }) => ( + <UnifiedThemeProvider theme={builtinThemes.light} children={children} /> + ), +}); + +export const DarkTheme = createThemeExtension({ + id: 'dark', + title: 'Dark Theme', + variant: 'dark', + icon: <DarkIcon />, + Provider: ({ children }) => ( + <UnifiedThemeProvider theme={builtinThemes.dark} children={children} /> + ), +}); diff --git a/packages/frontend-app-api/src/wiring/createApp.test.tsx b/packages/frontend-app-api/src/wiring/createApp.test.tsx new file mode 100644 index 0000000000..f6172f5a4b --- /dev/null +++ b/packages/frontend-app-api/src/wiring/createApp.test.tsx @@ -0,0 +1,137 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + createExtension, + createPageExtension, + createPlugin, + createThemeExtension, +} from '@backstage/frontend-plugin-api'; +import { createApp, createInstances } from './createApp'; +import { screen } from '@testing-library/react'; +import { MockConfigApi, renderWithEffects } from '@backstage/test-utils'; +import React from 'react'; +import { createRouteRef } from '@backstage/core-plugin-api'; + +describe('createInstances', () => { + it('throws an error when a root extension is parametrized', () => { + const config = new MockConfigApi({ + app: { + extensions: [ + { + root: { + at: '', + }, + }, + ], + }, + }); + const plugins = [ + createPlugin({ + id: 'plugin', + extensions: [], + }), + ]; + expect(() => createInstances({ config, plugins })).toThrow( + "A 'root' extension configuration was detected, but the root extension is not configurable", + ); + }); + + it('throws an error when a root extension is overridden', () => { + const config = new MockConfigApi({}); + const plugins = [ + createPlugin({ + id: 'plugin', + extensions: [ + createExtension({ + id: 'root', + at: 'core.routes/route', + inputs: {}, + output: {}, + factory() {}, + }), + ], + }), + ]; + expect(() => createInstances({ config, plugins })).toThrow( + "The following plugin(s) are overriding the 'root' extension which is forbidden: plugin", + ); + }); + + it('throws an error when duplicated extensions are detected', () => { + const config = new MockConfigApi({}); + + const ExtensionA = createPageExtension({ + id: 'A', + defaultPath: '/', + routeRef: createRouteRef({ id: 'A.route' }), + loader: async () => <div>Extension A</div>, + }); + + const ExtensionB = createPageExtension({ + id: 'B', + defaultPath: '/', + routeRef: createRouteRef({ id: 'B.route' }), + loader: async () => <div>Extension B</div>, + }); + + const PluginA = createPlugin({ + id: 'A', + extensions: [ExtensionA, ExtensionA], + }); + + const PluginB = createPlugin({ + id: 'B', + extensions: [ExtensionA, ExtensionB, ExtensionB], + }); + + const plugins = [PluginA, PluginB]; + + expect(() => createInstances({ config, plugins })).toThrow( + "The following extensions are duplicated: The extension 'A' was provided 2 time(s) by the plugin 'A' and 1 time(s) by the plugin 'B', The extension 'B' was provided 2 time(s) by the plugin 'B'", + ); + }); +}); + +describe('createApp', () => { + it('should allow themes to be installed', async () => { + const app = createApp({ + configLoader: async () => + new MockConfigApi({ + app: { + extensions: [{ 'themes.light': false }, { 'themes.dark': false }], + }, + }), + plugins: [ + createPlugin({ + id: 'test', + extensions: [ + createThemeExtension({ + id: 'derp', + title: 'Derp', + variant: 'dark', + Provider: () => <div>Derp</div>, + }), + ], + }), + ], + }); + + await renderWithEffects(app.createRoot()); + + await expect(screen.findByText('Derp')).resolves.toBeInTheDocument(); + }); +}); diff --git a/packages/frontend-app-api/src/wiring/createApp.tsx b/packages/frontend-app-api/src/wiring/createApp.tsx index 44d534f702..deb19d919d 100644 --- a/packages/frontend-app-api/src/wiring/createApp.tsx +++ b/packages/frontend-app-api/src/wiring/createApp.tsx @@ -49,6 +49,8 @@ import { featureFlagsApiRef, attachComponentData, useRouteRef, + identityApiRef, + AppTheme, } from '@backstage/core-plugin-api'; import { getAvailablePlugins } from './discovery'; import { @@ -62,6 +64,8 @@ import { // eslint-disable-next-line @backstage/no-relative-monorepo-imports import { AppThemeProvider } from '../../../core-app-api/src/app/AppThemeProvider'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports +import { AppIdentityProxy } from '../../../core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy'; +// eslint-disable-next-line @backstage/no-relative-monorepo-imports import { AppContextProvider } from '../../../core-app-api/src/app/AppContext'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports import { LocalStorageFeatureFlags } from '../../../core-app-api/src/apis/implementations/FeatureFlagsApi/LocalStorageFeatureFlags'; @@ -74,10 +78,10 @@ import { apis as defaultApis, components as defaultComponents, icons as defaultIcons, - themes as defaultThemes, } from '../../../app-defaults/src/defaults'; import { BrowserRouter, Route } from 'react-router-dom'; import { SidebarItem } from '@backstage/core-components'; +import { DarkTheme, LightTheme } from '../extensions/themes'; /** @public */ export interface ExtensionTreeNode { @@ -168,7 +172,14 @@ export function createInstances(options: { plugins: BackstagePlugin[]; config: Config; }) { - const builtinExtensions = [Core, CoreRoutes, CoreNav, CoreLayout]; + const builtinExtensions = [ + Core, + CoreRoutes, + CoreNav, + CoreLayout, + LightTheme, + DarkTheme, + ]; // pull in default extension instance from discovered packages // apply config to adjust default extension instances and add more @@ -209,18 +220,18 @@ export function createInstances(options: { function createInstance( instanceParams: ExtensionInstanceParameters, ): ExtensionInstance { - const existingInstance = instances.get(instanceParams.extension.id); + const extensionId = instanceParams.extension.id; + const existingInstance = instances.get(extensionId); if (existingInstance) { return existingInstance; } const attachments = new Map( - Array.from( - attachmentMap.get(instanceParams.extension.id)?.entries() ?? [], - ).map(([inputName, attachmentConfigs]) => [ - inputName, - attachmentConfigs.map(createInstance), - ]), + Array.from(attachmentMap.get(extensionId)?.entries() ?? []).map( + ([inputName, attachmentConfigs]) => { + return [inputName, attachmentConfigs.map(createInstance)]; + }, + ), ); const newInstance = createExtensionInstance({ @@ -230,7 +241,7 @@ export function createInstances(options: { attachments, }); - instances.set(instanceParams.extension.id, newInstance); + instances.set(extensionId, newInstance); return newInstance; } @@ -247,48 +258,71 @@ export function createInstances(options: { /** @public */ export function createApp(options: { plugins: BackstagePlugin[]; - config?: ConfigApi; + configLoader?: () => Promise<ConfigApi>; + pluginLoader?: (ctx: { config: ConfigApi }) => Promise<BackstagePlugin[]>; }): { createRoot(): JSX.Element; } { - const discoveredPlugins = getAvailablePlugins(); - const allPlugins = [...discoveredPlugins, ...options.plugins]; - const appConfig = - options?.config ?? - ConfigReader.fromConfigs(overrideBaseUrlConfigs(defaultConfigLoaderSync())); + async function appLoader() { + const config = + (await options?.configLoader?.()) ?? + ConfigReader.fromConfigs( + overrideBaseUrlConfigs(defaultConfigLoaderSync()), + ); - const { rootInstances } = createInstances({ - plugins: allPlugins, - config: appConfig, - }); + const discoveredPlugins = getAvailablePlugins(); + const loadedPlugins = (await options.pluginLoader?.({ config })) ?? []; + const allPlugins = Array.from( + new Set([...discoveredPlugins, ...options.plugins, ...loadedPlugins]), + ); - const routePaths = extractRouteInfoFromInstanceTree(rootInstances); + const { rootInstances } = createInstances({ + plugins: allPlugins, + config, + }); - const coreInstance = rootInstances.find(({ id }) => id === 'core'); - if (!coreInstance) { - throw Error('Unable to find core extension instance'); + const routePaths = extractRouteInfoFromInstanceTree(rootInstances); + + const coreInstance = rootInstances.find(({ id }) => id === 'core'); + if (!coreInstance) { + throw Error('Unable to find core extension instance'); + } + + const apiHolder = createApiHolder(coreInstance, config); + + const appContext = createLegacyAppContext(allPlugins); + + const rootElements = rootInstances + .map(e => ( + <React.Fragment key={e.id}> + {e.getData(coreExtensionData.reactElement)} + </React.Fragment> + )) + .filter((x): x is JSX.Element => !!x); + + const App = () => ( + <ApiProvider apis={apiHolder}> + <AppContextProvider appContext={appContext}> + <AppThemeProvider> + <RoutingProvider routePaths={routePaths}> + {/* TODO: set base path using the logic from AppRouter */} + <BrowserRouter>{rootElements}</BrowserRouter> + </RoutingProvider> + </AppThemeProvider> + </AppContextProvider> + </ApiProvider> + ); + + return { default: App }; } - const apiHolder = createApiHolder(coreInstance, appConfig); - - const appContext = createLegacyAppContext(allPlugins); - return { createRoot() { - const rootElements = rootInstances - .map(e => e.getData(coreExtensionData.reactElement)) - .filter((x): x is JSX.Element => !!x); + const LazyApp = React.lazy(appLoader); return ( - <ApiProvider apis={apiHolder}> - <AppContextProvider appContext={appContext}> - <AppThemeProvider> - <RoutingProvider routePaths={routePaths}> - {/* TODO: set base path using the logic from AppRouter */} - <BrowserRouter>{rootElements}</BrowserRouter> - </RoutingProvider> - </AppThemeProvider> - </AppContextProvider> - </ApiProvider> + <React.Suspense fallback="Loading..."> + <LazyApp /> + </React.Suspense> ); }, }; @@ -312,7 +346,6 @@ function toLegacyPlugin(plugin: BackstagePlugin): LegacyBackstagePlugin { getApis: notImplemented, getFeatureFlags: notImplemented, provide: notImplemented, - __experimentalReconfigure: notImplemented, }; } @@ -344,13 +377,19 @@ function createApiHolder( ): ApiHolder { const factoryRegistry = new ApiFactoryRegistry(); - const apiFactories = + const pluginApis = coreExtension.attachments .get('apis') ?.map(e => e.getData(coreExtensionData.apiFactory)) .filter((x): x is AnyApiFactory => !!x) ?? []; - for (const factory of apiFactories) { + const themeExtensions = + coreExtension.attachments + .get('themes') + ?.map(e => e.getData(coreExtensionData.theme)) + .filter((x): x is AppTheme => !!x) ?? []; + + for (const factory of [...defaultApis, ...pluginApis]) { factoryRegistry.register('default', factory); } @@ -361,11 +400,43 @@ function createApiHolder( factory: () => new LocalStorageFeatureFlags(), }); + factoryRegistry.register('static', { + api: identityApiRef, + deps: {}, + factory: () => { + const appIdentityProxy = new AppIdentityProxy(); + // TODO: Remove this when sign-in page is migrated + appIdentityProxy.setTarget( + { + getUserId: () => 'guest', + getIdToken: async () => undefined, + getProfile: () => ({ + email: 'guest@example.com', + displayName: 'Guest', + }), + getProfileInfo: async () => ({ + email: 'guest@example.com', + displayName: 'Guest', + }), + getBackstageIdentity: async () => ({ + type: 'user', + userEntityRef: 'user:default/guest', + ownershipEntityRefs: ['user:default/guest'], + }), + getCredentials: async () => ({}), + signOut: async () => {}, + }, + { signOutTargetUrl: '/' }, + ); + return appIdentityProxy; + }, + }); + factoryRegistry.register('static', { api: appThemeApiRef, deps: {}, // TODO: add extension for registering themes - factory: () => AppThemeSelector.createWithStorage(defaultThemes), + factory: () => AppThemeSelector.createWithStorage(themeExtensions), }); factoryRegistry.register('static', { diff --git a/packages/frontend-app-api/src/wiring/parameters.ts b/packages/frontend-app-api/src/wiring/parameters.ts index 1b2831aaca..efe0fbf678 100644 --- a/packages/frontend-app-api/src/wiring/parameters.ts +++ b/packages/frontend-app-api/src/wiring/parameters.ts @@ -196,18 +196,32 @@ export function mergeExtensionParameters(options: { }): ExtensionInstanceParameters[] { const { sources, builtinExtensions, parameters } = options; + const pluginExtensions = sources.flatMap(source => { + return source.extensions.map(extension => ({ ...extension, source })); + }); + + // Prevent root override + if (pluginExtensions.some(({ id }) => id === 'root')) { + const rootPluginIds = pluginExtensions + .filter(({ id }) => id === 'root') + .map(({ source }) => source.id); + throw new Error( + `The following plugin(s) are overriding the 'root' extension which is forbidden: ${rootPluginIds.join( + ',', + )}`, + ); + } + const overrides = [ - ...sources.flatMap(plugin => - plugin.extensions.map(extension => ({ - extension, - params: { - source: plugin, - at: extension.at, - disabled: extension.disabled, - config: undefined as unknown, - }, - })), - ), + ...pluginExtensions.map(({ source, ...extension }) => ({ + extension, + params: { + source, + at: extension.at, + disabled: extension.disabled, + config: undefined as unknown, + }, + })), ...builtinExtensions.map(extension => ({ extension, params: { @@ -219,9 +233,53 @@ export function mergeExtensionParameters(options: { })), ]; + const duplicatedExtensionIds = new Set<string>(); + const duplicatedExtensionData = overrides.reduce< + Record<string, Record<string, number>> + >((data, { extension, params }) => { + const extensionId = extension.id; + const extensionData = data?.[extensionId]; + if (extensionData) duplicatedExtensionIds.add(extensionId); + const pluginId = params.source?.id ?? 'internal'; + const pluginCount = extensionData?.[pluginId] ?? 0; + return { + ...data, + [extensionId]: { ...extensionData, [pluginId]: pluginCount + 1 }, + }; + }, {}); + + if (duplicatedExtensionIds.size > 0) { + throw new Error( + `The following extensions are duplicated: ${Array.from( + duplicatedExtensionIds, + ) + .map( + extensionId => + `The extension '${extensionId}' was provided ${Object.keys( + duplicatedExtensionData[extensionId], + ) + .map( + pluginId => + `${duplicatedExtensionData[extensionId][pluginId]} time(s) by the plugin '${pluginId}'`, + ) + .join(' and ')}`, + ) + .join(', ')}`, + ); + } + for (const overrideParam of parameters) { + const extensionId = overrideParam.id; + + // Prevent root parametrization + if (extensionId === 'root') { + throw new Error( + "A 'root' extension configuration was detected, but the root extension is not configurable", + ); + } + const existingIndex = overrides.findIndex( - e => e.extension.id === overrideParam.id, + e => e.extension.id === extensionId, ); if (existingIndex !== -1) { const existing = overrides[existingIndex]; @@ -243,7 +301,7 @@ export function mergeExtensionParameters(options: { } } } else { - throw new Error(`Extension ${overrideParam.id} does not exist`); + throw new Error(`Extension ${extensionId} does not exist`); } } diff --git a/packages/frontend-plugin-api/CHANGELOG.md b/packages/frontend-plugin-api/CHANGELOG.md index bf0531ab43..2295989418 100644 --- a/packages/frontend-plugin-api/CHANGELOG.md +++ b/packages/frontend-plugin-api/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/frontend-plugin-api +## 0.1.1-next.1 + +### Patch Changes + +- d3a37f55c0: Add support for `SidebarGroup` on the sidebar item extension. +- 52366db5b3: Added `createThemeExtension` and `coreExtensionData.theme`. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/types@1.1.1 + +## 0.1.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/types@1.1.1 + ## 0.1.0 ### Minor Changes diff --git a/packages/frontend-plugin-api/api-report.md b/packages/frontend-plugin-api/api-report.md index 5855976bc4..e28d7d5993 100644 --- a/packages/frontend-plugin-api/api-report.md +++ b/packages/frontend-plugin-api/api-report.md @@ -7,6 +7,7 @@ import { AnyApiFactory } from '@backstage/core-plugin-api'; import { AnyApiRef } from '@backstage/core-plugin-api'; +import { AppTheme } from '@backstage/core-plugin-api'; import { IconComponent } from '@backstage/core-plugin-api'; import { JsonObject } from '@backstage/types'; import { JSX as JSX_2 } from 'react'; @@ -71,6 +72,7 @@ export const coreExtensionData: { apiFactory: ConfigurableExtensionDataRef<AnyApiFactory, {}>; routeRef: ConfigurableExtensionDataRef<RouteRef, {}>; navTarget: ConfigurableExtensionDataRef<NavTarget, {}>; + theme: ConfigurableExtensionDataRef<AppTheme, {}>; }; // @public (undocumented) @@ -199,6 +201,9 @@ export function createSchemaFromZod<TOutput, TInput>( schemaCreator: (zImpl: typeof z) => ZodSchema<TOutput, ZodTypeDef, TInput>, ): PortableSchema<TOutput>; +// @public (undocumented) +export function createThemeExtension(theme: AppTheme): Extension<never>; + // @public (undocumented) export interface Extension<TConfig> { // (undocumented) diff --git a/packages/frontend-plugin-api/package.json b/packages/frontend-plugin-api/package.json index 957c207617..7785b03b7d 100644 --- a/packages/frontend-plugin-api/package.json +++ b/packages/frontend-plugin-api/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/frontend-plugin-api", - "version": "0.1.0", + "version": "0.1.1-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/cypress/src/integration/user/login.spec.ts b/packages/frontend-plugin-api/src/extensions/createThemeExtension.ts similarity index 57% rename from cypress/src/integration/user/login.spec.ts rename to packages/frontend-plugin-api/src/extensions/createThemeExtension.ts index 8e84ebbf06..5c13dd199e 100644 --- a/cypress/src/integration/user/login.spec.ts +++ b/packages/frontend-plugin-api/src/extensions/createThemeExtension.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Backstage Authors + * Copyright 2023 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,19 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/// <reference types="cypress" /> -import 'os'; -describe('Login', () => { - it('should render the login page', () => { - cy.visit('/'); - cy.contains('Select a sign-in method'); +import { createExtension, coreExtensionData } from '../wiring'; +import { AppTheme } from '@backstage/core-plugin-api'; + +/** @public */ +export function createThemeExtension(theme: AppTheme) { + return createExtension({ + id: `themes.${theme.id}`, + at: 'core/themes', + output: { + theme: coreExtensionData.theme, + }, + factory({ bind }) { + bind({ theme }); + }, }); - - it('should be able to login', () => { - cy.get('button').contains('Enter').click(); - cy.url().should('include', '/catalog'); - - cy.contains('artist-lookup'); - }); -}); +} diff --git a/packages/frontend-plugin-api/src/extensions/index.ts b/packages/frontend-plugin-api/src/extensions/index.ts index 0ec0cdf652..00cf4f919c 100644 --- a/packages/frontend-plugin-api/src/extensions/index.ts +++ b/packages/frontend-plugin-api/src/extensions/index.ts @@ -17,3 +17,4 @@ export { createApiExtension } from './createApiExtension'; export { createPageExtension } from './createPageExtension'; export { createNavItemExtension } from './createNavItemExtension'; +export { createThemeExtension } from './createThemeExtension'; diff --git a/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts b/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts index 079d5bcb18..6913501907 100644 --- a/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts +++ b/packages/frontend-plugin-api/src/wiring/coreExtensionData.ts @@ -17,6 +17,7 @@ import { JSX } from 'react'; import { AnyApiFactory, + AppTheme, IconComponent, RouteRef, } from '@backstage/core-plugin-api'; @@ -36,4 +37,5 @@ export const coreExtensionData = { apiFactory: createExtensionDataRef<AnyApiFactory>('core.api.factory'), routeRef: createExtensionDataRef<RouteRef>('core.routing.ref'), navTarget: createExtensionDataRef<NavTarget>('core.nav.target'), + theme: createExtensionDataRef<AppTheme>('core.theme'), }; diff --git a/packages/frontend-plugin-api/src/wiring/createPlugin.test.ts b/packages/frontend-plugin-api/src/wiring/createPlugin.test.ts index 1d45c221af..b14838c17a 100644 --- a/packages/frontend-plugin-api/src/wiring/createPlugin.test.ts +++ b/packages/frontend-plugin-api/src/wiring/createPlugin.test.ts @@ -16,14 +16,14 @@ import React from 'react'; import { createApp } from '@backstage/frontend-app-api'; -import { render, screen } from '@testing-library/react'; +import { screen } from '@testing-library/react'; import { createSchemaFromZod } from '../schema/createSchemaFromZod'; import { createPlugin, BackstagePlugin } from './createPlugin'; import { JsonObject } from '@backstage/types'; import { createExtension } from './createExtension'; import { createExtensionDataRef } from './createExtensionDataRef'; import { coreExtensionData } from './coreExtensionData'; -import { MockConfigApi } from '@backstage/test-utils'; +import { MockConfigApi, renderWithEffects } from '@backstage/test-utils'; import { createExtensionInput } from './createExtensionInput'; const nameExtensionDataRef = createExtensionDataRef<string>('name'); @@ -112,7 +112,7 @@ function createTestAppRoot({ }) { return createApp({ plugins: plugins, - config: new MockConfigApi(config), + configLoader: async () => new MockConfigApi(config), }).createRoot(); } @@ -123,24 +123,26 @@ describe('createPlugin', () => { expect(plugin).toBeDefined(); }); - it('should create a plugin with extension instances', () => { + it('should create a plugin with extension instances', async () => { const plugin = createPlugin({ id: 'empty', extensions: [TechRadarPage, CatalogPage, outputExtension], }); expect(plugin).toBeDefined(); - render( + await renderWithEffects( createTestAppRoot({ plugins: [plugin], config: { app: { extensions: [{ 'core.layout': false }] } }, }), ); - expect(screen.getByText('Names: TechRadar, Catalog')).toBeInTheDocument(); + await expect( + screen.findByText('Names: TechRadar, Catalog'), + ).resolves.toBeInTheDocument(); }); - it('should create a plugin with nested extension instances', () => { + it('should create a plugin with nested extension instances', async () => { const plugin = createPlugin({ id: 'empty', extensions: [ @@ -153,7 +155,7 @@ describe('createPlugin', () => { }); expect(plugin).toBeDefined(); - render( + await renderWithEffects( createTestAppRoot({ plugins: [plugin], config: { @@ -171,10 +173,10 @@ describe('createPlugin', () => { }), ); - expect( - screen.getByText( + await expect( + screen.findByText( 'Names: TechRadar, CatalogRenamed, TechDocs-TechDocsAddon', ), - ).toBeInTheDocument(); + ).resolves.toBeInTheDocument(); }); }); diff --git a/packages/integration-react/CHANGELOG.md b/packages/integration-react/CHANGELOG.md index ff0502e498..8ef2df3709 100644 --- a/packages/integration-react/CHANGELOG.md +++ b/packages/integration-react/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/integration-react +## 1.1.20-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/integration@1.7.1-next.0 + - @backstage/theme@0.4.2 + +## 1.1.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/config@1.1.0 + - @backstage/theme@0.4.2 + ## 1.1.19 ### Patch Changes diff --git a/packages/integration-react/package.json b/packages/integration-react/package.json index d08d3e0d4a..55e15f9b22 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.19", + "version": "1.1.20-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/integration/CHANGELOG.md b/packages/integration/CHANGELOG.md index eabcfd9d4b..961e6eb869 100644 --- a/packages/integration/CHANGELOG.md +++ b/packages/integration/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/integration +## 1.7.1-next.0 + +### Patch Changes + +- 3963d0b885: Ensure that all relevant config fields are properly marked as secret +- Updated dependencies + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + ## 1.7.0 ### Minor Changes diff --git a/packages/integration/package.json b/packages/integration/package.json index 83b137d347..ab78c07edf 100644 --- a/packages/integration/package.json +++ b/packages/integration/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/integration", "description": "Helpers for managing integrations towards external systems", - "version": "1.7.0", + "version": "1.7.1-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/repo-tools/CHANGELOG.md b/packages/repo-tools/CHANGELOG.md index 0b03d4808e..0864fd7347 100644 --- a/packages/repo-tools/CHANGELOG.md +++ b/packages/repo-tools/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/repo-tools +## 0.3.5-next.0 + +### Patch Changes + +- de42eebaaf: Bumped dev dependencies `@types/node` and `mock-fs`. +- Updated dependencies + - @backstage/cli-common@0.1.13-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/cli-node@0.1.5-next.0 + - @backstage/errors@1.2.2 + ## 0.3.4 ### Patch Changes diff --git a/packages/repo-tools/package.json b/packages/repo-tools/package.json index 0eb881aea8..8fc04fce71 100644 --- a/packages/repo-tools/package.json +++ b/packages/repo-tools/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/repo-tools", "description": "CLI for Backstage repo tooling ", - "version": "0.3.4", + "version": "0.3.5-next.0", "publishConfig": { "access": "public" }, diff --git a/packages/techdocs-cli-embedded-app/CHANGELOG.md b/packages/techdocs-cli-embedded-app/CHANGELOG.md index ec60ebb2fd..45494ccba1 100644 --- a/packages/techdocs-cli-embedded-app/CHANGELOG.md +++ b/packages/techdocs-cli-embedded-app/CHANGELOG.md @@ -1,5 +1,43 @@ # techdocs-cli-embedded-app +## 0.2.87-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.14.0-next.1 + - @backstage/plugin-techdocs@1.7.1-next.1 + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-app-api@1.10.1-next.1 + - @backstage/app-defaults@1.4.4-next.1 + - @backstage/test-utils@1.4.4-next.1 + - @backstage/cli@0.23.0-next.1 + - @backstage/integration-react@1.1.20-next.1 + - @backstage/plugin-techdocs-react@1.1.12-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## 0.2.87-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/test-utils@1.4.4-next.0 + - @backstage/cli@0.23.0-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/plugin-catalog@1.14.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/integration-react@1.1.20-next.0 + - @backstage/plugin-techdocs@1.7.1-next.0 + - @backstage/app-defaults@1.4.4-next.0 + - @backstage/config@1.1.0 + - @backstage/core-app-api@1.10.1-next.0 + - @backstage/plugin-techdocs-react@1.1.12-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + ## 0.2.86 ### Patch Changes diff --git a/packages/techdocs-cli-embedded-app/cypress.json b/packages/techdocs-cli-embedded-app/cypress.json deleted file mode 100644 index 5de7ebffea..0000000000 --- a/packages/techdocs-cli-embedded-app/cypress.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "baseUrl": "http://localhost:3001", - "fixturesFolder": false, - "pluginsFile": false -} diff --git a/packages/techdocs-cli-embedded-app/cypress/.eslintrc.json b/packages/techdocs-cli-embedded-app/cypress/.eslintrc.json deleted file mode 100644 index b903ff250a..0000000000 --- a/packages/techdocs-cli-embedded-app/cypress/.eslintrc.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "plugins": ["cypress"], - "extends": ["plugin:cypress/recommended"], - "rules": { - "jest/expect-expect": [ - "error", - { - "assertFunctionNames": ["expect", "cy.contains", "cy.**.should"] - } - ] - } -} diff --git a/packages/techdocs-cli-embedded-app/package.json b/packages/techdocs-cli-embedded-app/package.json index 4d49be6016..21eee41e19 100644 --- a/packages/techdocs-cli-embedded-app/package.json +++ b/packages/techdocs-cli-embedded-app/package.json @@ -1,6 +1,6 @@ { "name": "techdocs-cli-embedded-app", - "version": "0.2.86", + "version": "0.2.87-next.1", "private": true, "backstage": { "role": "frontend" @@ -42,21 +42,14 @@ "@testing-library/user-event": "^14.0.0", "@types/react": "*", "@types/react-dom": "*", - "cross-env": "^7.0.0", - "cypress": "^10.0.0", - "eslint-plugin-cypress": "^2.10.3", - "start-server-and-test": "^1.10.11" + "cross-env": "^7.0.0" }, "scripts": { "start": "backstage-cli package start --config ./app-config.yaml", "build": "backstage-cli package build --config ./app-config.yaml", "clean": "backstage-cli package clean", "test": "backstage-cli package test", - "lint": "backstage-cli package lint", - "test:e2e": "cross-env PORT=3001 start-server-and-test start http://localhost:3001 cy:dev", - "test:e2e:ci": "cross-env PORT=3001 start-server-and-test start http://localhost:3001 cy:run", - "cy:dev": "cypress open", - "cy:run": "cypress run" + "lint": "backstage-cli package lint" }, "prettier": "@spotify/prettier-config", "browserslist": { diff --git a/packages/techdocs-cli-embedded-app/public/index.html b/packages/techdocs-cli-embedded-app/public/index.html index c6083b3dd2..fc758eee32 100644 --- a/packages/techdocs-cli-embedded-app/public/index.html +++ b/packages/techdocs-cli-embedded-app/public/index.html @@ -8,7 +8,6 @@ name="description" content="Backstage is an open platform for building developer portals" /> - <link rel="apple-touch-icon" href="<%= publicPath %>/logo192.png" /> <!-- manifest.json provides metadata used when your web app is installed on a user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/ diff --git a/packages/techdocs-cli/CHANGELOG.md b/packages/techdocs-cli/CHANGELOG.md index b0d620a056..abafa808fc 100644 --- a/packages/techdocs-cli/CHANGELOG.md +++ b/packages/techdocs-cli/CHANGELOG.md @@ -1,5 +1,29 @@ # @techdocs/cli +## 1.5.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/plugin-techdocs-node@1.8.2-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/cli-common@0.1.13-next.0 + +## 1.5.2-next.0 + +### Patch Changes + +- de42eebaaf: Bumped dev dependencies `@types/node` and `mock-fs`. +- 2b6e572051: Restructured tests. +- Updated dependencies + - @backstage/cli-common@0.1.13-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/plugin-techdocs-node@1.8.2-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + ## 1.5.0 ### Minor Changes diff --git a/packages/techdocs-cli/README.md b/packages/techdocs-cli/README.md index 85c0075946..e7ae51053b 100644 --- a/packages/techdocs-cli/README.md +++ b/packages/techdocs-cli/README.md @@ -75,38 +75,3 @@ pip install mkdocs-techdocs-core ``` Then run `yarn test`. - -#### Cypress (Integration and Visual regression) tests - -Running cypress tests requires you to run the CLI locally against our example docs. - -Run the local version of techdocs-cli against the example docs: - -```sh -# From the root of this repository run -# NOTE: This will build the techdocs-cli-embedded-app and copy the output into the cli dist directory -yarn build --scope @techdocs/cli - -# Navigate to the example project -cd packages/techdocs-cli/src/example-docs - -# Now execute the techdocs-cli serve command -../../bin/techdocs-cli serve -``` - -In another shell, run the cypress tests: - -```sh -# From the root of the project, navigate to the techdocs-cli package -cd packages/techdocs-cli - -# Run tests -yarn test:cypress -``` - -This will launch a cypress app where you can run the two different tests: - -- `backstage_serve` - will run against the backstage server -- `mkdocs_serve` - will run test against the mkdocs server - -> If its the first time you run Cypress, it will run a "Verifying Cypress can run" step. This step can result in a "Cypress verification timed out" error. If that is the case, let the verification step run and then run the command again and it should succeed. diff --git a/packages/techdocs-cli/e2e-test.config.js b/packages/techdocs-cli/cli-e2e-test.config.js similarity index 93% rename from packages/techdocs-cli/e2e-test.config.js rename to packages/techdocs-cli/cli-e2e-test.config.js index 2fa92462ab..b2e6e53918 100644 --- a/packages/techdocs-cli/e2e-test.config.js +++ b/packages/techdocs-cli/cli-e2e-test.config.js @@ -18,5 +18,5 @@ const path = require('path'); module.exports = require('@backstage/cli/config/jest').then(baseConfig => ({ ...baseConfig, - rootDir: path.resolve(__dirname, 'e2e-tests'), + rootDir: path.resolve(__dirname, 'cli-e2e-tests'), })); diff --git a/packages/techdocs-cli/e2e-tests/techdocs-cli.test.ts b/packages/techdocs-cli/cli-e2e-tests/techdocs-cli.test.ts similarity index 100% rename from packages/techdocs-cli/e2e-tests/techdocs-cli.test.ts rename to packages/techdocs-cli/cli-e2e-tests/techdocs-cli.test.ts diff --git a/packages/techdocs-cli/cypress.config.js b/packages/techdocs-cli/cypress.config.js deleted file mode 100644 index abaa324d76..0000000000 --- a/packages/techdocs-cli/cypress.config.js +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2022 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import { defineConfig } from 'cypress'; -import { initPlugin } from '@frsource/cypress-plugin-visual-regression-diff/plugins'; - -module.exports = defineConfig({ - e2e: { - setupNodeEvents(on, config) { - initPlugin(on, config); - }, - - excludeSpecPattern: ['**/__snapshots__/*', '**/__image_snapshots__/*'], - }, - viewportWidth: 1920, - viewportHeight: 1080, - includeShadowDom: true, -}); diff --git a/packages/techdocs-cli/cypress/.eslintrc.json b/packages/techdocs-cli/cypress/.eslintrc.json deleted file mode 100644 index 06965a82da..0000000000 --- a/packages/techdocs-cli/cypress/.eslintrc.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "plugins": ["cypress"], - "extends": ["plugin:cypress/recommended"], - "rules": { - "jest/expect-expect": [ - "error", - { - "assertFunctionNames": ["expect", "cy.contains", "cy.document"] - } - ] - } -} diff --git a/packages/techdocs-cli/cypress/e2e/__image_snapshots__/TechDocs Live Preview - Backstage Serve toMatchImageSnapshot - Backstage TechDocs Page #0.png b/packages/techdocs-cli/cypress/e2e/__image_snapshots__/TechDocs Live Preview - Backstage Serve toMatchImageSnapshot - Backstage TechDocs Page #0.png deleted file mode 100644 index 99fc1ea483..0000000000 Binary files a/packages/techdocs-cli/cypress/e2e/__image_snapshots__/TechDocs Live Preview - Backstage Serve toMatchImageSnapshot - Backstage TechDocs Page #0.png and /dev/null differ diff --git a/packages/techdocs-cli/cypress/e2e/__image_snapshots__/TechDocs Live Preview - MkDocs Serve toMatchImageSnapshot - MkDocs Page #0.png b/packages/techdocs-cli/cypress/e2e/__image_snapshots__/TechDocs Live Preview - MkDocs Serve toMatchImageSnapshot - MkDocs Page #0.png deleted file mode 100644 index e6c63d5d57..0000000000 Binary files a/packages/techdocs-cli/cypress/e2e/__image_snapshots__/TechDocs Live Preview - MkDocs Serve toMatchImageSnapshot - MkDocs Page #0.png and /dev/null differ diff --git a/packages/techdocs-cli/cypress/e2e/backstage_serve.cy.js b/packages/techdocs-cli/cypress/e2e/backstage_serve.cy.js deleted file mode 100644 index 0267c8bfe6..0000000000 --- a/packages/techdocs-cli/cypress/e2e/backstage_serve.cy.js +++ /dev/null @@ -1,58 +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. - */ -/// <reference types="cypress" /> -describe('TechDocs Live Preview - Backstage Serve', () => { - it('successfully serves documentation', () => { - cy.visit(`${Cypress.env('backstageBaseUrl')}/docs/default/component/local`); - cy.contains('hello mock docs'); - }); - - it('successfully navigates to sub page of documentation', () => { - cy.contains('SubDocs').click(); - cy.contains('Home 2').click(); - cy.contains( - 'This is an md file in another docs folder using the MkDocs Monorepo Plugin', - ); - }); - - it('successfully renders all Backstage main elements', () => { - cy.contains('header', 'Live preview environment'); - cy.get('[data-testid="sidebar-root"]') - .children() - .should('have.length.gt', 0); - }); - - it('successfully renders all extracted MkDocs main elements', () => { - // as it gets replaced by Backstage header - cy.get('.md-header').should('have.length', 0); - cy.get('.md-main').should('have.length', 1); - cy.contains( - '.md-main', - 'This is an md file in another docs folder using the MkDocs Monorepo Plugin', - ); - cy.get('.md-sidebar.md-sidebar--primary').should('have.length', 1); - cy.get('.md-sidebar.md-sidebar--primary').should('have.length', 1); - cy.get('.md-footer').should('have.length', 1); - }); - - it('matchImage - Backstage TechDocs Page', () => { - cy.visit( - `${Cypress.env('backstageBaseUrl')}/docs/default/component/local`, - ).then(() => { - cy.document().matchImage(); - }); - }); -}); diff --git a/packages/techdocs-cli/cypress/e2e/mkdocs_serve.cy.js b/packages/techdocs-cli/cypress/e2e/mkdocs_serve.cy.js deleted file mode 100644 index d5417e615f..0000000000 --- a/packages/techdocs-cli/cypress/e2e/mkdocs_serve.cy.js +++ /dev/null @@ -1,48 +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. - */ -/// <reference types="cypress" /> -describe('TechDocs Live Preview - MkDocs Serve', () => { - it('successfully serves documentation', () => { - cy.visit(Cypress.env('mkdocsBaseUrl')); - cy.contains('hello mock docs'); - }); - - it('successfully navigates to sub page of documentation', () => { - cy.contains('SubDocs').click(); - cy.contains('Home 2').click(); - cy.contains( - 'This is an md file in another docs folder using the MkDocs Monorepo Plugin', - ); - }); - - it('successfully renders all main elements', () => { - cy.get('.md-header').should('have.length', 1); - cy.get('.md-main').should('have.length', 1); - cy.contains( - '.md-main', - 'This is an md file in another docs folder using the MkDocs Monorepo Plugin', - ); - cy.get('.md-sidebar.md-sidebar--primary').should('have.length', 1); - cy.get('.md-sidebar.md-sidebar--primary').should('have.length', 1); - cy.get('.md-footer').should('have.length', 1); - }); - - it('matchImage - MkDocs Page', () => { - cy.visit(Cypress.env('mkdocsBaseUrl')).then(() => { - cy.document().matchImage(); - }); - }); -}); diff --git a/packages/techdocs-cli/cypress/fixtures/example.json b/packages/techdocs-cli/cypress/fixtures/example.json deleted file mode 100644 index 02e4254378..0000000000 --- a/packages/techdocs-cli/cypress/fixtures/example.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "Using fixtures to represent data", - "email": "hello@cypress.io", - "body": "Fixtures are a great way to mock data for responses to routes" -} diff --git a/packages/techdocs-cli/cypress/screenshots/backstage_serve.js/TechDocs Live Preview - Backstage Serve toMatchImageSnapshot - Backstage Header #0.png b/packages/techdocs-cli/cypress/screenshots/backstage_serve.js/TechDocs Live Preview - Backstage Serve toMatchImageSnapshot - Backstage Header #0.png deleted file mode 100644 index 867e8ddd81..0000000000 Binary files a/packages/techdocs-cli/cypress/screenshots/backstage_serve.js/TechDocs Live Preview - Backstage Serve toMatchImageSnapshot - Backstage Header #0.png and /dev/null differ diff --git a/packages/techdocs-cli/cypress/screenshots/backstage_serve.js/TechDocs Live Preview - Backstage Serve toMatchImageSnapshot - Backstage TechDocs Page #0 (1).png b/packages/techdocs-cli/cypress/screenshots/backstage_serve.js/TechDocs Live Preview - Backstage Serve toMatchImageSnapshot - Backstage TechDocs Page #0 (1).png deleted file mode 100644 index 3f1078345d..0000000000 Binary files a/packages/techdocs-cli/cypress/screenshots/backstage_serve.js/TechDocs Live Preview - Backstage Serve toMatchImageSnapshot - Backstage TechDocs Page #0 (1).png and /dev/null differ diff --git a/packages/techdocs-cli/cypress/screenshots/backstage_serve.js/TechDocs Live Preview - Backstage Serve toMatchImageSnapshot - Backstage TechDocs Page #0 (2).png b/packages/techdocs-cli/cypress/screenshots/backstage_serve.js/TechDocs Live Preview - Backstage Serve toMatchImageSnapshot - Backstage TechDocs Page #0 (2).png deleted file mode 100644 index c576be51c5..0000000000 Binary files a/packages/techdocs-cli/cypress/screenshots/backstage_serve.js/TechDocs Live Preview - Backstage Serve toMatchImageSnapshot - Backstage TechDocs Page #0 (2).png and /dev/null differ diff --git a/packages/techdocs-cli/cypress/screenshots/backstage_serve.js/TechDocs Live Preview - Backstage Serve toMatchImageSnapshot - Backstage TechDocs Page #0.png b/packages/techdocs-cli/cypress/screenshots/backstage_serve.js/TechDocs Live Preview - Backstage Serve toMatchImageSnapshot - Backstage TechDocs Page #0.png deleted file mode 100644 index 3f1078345d..0000000000 Binary files a/packages/techdocs-cli/cypress/screenshots/backstage_serve.js/TechDocs Live Preview - Backstage Serve toMatchImageSnapshot - Backstage TechDocs Page #0.png and /dev/null differ diff --git a/packages/techdocs-cli/cypress/support/commands.js b/packages/techdocs-cli/cypress/support/commands.js deleted file mode 100644 index a8d6a5fdb7..0000000000 --- a/packages/techdocs-cli/cypress/support/commands.js +++ /dev/null @@ -1,40 +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. - */ - -// This example commands.js shows you how to -// create various custom commands and overwrite -// existing commands. -// -// For more comprehensive examples of custom -// commands please read more here: -// https://on.cypress.io/custom-commands -// *********************************************** -// -// -// -- This is a parent command -- -// Cypress.Commands.add('login', (email, password) => { ... }) -// -// -// -- This is a child command -- -// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... }) -// -// -// -- This is a dual command -- -// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... }) -// -// -// -- This will overwrite an existing command -- -// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) diff --git a/packages/techdocs-cli/cypress/support/e2e.js b/packages/techdocs-cli/cypress/support/e2e.js deleted file mode 100644 index f06a08e9a5..0000000000 --- a/packages/techdocs-cli/cypress/support/e2e.js +++ /dev/null @@ -1,36 +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. - */ - -// This example support/index.js is processed and -// loaded automatically before your test files. -// -// This is a great place to put global configuration and -// behavior that modifies Cypress. -// -// You can change the location of this file or turn off -// automatically serving support files with the -// 'supportFile' configuration option. -// -// You can read more here: -// https://on.cypress.io/configuration -// *********************************************************** - -// Import commands.js using ES2015 syntax: -import './commands'; -import '@frsource/cypress-plugin-visual-regression-diff/commands'; - -// Alternatively you can use CommonJS syntax: -// require('./commands') diff --git a/packages/techdocs-cli/package.json b/packages/techdocs-cli/package.json index 9a8c420ffd..14120ab801 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.5.0", + "version": "1.5.2-next.1", "publishConfig": { "access": "public" }, @@ -27,9 +27,8 @@ "clean": "backstage-cli package clean", "lint": "backstage-cli package lint", "test": "backstage-cli package test", - "test:e2e": "backstage-cli test --config e2e-test.config.js", - "test:e2e:ci": "backstage-cli test --config e2e-test.config.js --watchAll=false --ci", - "test:cypress": "cypress open", + "test:e2e": "backstage-cli test --config cli-e2e-test.config.js", + "test:e2e:ci": "backstage-cli test --config cli-e2e-test.config.js --watchAll=false --ci", "prepack": "./scripts/prepack.sh" }, "bin": { @@ -37,14 +36,12 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", - "@frsource/cypress-plugin-visual-regression-diff": "^3.2.8", "@types/commander": "^2.12.2", "@types/fs-extra": "^9.0.6", "@types/http-proxy": "^1.17.4", "@types/node": "^18.17.8", "@types/serve-handler": "^6.1.0", "@types/webpack-env": "^1.15.3", - "cypress": "^10.0.0", "find-process": "^1.4.5", "nodemon": "^3.0.1", "techdocs-cli-embedded-app": "link:../techdocs-cli-embedded-app", diff --git a/packages/test-utils/CHANGELOG.md b/packages/test-utils/CHANGELOG.md index b44f54e2ab..4cab843d01 100644 --- a/packages/test-utils/CHANGELOG.md +++ b/packages/test-utils/CHANGELOG.md @@ -1,5 +1,33 @@ # @backstage/test-utils +## 1.4.4-next.1 + +### Patch Changes + +- 1a0616fa10: Add missing resource and template app icons +- Updated dependencies + - @backstage/core-app-api@1.10.1-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/plugin-permission-react@0.4.16-next.0 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.8 + +## 1.4.4-next.0 + +### Patch Changes + +- 322bbcae24: Removed the alpha `MockPluginProvider` export since the plugin configuration API has been removed. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/core-app-api@1.10.1-next.0 + - @backstage/plugin-permission-react@0.4.16-next.0 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.8 + ## 1.4.3 ### Patch Changes @@ -264,7 +292,7 @@ ### Minor Changes -- 7908d72e033: Introduce a new global config parameter, `auth.enableExperimentalRedirectFlow`. When enabled, auth will happen with an in-window redirect flow rather than through a popup window. +- 7908d72e033: Introduce a new global config parameter, `enableExperimentalRedirectFlow`. When enabled, auth will happen with an in-window redirect flow rather than through a popup window. ### Patch Changes @@ -322,7 +350,7 @@ ### Minor Changes -- 7908d72e033: Introduce a new global config parameter, `auth.enableExperimentalRedirectFlow`. When enabled, auth will happen with an in-window redirect flow rather than through a popup window. +- 7908d72e033: Introduce a new global config parameter, `enableExperimentalRedirectFlow`. When enabled, auth will happen with an in-window redirect flow rather than through a popup window. ### Patch Changes diff --git a/packages/test-utils/alpha-api-report.md b/packages/test-utils/alpha-api-report.md index 4a9fd2e5a4..945c754f83 100644 --- a/packages/test-utils/alpha-api-report.md +++ b/packages/test-utils/alpha-api-report.md @@ -4,17 +4,10 @@ ```ts import { Observable } from '@backstage/types'; -import { PropsWithChildren } from 'react'; -import { default as React_2 } from 'react'; import { TranslationApi } from '@backstage/core-plugin-api/alpha'; import { TranslationRef } from '@backstage/core-plugin-api/alpha'; import { TranslationSnapshot } from '@backstage/core-plugin-api/alpha'; -// @alpha -export const MockPluginProvider: ({ - children, -}: PropsWithChildren<{}>) => React_2.JSX.Element; - // @alpha (undocumented) export class MockTranslationApi implements TranslationApi { // (undocumented) diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index 875f67ffbb..b972a6a824 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/test-utils", "description": "Utilities to test Backstage plugins and apps.", - "version": "1.4.3", + "version": "1.4.4-next.1", "publishConfig": { "access": "public" }, diff --git a/packages/test-utils/src/alpha.ts b/packages/test-utils/src/alpha.ts index c6801993bc..2077ad3586 100644 --- a/packages/test-utils/src/alpha.ts +++ b/packages/test-utils/src/alpha.ts @@ -14,5 +14,4 @@ * limitations under the License. */ -export * from './testUtils/MockPluginProvider'; export * from './testUtils/apis/TranslationApi'; diff --git a/packages/test-utils/src/testUtils/MockPluginProvider.tsx b/packages/test-utils/src/testUtils/MockPluginProvider.tsx deleted file mode 100644 index 25442ae267..0000000000 --- a/packages/test-utils/src/testUtils/MockPluginProvider.tsx +++ /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 React, { PropsWithChildren } from 'react'; -import { PluginProvider } from '@backstage/core-plugin-api/alpha'; -import { createPlugin } from '@backstage/core-plugin-api'; - -/** - * Mock for PluginProvider to use in unit tests - * @alpha - */ -export const MockPluginProvider = ({ children }: PropsWithChildren<{}>) => { - type TestInputPluginOptions = {}; - type TestPluginOptions = {}; - const plugin = createPlugin({ - id: 'my-plugin', - __experimentalConfigure(_: TestInputPluginOptions): TestPluginOptions { - return {}; - }, - }); - - return <PluginProvider plugin={plugin}>{children}</PluginProvider>; -}; diff --git a/packages/test-utils/src/testUtils/appWrappers.tsx b/packages/test-utils/src/testUtils/appWrappers.tsx index ebded4d813..8bc69e184a 100644 --- a/packages/test-utils/src/testUtils/appWrappers.tsx +++ b/packages/test-utils/src/testUtils/appWrappers.tsx @@ -16,24 +16,23 @@ import React, { ComponentType, - ReactNode, - ReactElement, PropsWithChildren, + ReactElement, + ReactNode, } from 'react'; -import { MemoryRouter } from 'react-router-dom'; -import { Route } from 'react-router-dom'; -import { UnifiedThemeProvider, themes } from '@backstage/theme'; +import { MemoryRouter, Route } from 'react-router-dom'; +import { themes, UnifiedThemeProvider } from '@backstage/theme'; import MockIcon from '@material-ui/icons/AcUnit'; import { createSpecializedApp } from '@backstage/core-app-api'; import { - BootErrorPageProps, - RouteRef, - ExternalRouteRef, attachComponentData, + BootErrorPageProps, createRouteRef, + ExternalRouteRef, + RouteRef, } from '@backstage/core-plugin-api'; import { MatcherFunction, RenderResult } from '@testing-library/react'; -import { renderWithEffects, LegacyRootOption } from './testingLibrary'; +import { LegacyRootOption, renderWithEffects } from './testingLibrary'; import { defaultApis } from './defaultApis'; import { mockApis } from './mockApis'; @@ -45,6 +44,8 @@ const mockIcons = { 'kind:location': MockIcon, 'kind:system': MockIcon, 'kind:user': MockIcon, + 'kind:resource': MockIcon, + 'kind:template': MockIcon, brokenImage: MockIcon, catalog: MockIcon, diff --git a/playwright.config.ts b/playwright.config.ts new file mode 100644 index 0000000000..ee8228e413 --- /dev/null +++ b/playwright.config.ts @@ -0,0 +1,67 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { defineConfig } from '@playwright/test'; +import { generateProjects } from '@backstage/e2e-test-utils/playwright'; + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + timeout: 30_000, + + expect: { + timeout: 5_000, + }, + + // Run your local dev server before starting the tests + webServer: process.env.CI + ? [] + : [ + { + command: 'yarn start', + port: 3000, + reuseExistingServer: true, + timeout: 60_000, + }, + // TODO: Before encouraging e2e tests for backend we'll want to provide better utilities for mocking auth + // { + // command: 'yarn start-backend', + // port: 7007, + // reuseExistingServer: true, + // timeout: 60_000, + // }, + ], + + forbidOnly: !!process.env.CI, + + retries: process.env.CI ? 2 : 0, + + reporter: [['html', { open: 'never', outputFolder: 'e2e-test-report' }]], + + use: { + actionTimeout: 0, + baseURL: + process.env.PLAYWRIGHT_URL ?? + (process.env.CI ? 'http://localhost:7007' : 'http://localhost:3000'), + screenshot: 'only-on-failure', + trace: 'on-first-retry', + }, + + outputDir: 'node_modules/.cache/e2e-test-results', + + projects: generateProjects(), // Find all packages with e2e-test folders +}); diff --git a/plugins/adr-backend/CHANGELOG.md b/plugins/adr-backend/CHANGELOG.md index 288acd07d6..e2acb92554 100644 --- a/plugins/adr-backend/CHANGELOG.md +++ b/plugins/adr-backend/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/plugin-adr-backend +## 0.4.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/plugin-adr-common@0.2.16-next.0 + - @backstage/plugin-search-common@1.2.6 + +## 0.4.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/plugin-adr-common@0.2.16-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/plugin-search-common@1.2.6 + ## 0.4.0 ### Minor Changes diff --git a/plugins/adr-backend/package.json b/plugins/adr-backend/package.json index 8b81223a56..580e3064af 100644 --- a/plugins/adr-backend/package.json +++ b/plugins/adr-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-adr-backend", - "version": "0.4.0", + "version": "0.4.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/adr-common/CHANGELOG.md b/plugins/adr-common/CHANGELOG.md index 73d9660fe2..961562e016 100644 --- a/plugins/adr-common/CHANGELOG.md +++ b/plugins/adr-common/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-adr-common +## 0.2.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/plugin-search-common@1.2.6 + ## 0.2.15 ### Patch Changes diff --git a/plugins/adr-common/package.json b/plugins/adr-common/package.json index 68cd5e6234..5e8e236b42 100644 --- a/plugins/adr-common/package.json +++ b/plugins/adr-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-adr-common", "description": "Common functionalities for the adr plugin", - "version": "0.2.15", + "version": "0.2.16-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/adr/CHANGELOG.md b/plugins/adr/CHANGELOG.md index e433fd174b..950e2c7ca3 100644 --- a/plugins/adr/CHANGELOG.md +++ b/plugins/adr/CHANGELOG.md @@ -1,5 +1,37 @@ # @backstage/plugin-adr +## 0.6.8-next.1 + +### Patch Changes + +- 1204e7628e: Create an experimental `AdrSearchResultItemExtension` for declarative integration with Backstage; it can be accessed via the `/alpha` import. +- Updated dependencies + - @backstage/frontend-plugin-api@0.1.1-next.1 + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-search-react@1.7.1-next.1 + - @backstage/integration-react@1.1.20-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-adr-common@0.2.16-next.0 + - @backstage/plugin-search-common@1.2.6 + +## 0.6.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/integration-react@1.1.20-next.0 + - @backstage/plugin-adr-common@0.2.16-next.0 + - @backstage/plugin-search-react@1.7.1-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-search-common@1.2.6 + ## 0.6.7 ### Patch Changes diff --git a/plugins/adr/alpha-api-report.md b/plugins/adr/alpha-api-report.md index 7ce9f6f055..9d0bd071b1 100644 --- a/plugins/adr/alpha-api-report.md +++ b/plugins/adr/alpha-api-report.md @@ -3,8 +3,16 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +import { BackstagePlugin } from '@backstage/frontend-plugin-api'; +import { Extension } from '@backstage/frontend-plugin-api'; import { TranslationRef } from '@backstage/core-plugin-api/alpha'; +// @alpha (undocumented) +export const AdrSearchResultListItemExtension: Extension<{ + lineClamp: number; + noTrack: boolean; +}>; + // @alpha (undocumented) export const adrTranslationRef: TranslationRef< 'adr', @@ -15,5 +23,9 @@ export const adrTranslationRef: TranslationRef< } >; +// @alpha (undocumented) +const _default: BackstagePlugin; +export default _default; + // (No @packageDocumentation comment for this package) ``` diff --git a/plugins/adr/api-report.md b/plugins/adr/api-report.md index 6ed7b68196..9ce5834574 100644 --- a/plugins/adr/api-report.md +++ b/plugins/adr/api-report.md @@ -72,7 +72,6 @@ export const adrPlugin: BackstagePlugin< { root: RouteRef<undefined>; }, - {}, {} >; diff --git a/plugins/adr/package.json b/plugins/adr/package.json index 5a8eabe337..94d8250993 100644 --- a/plugins/adr/package.json +++ b/plugins/adr/package.json @@ -1,18 +1,18 @@ { "name": "@backstage/plugin-adr", - "version": "0.6.7", + "version": "0.6.8-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", "exports": { ".": "./src/index.ts", - "./alpha": "./src/alpha.ts", + "./alpha": "./src/alpha.tsx", "./package.json": "./package.json" }, "typesVersions": { "*": { "alpha": [ - "src/alpha.ts" + "src/alpha.tsx" ], "package.json": [ "package.json" @@ -45,6 +45,7 @@ "@backstage/catalog-model": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", + "@backstage/frontend-plugin-api": "workspace:^", "@backstage/integration-react": "workspace:^", "@backstage/plugin-adr-common": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", diff --git a/plugins/adr/src/alpha.tsx b/plugins/adr/src/alpha.tsx new file mode 100644 index 0000000000..1f6fa0711d --- /dev/null +++ b/plugins/adr/src/alpha.tsx @@ -0,0 +1,58 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { + createPlugin, + createSchemaFromZod, +} from '@backstage/frontend-plugin-api'; +import { createSearchResultListItemExtension } from '@backstage/plugin-search-react/alpha'; +import { AdrDocument } from '@backstage/plugin-adr-common'; + +export * from './translations'; + +function isAdrDocument(result: any): result is AdrDocument { + return result.entityRef; +} + +/** @alpha */ +export const AdrSearchResultListItemExtension = + createSearchResultListItemExtension({ + id: 'adr', + configSchema: createSchemaFromZod(z => + z.object({ + // TODO: Define how the icon can be configurable + noTrack: z.boolean().default(false), + lineClamp: z.number().default(5), + }), + ), + predicate: result => result.type === 'adr', + component: async ({ config }) => { + const { AdrSearchResultListItem } = await import( + './search/AdrSearchResultListItem' + ); + return ({ result, ...rest }) => + isAdrDocument(result) ? ( + <AdrSearchResultListItem {...rest} {...config} result={result} /> + ) : null; + }, + }); + +/** @alpha */ +export default createPlugin({ + id: 'adr', + extensions: [AdrSearchResultListItemExtension], +}); diff --git a/plugins/airbrake-backend/CHANGELOG.md b/plugins/airbrake-backend/CHANGELOG.md index d4e68fdf50..ba6e94f7eb 100644 --- a/plugins/airbrake-backend/CHANGELOG.md +++ b/plugins/airbrake-backend/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-airbrake-backend +## 0.3.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + +## 0.3.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + ## 0.3.0 ### Minor Changes diff --git a/plugins/airbrake-backend/package.json b/plugins/airbrake-backend/package.json index dbe7054705..e7bbcc9310 100644 --- a/plugins/airbrake-backend/package.json +++ b/plugins/airbrake-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-airbrake-backend", - "version": "0.3.0", + "version": "0.3.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/airbrake/CHANGELOG.md b/plugins/airbrake/CHANGELOG.md index 9cface3b85..712f785b2e 100644 --- a/plugins/airbrake/CHANGELOG.md +++ b/plugins/airbrake/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/plugin-airbrake +## 0.3.25-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/test-utils@1.4.4-next.1 + - @backstage/dev-utils@1.0.22-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## 0.3.25-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/test-utils@1.4.4-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/dev-utils@1.0.22-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + ## 0.3.24 ### Patch Changes diff --git a/plugins/airbrake/api-report.md b/plugins/airbrake/api-report.md index a04d57d7e9..66f9b19bc8 100644 --- a/plugins/airbrake/api-report.md +++ b/plugins/airbrake/api-report.md @@ -13,7 +13,6 @@ export const airbrakePlugin: BackstagePlugin< { root: RouteRef<undefined>; }, - {}, {} >; diff --git a/plugins/airbrake/package.json b/plugins/airbrake/package.json index f5a8f1debe..003da7d232 100644 --- a/plugins/airbrake/package.json +++ b/plugins/airbrake/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-airbrake", - "version": "0.3.24", + "version": "0.3.25-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/allure/CHANGELOG.md b/plugins/allure/CHANGELOG.md index 5b7971054a..956f4d79fa 100644 --- a/plugins/allure/CHANGELOG.md +++ b/plugins/allure/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-allure +## 0.1.41-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## 0.1.41-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + ## 0.1.40 ### Patch Changes diff --git a/plugins/allure/api-report.md b/plugins/allure/api-report.md index a192851f26..69bb740271 100644 --- a/plugins/allure/api-report.md +++ b/plugins/allure/api-report.md @@ -18,7 +18,6 @@ export const allurePlugin: BackstagePlugin< { root: RouteRef<undefined>; }, - {}, {} >; diff --git a/plugins/allure/package.json b/plugins/allure/package.json index 104dbc4313..fde188d1c8 100644 --- a/plugins/allure/package.json +++ b/plugins/allure/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-allure", "description": "A Backstage plugin that integrates with Allure", - "version": "0.1.40", + "version": "0.1.41-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/analytics-module-ga/CHANGELOG.md b/plugins/analytics-module-ga/CHANGELOG.md index 6829162be7..251990d5c3 100644 --- a/plugins/analytics-module-ga/CHANGELOG.md +++ b/plugins/analytics-module-ga/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-analytics-module-ga +## 0.1.34-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/theme@0.4.2 + +## 0.1.34-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/config@1.1.0 + - @backstage/theme@0.4.2 + ## 0.1.33 ### Patch Changes diff --git a/plugins/analytics-module-ga/api-report.md b/plugins/analytics-module-ga/api-report.md index f28c919f33..1846211e72 100644 --- a/plugins/analytics-module-ga/api-report.md +++ b/plugins/analytics-module-ga/api-report.md @@ -10,7 +10,7 @@ import { Config } from '@backstage/config'; import { IdentityApi } from '@backstage/core-plugin-api'; // @public @deprecated (undocumented) -export const analyticsModuleGA: BackstagePlugin<{}, {}, {}>; +export const analyticsModuleGA: BackstagePlugin<{}, {}>; // @public export class GoogleAnalytics implements AnalyticsApi { diff --git a/plugins/analytics-module-ga/package.json b/plugins/analytics-module-ga/package.json index 66a07699d2..86f0a4204e 100644 --- a/plugins/analytics-module-ga/package.json +++ b/plugins/analytics-module-ga/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-analytics-module-ga", - "version": "0.1.33", + "version": "0.1.34-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/analytics-module-ga4/CHANGELOG.md b/plugins/analytics-module-ga4/CHANGELOG.md index 34dafc1f97..d79ec11dea 100644 --- a/plugins/analytics-module-ga4/CHANGELOG.md +++ b/plugins/analytics-module-ga4/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-analytics-module-ga4 +## 0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/theme@0.4.2 + +## 0.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/config@1.1.0 + - @backstage/theme@0.4.2 + ## 0.1.4 ### Patch Changes diff --git a/plugins/analytics-module-ga4/package.json b/plugins/analytics-module-ga4/package.json index eb72c1ed30..ab9611f5e8 100644 --- a/plugins/analytics-module-ga4/package.json +++ b/plugins/analytics-module-ga4/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-analytics-module-ga4", - "version": "0.1.4", + "version": "0.1.5-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/analytics-module-newrelic-browser/CHANGELOG.md b/plugins/analytics-module-newrelic-browser/CHANGELOG.md index 58c4c4c575..7bfaf1c262 100644 --- a/plugins/analytics-module-newrelic-browser/CHANGELOG.md +++ b/plugins/analytics-module-newrelic-browser/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-analytics-module-newrelic-browser +## 0.0.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + +## 0.0.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/config@1.1.0 + ## 0.0.2 ### Patch Changes diff --git a/plugins/analytics-module-newrelic-browser/package.json b/plugins/analytics-module-newrelic-browser/package.json index 815dd3fbaf..c27be5f94e 100644 --- a/plugins/analytics-module-newrelic-browser/package.json +++ b/plugins/analytics-module-newrelic-browser/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-analytics-module-newrelic-browser", - "version": "0.0.2", + "version": "0.0.3-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/apache-airflow/CHANGELOG.md b/plugins/apache-airflow/CHANGELOG.md index fd787df404..4c0f6a418d 100644 --- a/plugins/apache-airflow/CHANGELOG.md +++ b/plugins/apache-airflow/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-apache-airflow +## 0.2.16-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + +## 0.2.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + ## 0.2.15 ### Patch Changes diff --git a/plugins/apache-airflow/api-report.md b/plugins/apache-airflow/api-report.md index be2a208bd4..922ad4e868 100644 --- a/plugins/apache-airflow/api-report.md +++ b/plugins/apache-airflow/api-report.md @@ -22,7 +22,6 @@ export const apacheAirflowPlugin: BackstagePlugin< { root: RouteRef<undefined>; }, - {}, {} >; ``` diff --git a/plugins/apache-airflow/package.json b/plugins/apache-airflow/package.json index a076265402..28f8f81ab0 100644 --- a/plugins/apache-airflow/package.json +++ b/plugins/apache-airflow/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-apache-airflow", - "version": "0.2.15", + "version": "0.2.16-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/api-docs/CHANGELOG.md b/plugins/api-docs/CHANGELOG.md index 628cee37bb..021c55b807 100644 --- a/plugins/api-docs/CHANGELOG.md +++ b/plugins/api-docs/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/plugin-api-docs +## 0.9.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.14.0-next.1 + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## 0.9.12-next.0 + +### Patch Changes + +- 0117a6b47e: Adding `requestInterceptor` option to `api-docs` and pass it to SwaggerUI. This will enable to configure a proxy or headers to be sent to all the request made through the `Try it out` button on SwaggerUI. +- 18f1756908: added aria-label on api definition button for better a11y. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/plugin-catalog@1.14.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + ## 0.9.11 ### Patch Changes diff --git a/plugins/api-docs/README.md b/plugins/api-docs/README.md index 27e19b218d..792a7fb0b7 100644 --- a/plugins/api-docs/README.md +++ b/plugins/api-docs/README.md @@ -222,3 +222,42 @@ security: ## Links - [The Backstage homepage](https://backstage.io) + +### Adding `requestInterceptor` to Swagger UI + +To configure a [`requestInterceptor` for Swagger UI](https://github.com/swagger-api/swagger-ui/tree/master/flavors/swagger-ui-react#requestinterceptor-proptypesfunc) you'll need to add the following to your `api.tsx`: + +```tsx +... +import { OpenApiDefinitionWidget, apiDocsConfigRef, defaultDefinitionWidgets } from '@backstage/plugin-api-docs'; +import { ApiEntity } from '@backstage/catalog-model'; + +export const apis: AnyApiFactory[] = [ +... +createApiFactory({ + api: apiDocsConfigRef, + deps: {}, + factory: () => { + // Overriding openapi definition widget to add header + const requestInterceptor = (req: any) => { + req.headers.append('myheader', 'wombats'); + return req; + }; + const definitionWidgets = defaultDefinitionWidgets().map(obj => { + if (obj.type === 'openapi') { + return { + ...obj, + component: (definition) => <OpenApiDefinitionWidget definition={definition} requestInterceptor={requestInterceptor} />, + } + } + return obj; + }); + + return { + getApiDefinitionWidget: (apiEntity: ApiEntity) => { + return definitionWidgets.find(d => d.type === apiEntity.spec.type); + }, + }; + }, + }) +``` diff --git a/plugins/api-docs/api-report.md b/plugins/api-docs/api-report.md index 59d490a1fe..a018dfcdb1 100644 --- a/plugins/api-docs/api-report.md +++ b/plugins/api-docs/api-report.md @@ -54,8 +54,7 @@ const apiDocsPlugin: BackstagePlugin< }, { registerApi: ExternalRouteRef<undefined, true>; - }, - {} + } >; export { apiDocsPlugin }; export { apiDocsPlugin as plugin }; @@ -166,6 +165,7 @@ export const OpenApiDefinitionWidget: ( // @public (undocumented) export type OpenApiDefinitionWidgetProps = { definition: string; + requestInterceptor?: (req: any) => any | Promise<any>; }; // @public (undocumented) diff --git a/plugins/api-docs/package.json b/plugins/api-docs/package.json index a045d903f5..f257d85d82 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.9.11", + "version": "0.9.12-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/api-docs/src/components/ApisCards/presets.tsx b/plugins/api-docs/src/components/ApisCards/presets.tsx index b1ef39c113..050944b239 100644 --- a/plugins/api-docs/src/components/ApisCards/presets.tsx +++ b/plugins/api-docs/src/components/ApisCards/presets.tsx @@ -33,10 +33,12 @@ export function createSpecApiTypeColumn(): TableColumn<ApiEntity> { const ApiDefinitionButton = ({ apiEntity }: { apiEntity: ApiEntity }) => { const [dialogOpen, setDialogOpen] = useState(false); - return ( <> - <ToggleButton onClick={() => setDialogOpen(!dialogOpen)}> + <ToggleButton + aria-label="Toggle API Definition Dialog" + onClick={() => setDialogOpen(!dialogOpen)} + > <ExtensionIcon /> </ToggleButton> <ApiDefinitionDialog diff --git a/plugins/api-docs/src/components/OpenApiDefinitionWidget/OpenApiDefinition.test.tsx b/plugins/api-docs/src/components/OpenApiDefinitionWidget/OpenApiDefinition.test.tsx index 735fba86f7..adbd069908 100644 --- a/plugins/api-docs/src/components/OpenApiDefinitionWidget/OpenApiDefinition.test.tsx +++ b/plugins/api-docs/src/components/OpenApiDefinitionWidget/OpenApiDefinition.test.tsx @@ -38,8 +38,14 @@ paths: "200": description: Success `; + + const requestInterceptor = (req: any) => req; + const { getByText } = await renderInTestApp( - <OpenApiDefinition definition={definition} />, + <OpenApiDefinition + definition={definition} + requestInterceptor={requestInterceptor} + />, ); // swagger-ui loads the documentation asynchronously diff --git a/plugins/api-docs/src/components/OpenApiDefinitionWidget/OpenApiDefinition.tsx b/plugins/api-docs/src/components/OpenApiDefinitionWidget/OpenApiDefinition.tsx index 5d5988399a..a2ebbbc7e3 100644 --- a/plugins/api-docs/src/components/OpenApiDefinitionWidget/OpenApiDefinition.tsx +++ b/plugins/api-docs/src/components/OpenApiDefinitionWidget/OpenApiDefinition.tsx @@ -136,9 +136,13 @@ const useStyles = makeStyles(theme => ({ export type OpenApiDefinitionProps = { definition: string; + requestInterceptor?: (req: any) => any | Promise<any>; }; -export const OpenApiDefinition = ({ definition }: OpenApiDefinitionProps) => { +export const OpenApiDefinition = ({ + definition, + requestInterceptor, +}: OpenApiDefinitionProps) => { const classes = useStyles(); // Due to a bug in the swagger-ui-react component, the component needs @@ -152,7 +156,12 @@ export const OpenApiDefinition = ({ definition }: OpenApiDefinitionProps) => { return ( <div className={classes.root}> - <SwaggerUI spec={def} url="" deepLinking /> + <SwaggerUI + spec={def} + url="" + requestInterceptor={requestInterceptor} + deepLinking + /> </div> ); }; diff --git a/plugins/api-docs/src/components/OpenApiDefinitionWidget/OpenApiDefinitionWidget.tsx b/plugins/api-docs/src/components/OpenApiDefinitionWidget/OpenApiDefinitionWidget.tsx index 424a52136b..152f1fd089 100644 --- a/plugins/api-docs/src/components/OpenApiDefinitionWidget/OpenApiDefinitionWidget.tsx +++ b/plugins/api-docs/src/components/OpenApiDefinitionWidget/OpenApiDefinitionWidget.tsx @@ -28,6 +28,7 @@ const LazyOpenApiDefinition = React.lazy(() => /** @public */ export type OpenApiDefinitionWidgetProps = { definition: string; + requestInterceptor?: (req: any) => any | Promise<any>; }; /** @public */ diff --git a/plugins/apollo-explorer/CHANGELOG.md b/plugins/apollo-explorer/CHANGELOG.md index 9af673faae..869e487cff 100644 --- a/plugins/apollo-explorer/CHANGELOG.md +++ b/plugins/apollo-explorer/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-apollo-explorer +## 0.1.16-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/theme@0.4.2 + +## 0.1.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/theme@0.4.2 + ## 0.1.15 ### Patch Changes diff --git a/plugins/apollo-explorer/api-report.md b/plugins/apollo-explorer/api-report.md index 2dd6c14a90..7d06876e89 100644 --- a/plugins/apollo-explorer/api-report.md +++ b/plugins/apollo-explorer/api-report.md @@ -38,7 +38,6 @@ export const apolloExplorerPlugin: BackstagePlugin< { root: RouteRef<undefined>; }, - {}, {} >; ``` diff --git a/plugins/apollo-explorer/package.json b/plugins/apollo-explorer/package.json index d474094ed1..6c7eb11c50 100644 --- a/plugins/apollo-explorer/package.json +++ b/plugins/apollo-explorer/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-apollo-explorer", - "version": "0.1.15", + "version": "0.1.16-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/app-backend/CHANGELOG.md b/plugins/app-backend/CHANGELOG.md index 86eb85a42b..d54709fbc2 100644 --- a/plugins/app-backend/CHANGELOG.md +++ b/plugins/app-backend/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-app-backend +## 0.3.53-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/config-loader@1.5.1-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-app-node@0.1.5-next.1 + +## 0.3.53-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.5.1-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-app-node@0.1.5-next.0 + ## 0.3.51 ### Patch Changes diff --git a/plugins/app-backend/package.json b/plugins/app-backend/package.json index 561dbff245..0c0ecc8f60 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.51", + "version": "0.3.53-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/app-node/CHANGELOG.md b/plugins/app-node/CHANGELOG.md index 871c31f902..d1d2284dce 100644 --- a/plugins/app-node/CHANGELOG.md +++ b/plugins/app-node/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-app-node +## 0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.5-next.1 + +## 0.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.5-next.0 + ## 0.1.3 ### Patch Changes diff --git a/plugins/app-node/package.json b/plugins/app-node/package.json index 05d49416dc..5e21650501 100644 --- a/plugins/app-node/package.json +++ b/plugins/app-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-app-node", "description": "Node.js library for the app plugin", - "version": "0.1.3", + "version": "0.1.5-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md b/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md index bfdf090263..8c14e20d07 100644 --- a/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-auth-backend-module-gcp-iap-provider +## 0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + +## 0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + ## 0.1.0 ### Minor Changes diff --git a/plugins/auth-backend-module-gcp-iap-provider/package.json b/plugins/auth-backend-module-gcp-iap-provider/package.json index 6764224b28..7e9cd78fa4 100644 --- a/plugins/auth-backend-module-gcp-iap-provider/package.json +++ b/plugins/auth-backend-module-gcp-iap-provider/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend-module-gcp-iap-provider", "description": "A GCP IAP auth provider module for the Backstage auth backend", - "version": "0.1.0", + "version": "0.1.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/auth-backend-module-github-provider/CHANGELOG.md b/plugins/auth-backend-module-github-provider/CHANGELOG.md index b7c928b62e..d98d330281 100644 --- a/plugins/auth-backend-module-github-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-github-provider/CHANGELOG.md @@ -1,5 +1,24 @@ # @backstage/plugin-auth-backend-module-github-provider +## 0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + +## 0.1.2-next.0 + +### Patch Changes + +- 5d32a58b5a: Fixed a bug where the GitHub authenticator did not properly persist granted OAuth scopes. +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + ## 0.1.0 ### Minor Changes diff --git a/plugins/auth-backend-module-github-provider/package.json b/plugins/auth-backend-module-github-provider/package.json index 0b86025503..25563c32c5 100644 --- a/plugins/auth-backend-module-github-provider/package.json +++ b/plugins/auth-backend-module-github-provider/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend-module-github-provider", "description": "The github-provider backend module for the auth plugin.", - "version": "0.1.0", + "version": "0.1.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/auth-backend-module-github-provider/src/authenticator.ts b/plugins/auth-backend-module-github-provider/src/authenticator.ts index f59ac3d727..4a9710d114 100644 --- a/plugins/auth-backend-module-github-provider/src/authenticator.ts +++ b/plugins/auth-backend-module-github-provider/src/authenticator.ts @@ -28,6 +28,7 @@ const ACCESS_TOKEN_PREFIX = 'access-token.'; export const githubAuthenticator = createOAuthAuthenticator({ defaultProfileTransform: PassportOAuthAuthenticatorHelper.defaultProfileTransform, + shouldPersistScopes: true, initialize({ callbackUrl, config }) { const clientId = config.getString('clientId'); const clientSecret = config.getString('clientSecret'); diff --git a/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md b/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md index 3867635a91..cafc7ec1a4 100644 --- a/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-auth-backend-module-gitlab-provider +## 0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + +## 0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + ## 0.1.0 ### Minor Changes diff --git a/plugins/auth-backend-module-gitlab-provider/package.json b/plugins/auth-backend-module-gitlab-provider/package.json index 49ebb0dca0..e039faf1a2 100644 --- a/plugins/auth-backend-module-gitlab-provider/package.json +++ b/plugins/auth-backend-module-gitlab-provider/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend-module-gitlab-provider", "description": "The gitlab-provider backend module for the auth plugin.", - "version": "0.1.0", + "version": "0.1.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/auth-backend-module-google-provider/CHANGELOG.md b/plugins/auth-backend-module-google-provider/CHANGELOG.md index b0de32217e..974a3c1dfe 100644 --- a/plugins/auth-backend-module-google-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-google-provider/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-auth-backend-module-google-provider +## 0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + +## 0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + ## 0.1.0 ### Minor Changes diff --git a/plugins/auth-backend-module-google-provider/package.json b/plugins/auth-backend-module-google-provider/package.json index ac69fa91ae..46adb1148e 100644 --- a/plugins/auth-backend-module-google-provider/package.json +++ b/plugins/auth-backend-module-google-provider/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend-module-google-provider", "description": "A Google auth provider module for the Backstage auth backend", - "version": "0.1.0", + "version": "0.1.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md b/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md index 20753caa5e..f2437a2e73 100644 --- a/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-auth-backend-module-oauth2-provider +## 0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + +## 0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + ## 0.1.0 ### Minor Changes diff --git a/plugins/auth-backend-module-oauth2-provider/package.json b/plugins/auth-backend-module-oauth2-provider/package.json index 34632c4073..3e53ba5954 100644 --- a/plugins/auth-backend-module-oauth2-provider/package.json +++ b/plugins/auth-backend-module-oauth2-provider/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend-module-oauth2-provider", "description": "The oauth2-provider backend module for the auth plugin.", - "version": "0.1.0", + "version": "0.1.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/auth-backend/CHANGELOG.md b/plugins/auth-backend/CHANGELOG.md index a82d928581..f2eadd6c3d 100644 --- a/plugins/auth-backend/CHANGELOG.md +++ b/plugins/auth-backend/CHANGELOG.md @@ -1,5 +1,45 @@ # @backstage/plugin-auth-backend +## 0.19.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-auth-backend-module-github-provider@0.1.2-next.1 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.2-next.1 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.1.2-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.1.2-next.1 + - @backstage/plugin-auth-backend-module-google-provider@0.1.2-next.1 + +## 0.19.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-backend-module-github-provider@0.1.2-next.0 + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.1.2-next.0 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.2-next.0 + - @backstage/plugin-auth-backend-module-google-provider@0.1.2-next.0 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.1.2-next.0 + - @backstage/plugin-catalog-node@1.4.6-next.0 + ## 0.19.0 ### Minor Changes @@ -342,7 +382,7 @@ ### Patch Changes - d8f774c30df: Enforce the secret visibility of certificates and client secrets in the auth backend. Also, document all known options for each auth plugin. -- 7908d72e033: Introduce a new global config parameter, `auth.enableExperimentalRedirectFlow`. When enabled, auth will happen with an in-window redirect flow rather than through a popup window. +- 7908d72e033: Introduce a new global config parameter, `enableExperimentalRedirectFlow`. When enabled, auth will happen with an in-window redirect flow rather than through a popup window. - 475abd1dc3f: The `microsoft` (i.e. Azure) auth provider now supports negotiating tokens for Azure resources besides Microsoft Graph (e.g. AKS, Virtual Machines, Machine Learning Services, etc.). When the `/frame/handler` endpoint is called with an @@ -428,7 +468,7 @@ ### Patch Changes - d8f774c30df: Enforce the secret visibility of certificates and client secrets in the auth backend. Also, document all known options for each auth plugin. -- 7908d72e033: Introduce a new global config parameter, `auth.enableExperimentalRedirectFlow`. When enabled, auth will happen with an in-window redirect flow rather than through a popup window. +- 7908d72e033: Introduce a new global config parameter, `enableExperimentalRedirectFlow`. When enabled, auth will happen with an in-window redirect flow rather than through a popup window. - Updated dependencies - @backstage/backend-common@0.18.4-next.0 - @backstage/config@1.0.7 diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json index 98c5e0bd8a..398814564e 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.19.0", + "version": "0.19.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/auth-node/CHANGELOG.md b/plugins/auth-node/CHANGELOG.md index ba010a155a..2dcd93dc51 100644 --- a/plugins/auth-node/CHANGELOG.md +++ b/plugins/auth-node/CHANGELOG.md @@ -1,5 +1,32 @@ # @backstage/plugin-auth-node +## 0.3.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + +## 0.3.2-next.0 + +### Patch Changes + +- 6c2b0793bf: Fix for persisted scopes not being properly restored on sign-in. +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + ## 0.3.0 ### Minor Changes diff --git a/plugins/auth-node/package.json b/plugins/auth-node/package.json index 11859a899d..91ae1b5e6a 100644 --- a/plugins/auth-node/package.json +++ b/plugins/auth-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-node", - "version": "0.3.0", + "version": "0.3.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/auth-node/src/oauth/createOAuthRouteHandlers.test.ts b/plugins/auth-node/src/oauth/createOAuthRouteHandlers.test.ts index 2573d95ea1..7da5519655 100644 --- a/plugins/auth-node/src/oauth/createOAuthRouteHandlers.test.ts +++ b/plugins/auth-node/src/oauth/createOAuthRouteHandlers.test.ts @@ -297,7 +297,7 @@ describe('createOAuthRouteHandlers', () => { state: encodeOAuthState({ env: 'development', nonce: '123', - scope: 'my-scope', + scope: 'my-scope my-other-scope', } as OAuthState), }); @@ -310,7 +310,7 @@ describe('createOAuthRouteHandlers', () => { accessToken: 'access-token', expiresInSeconds: 3, idToken: 'id-token', - scope: 'my-scope', + scope: 'my-scope my-other-scope', }, backstageIdentity: { identity: { @@ -324,7 +324,9 @@ describe('createOAuthRouteHandlers', () => { }); expect(getRefreshTokenCookie(agent).value).toBe('refresh-token'); - expect(getGrantedScopesCookie(agent).value).toBe('my-scope'); + expect(getGrantedScopesCookie(agent).value).toBe( + 'my-scope%20my-other-scope', + ); }); it('should redirect with persisted scope', async () => { @@ -357,7 +359,7 @@ describe('createOAuthRouteHandlers', () => { state: encodeOAuthState({ env: 'development', nonce: '123', - scope: 'my-scope', + scope: 'my-scope my-other-scope', flow: 'redirect', redirectUrl: 'https://127.0.0.1:3000/redirect', } as OAuthState), @@ -367,7 +369,9 @@ describe('createOAuthRouteHandlers', () => { expect(res.get('Location')).toBe('https://127.0.0.1:3000/redirect'); expect(getRefreshTokenCookie(agent).value).toBe('refresh-token'); - expect(getGrantedScopesCookie(agent).value).toBe('my-scope'); + expect(getGrantedScopesCookie(agent).value).toBe( + 'my-scope%20my-other-scope', + ); }); it('should require a valid origin', async () => { diff --git a/plugins/auth-node/src/oauth/createOAuthRouteHandlers.ts b/plugins/auth-node/src/oauth/createOAuthRouteHandlers.ts index 011b3fc0f0..a0735e3ba0 100644 --- a/plugins/auth-node/src/oauth/createOAuthRouteHandlers.ts +++ b/plugins/auth-node/src/oauth/createOAuthRouteHandlers.ts @@ -136,7 +136,7 @@ export function createOAuthRouteHandlers<TProfile>( // If scopes are persisted then we pass them through the state so that we // can set the cookie on successful auth - if (authenticator.shouldPersistScopes) { + if (authenticator.shouldPersistScopes && scope) { state.scope = scope; } @@ -214,7 +214,7 @@ export function createOAuthRouteHandlers<TProfile>( // the provider does not return granted scopes on refresh or if they are normalized. if (authenticator.shouldPersistScopes && state.scope) { cookieManager.setGrantedScopes(res, state.scope, appOrigin); - result.session.scope = state.scope; + response.providerInfo.scope = state.scope; } if (result.session.refreshToken) { @@ -320,7 +320,9 @@ export function createOAuthRouteHandlers<TProfile>( providerInfo: { idToken: result.session.idToken, accessToken: result.session.accessToken, - scope: result.session.scope, + scope: authenticator.shouldPersistScopes + ? scope + : result.session.scope, expiresInSeconds: result.session.expiresInSeconds, }, }; diff --git a/plugins/azure-devops-backend/CHANGELOG.md b/plugins/azure-devops-backend/CHANGELOG.md index 34fd461a3b..f38133089c 100644 --- a/plugins/azure-devops-backend/CHANGELOG.md +++ b/plugins/azure-devops-backend/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-azure-devops-backend +## 0.4.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/plugin-azure-devops-common@0.3.1 + +## 0.4.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/plugin-azure-devops-common@0.3.1 + ## 0.4.0 ### Minor Changes diff --git a/plugins/azure-devops-backend/package.json b/plugins/azure-devops-backend/package.json index a377425b51..1da72ae8dc 100644 --- a/plugins/azure-devops-backend/package.json +++ b/plugins/azure-devops-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-azure-devops-backend", - "version": "0.4.0", + "version": "0.4.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/azure-devops/CHANGELOG.md b/plugins/azure-devops/CHANGELOG.md index 2712586d93..eee90fe4b2 100644 --- a/plugins/azure-devops/CHANGELOG.md +++ b/plugins/azure-devops/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/plugin-azure-devops +## 0.3.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-azure-devops-common@0.3.1 + +## 0.3.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-azure-devops-common@0.3.1 + ## 0.3.6 ### Patch Changes diff --git a/plugins/azure-devops/api-report.md b/plugins/azure-devops/api-report.md index 2c916ec33b..6b33762639 100644 --- a/plugins/azure-devops/api-report.md +++ b/plugins/azure-devops/api-report.md @@ -162,7 +162,7 @@ export class AzureDevOpsClient implements AzureDevOpsApi { } // @public (undocumented) -export const azureDevOpsPlugin: BackstagePlugin<{}, {}, {}>; +export const azureDevOpsPlugin: BackstagePlugin<{}, {}>; // @public (undocumented) export const AzurePullRequestsIcon: ( diff --git a/plugins/azure-devops/package.json b/plugins/azure-devops/package.json index 740ab7d1d7..f47811bf58 100644 --- a/plugins/azure-devops/package.json +++ b/plugins/azure-devops/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-azure-devops", - "version": "0.3.6", + "version": "0.3.7-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/azure-sites-backend/CHANGELOG.md b/plugins/azure-sites-backend/CHANGELOG.md index 66c4b92c4a..fe92430af1 100644 --- a/plugins/azure-sites-backend/CHANGELOG.md +++ b/plugins/azure-sites-backend/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-azure-sites-backend +## 0.1.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/config@1.1.0 + - @backstage/plugin-azure-sites-common@0.1.1 + +## 0.1.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/plugin-azure-sites-common@0.1.1 + ## 0.1.13 ### Patch Changes diff --git a/plugins/azure-sites-backend/package.json b/plugins/azure-sites-backend/package.json index f6e08af1f2..d1c9c6c2b7 100644 --- a/plugins/azure-sites-backend/package.json +++ b/plugins/azure-sites-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-azure-sites-backend", - "version": "0.1.13", + "version": "0.1.15-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/azure-sites/CHANGELOG.md b/plugins/azure-sites/CHANGELOG.md index 1d9fac99a5..3f044f2243 100644 --- a/plugins/azure-sites/CHANGELOG.md +++ b/plugins/azure-sites/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-azure-sites +## 0.1.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-azure-sites-common@0.1.1 + +## 0.1.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-azure-sites-common@0.1.1 + ## 0.1.13 ### Patch Changes diff --git a/plugins/azure-sites/api-report.md b/plugins/azure-sites/api-report.md index bec89e17bc..abc10ec723 100644 --- a/plugins/azure-sites/api-report.md +++ b/plugins/azure-sites/api-report.md @@ -49,7 +49,6 @@ export const azureSitesPlugin: BackstagePlugin< { entityContent: RouteRef<undefined>; }, - {}, {} >; diff --git a/plugins/azure-sites/package.json b/plugins/azure-sites/package.json index a6147e6c02..d7a4826be1 100644 --- a/plugins/azure-sites/package.json +++ b/plugins/azure-sites/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-azure-sites", - "version": "0.1.13", + "version": "0.1.14-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/badges-backend/CHANGELOG.md b/plugins/badges-backend/CHANGELOG.md index e778ba0eef..3081811eca 100644 --- a/plugins/badges-backend/CHANGELOG.md +++ b/plugins/badges-backend/CHANGELOG.md @@ -1,5 +1,32 @@ # @backstage/plugin-badges-backend +## 0.3.2-next.1 + +### Patch Changes + +- 817f2acbb1: Make sure the default badge factory is used if nothing is defined +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + +## 0.3.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + ## 0.3.0 ### Minor Changes diff --git a/plugins/badges-backend/package.json b/plugins/badges-backend/package.json index 7b6f2a65b3..4137092f17 100644 --- a/plugins/badges-backend/package.json +++ b/plugins/badges-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-badges-backend", "description": "A Backstage backend plugin that generates README badges for your entities", - "version": "0.3.0", + "version": "0.3.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/badges-backend/src/plugin.ts b/plugins/badges-backend/src/plugin.ts index 3e462e88e9..e5a51d763f 100644 --- a/plugins/badges-backend/src/plugin.ts +++ b/plugins/badges-backend/src/plugin.ts @@ -20,6 +20,7 @@ import { createBackendPlugin, } from '@backstage/backend-plugin-api'; import { createRouter } from './service/router'; +import { createDefaultBadgeFactories } from './badges'; /** * Badges backend plugin @@ -50,6 +51,7 @@ export const badgesPlugin = createBackendPlugin({ await createRouter({ config, logger: loggerToWinstonLogger(logger), + badgeFactories: createDefaultBadgeFactories(), discovery, tokenManager, identity, diff --git a/plugins/badges-backend/src/service/router.ts b/plugins/badges-backend/src/service/router.ts index 308865b73a..47bb8fcbe8 100644 --- a/plugins/badges-backend/src/service/router.ts +++ b/plugins/badges-backend/src/service/router.ts @@ -32,6 +32,7 @@ import { Logger } from 'winston'; import { IdentityApi } from '@backstage/plugin-auth-node'; import { getBearerTokenFromAuthorizationHeader } from '@backstage/plugin-auth-node'; import { BadgesStore, DatabaseBadgesStore } from '../database/badgesStore'; +import { createDefaultBadgeFactories } from '../badges'; /** @public */ export interface RouterOptions { @@ -54,7 +55,9 @@ export async function createRouter( options.catalog || new CatalogClient({ discoveryApi: options.discovery }); const badgeBuilder = options.badgeBuilder || - new DefaultBadgeBuilder(options.badgeFactories || {}); + new DefaultBadgeBuilder( + options.badgeFactories || createDefaultBadgeFactories(), + ); const router = Router(); const { config, logger, tokenManager, discovery, identity } = options; diff --git a/plugins/badges/CHANGELOG.md b/plugins/badges/CHANGELOG.md index f5bc8cc130..c20dd1af3e 100644 --- a/plugins/badges/CHANGELOG.md +++ b/plugins/badges/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-badges +## 0.2.49-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## 0.2.49-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + ## 0.2.48 ### Patch Changes diff --git a/plugins/badges/api-report.md b/plugins/badges/api-report.md index e73a887316..c32b901058 100644 --- a/plugins/badges/api-report.md +++ b/plugins/badges/api-report.md @@ -9,7 +9,7 @@ import { BackstagePlugin } from '@backstage/core-plugin-api'; import { JSX as JSX_2 } from 'react'; // @public (undocumented) -export const badgesPlugin: BackstagePlugin<{}, {}, {}>; +export const badgesPlugin: BackstagePlugin<{}, {}>; // @public (undocumented) export const EntityBadgesDialog: (props: { diff --git a/plugins/badges/package.json b/plugins/badges/package.json index 8dc33ee346..d0565cdaf9 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.48", + "version": "0.2.49-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/bazaar-backend/CHANGELOG.md b/plugins/bazaar-backend/CHANGELOG.md index e9fdaf4005..3f3bfb6eaf 100644 --- a/plugins/bazaar-backend/CHANGELOG.md +++ b/plugins/bazaar-backend/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-bazaar-backend +## 0.3.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + +## 0.3.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/errors@1.2.2 + ## 0.3.0 ### Minor Changes diff --git a/plugins/bazaar-backend/package.json b/plugins/bazaar-backend/package.json index 2a2b453c6e..28358525ee 100644 --- a/plugins/bazaar-backend/package.json +++ b/plugins/bazaar-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-bazaar-backend", - "version": "0.3.0", + "version": "0.3.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/bazaar/CHANGELOG.md b/plugins/bazaar/CHANGELOG.md index 77f24dd5da..d7c48b8802 100644 --- a/plugins/bazaar/CHANGELOG.md +++ b/plugins/bazaar/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/plugin-bazaar +## 0.2.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.14.0-next.1 + - @backstage/core-components@0.13.6-next.1 + - @backstage/cli@0.23.0-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## 0.2.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/cli@0.23.0-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/plugin-catalog@1.14.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + ## 0.2.16 ### Patch Changes diff --git a/plugins/bazaar/api-report.md b/plugins/bazaar/api-report.md index 282983b378..ba0396f81e 100644 --- a/plugins/bazaar/api-report.md +++ b/plugins/bazaar/api-report.md @@ -41,7 +41,6 @@ export const bazaarPlugin: BackstagePlugin< { root: RouteRef<undefined>; }, - {}, {} >; diff --git a/plugins/bazaar/package.json b/plugins/bazaar/package.json index 05ae2c442a..4a6ac9530d 100644 --- a/plugins/bazaar/package.json +++ b/plugins/bazaar/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-bazaar", - "version": "0.2.16", + "version": "0.2.17-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/bitbucket-cloud-common/CHANGELOG.md b/plugins/bitbucket-cloud-common/CHANGELOG.md index d3fb8b0eb2..439fda1b41 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.2.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + ## 0.2.12 ### Patch Changes diff --git a/plugins/bitbucket-cloud-common/package.json b/plugins/bitbucket-cloud-common/package.json index a0d0df7a91..5a109f3fb5 100644 --- a/plugins/bitbucket-cloud-common/package.json +++ b/plugins/bitbucket-cloud-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-bitbucket-cloud-common", "description": "Common functionalities for bitbucket-cloud plugins", - "version": "0.2.12", + "version": "0.2.13-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/bitrise/CHANGELOG.md b/plugins/bitrise/CHANGELOG.md index 8564978855..6a1c85393c 100644 --- a/plugins/bitrise/CHANGELOG.md +++ b/plugins/bitrise/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-bitrise +## 0.1.52-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## 0.1.52-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + ## 0.1.51 ### Patch Changes diff --git a/plugins/bitrise/api-report.md b/plugins/bitrise/api-report.md index 7f2e44f04f..cb68d79c51 100644 --- a/plugins/bitrise/api-report.md +++ b/plugins/bitrise/api-report.md @@ -13,7 +13,7 @@ import { JSX as JSX_2 } from 'react'; export const BITRISE_APP_ANNOTATION = 'bitrise.io/app'; // @public (undocumented) -export const bitrisePlugin: BackstagePlugin<{}, {}, {}>; +export const bitrisePlugin: BackstagePlugin<{}, {}>; // @public (undocumented) export const EntityBitriseContent: () => JSX_2.Element; diff --git a/plugins/bitrise/package.json b/plugins/bitrise/package.json index 413257109b..bc88d84191 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.51", + "version": "0.1.52-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-aws/CHANGELOG.md b/plugins/catalog-backend-module-aws/CHANGELOG.md index 70684170dd..cba33bfb38 100644 --- a/plugins/catalog-backend-module-aws/CHANGELOG.md +++ b/plugins/catalog-backend-module-aws/CHANGELOG.md @@ -1,5 +1,42 @@ # @backstage/plugin-catalog-backend-module-aws +## 0.2.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/plugin-kubernetes-common@0.7.0-next.0 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/integration-aws-node@0.1.6 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.16 + +## 0.2.8-next.0 + +### Patch Changes + +- 890e3b5ad4: Make sure to include the error message when ingestion fails +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/integration-aws-node@0.1.6 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-catalog-node@1.4.6-next.0 + - @backstage/plugin-kubernetes-common@0.6.6 + ## 0.2.6 ### Patch Changes diff --git a/plugins/catalog-backend-module-aws/package.json b/plugins/catalog-backend-module-aws/package.json index 3d0321e00c..c4891dd2b7 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.2.6", + "version": "0.2.8-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-aws/src/providers/AwsS3EntityProvider.ts b/plugins/catalog-backend-module-aws/src/providers/AwsS3EntityProvider.ts index 4df92b58c2..25631b2f99 100644 --- a/plugins/catalog-backend-module-aws/src/providers/AwsS3EntityProvider.ts +++ b/plugins/catalog-backend-module-aws/src/providers/AwsS3EntityProvider.ts @@ -131,7 +131,10 @@ export class AwsS3EntityProvider implements EntityProvider { try { await this.refresh(logger); } catch (error) { - logger.error(`${this.getProviderName()} refresh failed`, error); + logger.error( + `${this.getProviderName()} refresh failed, ${error}`, + error, + ); } }, }); diff --git a/plugins/catalog-backend-module-azure/CHANGELOG.md b/plugins/catalog-backend-module-azure/CHANGELOG.md index 75872ba873..6d1613bf1e 100644 --- a/plugins/catalog-backend-module-azure/CHANGELOG.md +++ b/plugins/catalog-backend-module-azure/CHANGELOG.md @@ -1,5 +1,38 @@ # @backstage/plugin-catalog-backend-module-azure +## 0.1.24-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.16 + +## 0.1.24-next.0 + +### Patch Changes + +- 890e3b5ad4: Make sure to include the error message when ingestion fails +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-catalog-node@1.4.6-next.0 + ## 0.1.22 ### Patch Changes diff --git a/plugins/catalog-backend-module-azure/package.json b/plugins/catalog-backend-module-azure/package.json index 92d27e63ed..f8849b4925 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.22", + "version": "0.1.24-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-azure/src/providers/AzureDevOpsEntityProvider.ts b/plugins/catalog-backend-module-azure/src/providers/AzureDevOpsEntityProvider.ts index 92398779c7..f56369a0d1 100644 --- a/plugins/catalog-backend-module-azure/src/providers/AzureDevOpsEntityProvider.ts +++ b/plugins/catalog-backend-module-azure/src/providers/AzureDevOpsEntityProvider.ts @@ -123,7 +123,10 @@ export class AzureDevOpsEntityProvider implements EntityProvider { try { await this.refresh(logger); } catch (error) { - logger.error(`${this.getProviderName()} refresh failed`, error); + logger.error( + `${this.getProviderName()} refresh failed, ${error}`, + error, + ); } }, }); diff --git a/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md index a20cbb30a0..4a989d8214 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md +++ b/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md @@ -1,5 +1,40 @@ # @backstage/plugin-catalog-backend-module-bitbucket-cloud +## 0.1.20-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.13-next.0 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-events-node@0.2.14-next.1 + +## 0.1.20-next.0 + +### Patch Changes + +- 890e3b5ad4: Make sure to include the error message when ingestion fails +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.13-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-catalog-node@1.4.6-next.0 + - @backstage/plugin-events-node@0.2.14-next.0 + ## 0.1.18 ### Patch Changes diff --git a/plugins/catalog-backend-module-bitbucket-cloud/package.json b/plugins/catalog-backend-module-bitbucket-cloud/package.json index 51f4f716b5..40f83d3717 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.18", + "version": "0.1.20-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-bitbucket-cloud/src/providers/BitbucketCloudEntityProvider.ts b/plugins/catalog-backend-module-bitbucket-cloud/src/providers/BitbucketCloudEntityProvider.ts index 96c6be5b80..14f561473b 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/src/providers/BitbucketCloudEntityProvider.ts +++ b/plugins/catalog-backend-module-bitbucket-cloud/src/providers/BitbucketCloudEntityProvider.ts @@ -152,7 +152,10 @@ export class BitbucketCloudEntityProvider try { await this.refresh(logger); } catch (error) { - logger.error(`${this.getProviderName()} refresh failed`, error); + logger.error( + `${this.getProviderName()} refresh failed, ${error}`, + error, + ); } }, }); diff --git a/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md index 766f4689a0..db98df3fc1 100644 --- a/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md +++ b/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md @@ -1,5 +1,34 @@ # @backstage/plugin-catalog-backend-module-bitbucket-server +## 0.1.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + +## 0.1.18-next.0 + +### Patch Changes + +- 890e3b5ad4: Make sure to include the error message when ingestion fails +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/plugin-catalog-node@1.4.6-next.0 + ## 0.1.16 ### Patch Changes diff --git a/plugins/catalog-backend-module-bitbucket-server/package.json b/plugins/catalog-backend-module-bitbucket-server/package.json index d1819e9a3b..d86127555f 100644 --- a/plugins/catalog-backend-module-bitbucket-server/package.json +++ b/plugins/catalog-backend-module-bitbucket-server/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-bitbucket-server", - "version": "0.1.16", + "version": "0.1.18-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-bitbucket-server/src/providers/BitbucketServerEntityProvider.ts b/plugins/catalog-backend-module-bitbucket-server/src/providers/BitbucketServerEntityProvider.ts index fd2b3e3959..95bda0e910 100644 --- a/plugins/catalog-backend-module-bitbucket-server/src/providers/BitbucketServerEntityProvider.ts +++ b/plugins/catalog-backend-module-bitbucket-server/src/providers/BitbucketServerEntityProvider.ts @@ -130,7 +130,10 @@ export class BitbucketServerEntityProvider implements EntityProvider { try { await this.refresh(logger); } catch (error) { - logger.error(`${this.getProviderName()} refresh failed`, error); + logger.error( + `${this.getProviderName()} refresh failed, ${error}`, + error, + ); } }, }); diff --git a/plugins/catalog-backend-module-bitbucket/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket/CHANGELOG.md index 1782c518b5..756ad9f1dd 100644 --- a/plugins/catalog-backend-module-bitbucket/CHANGELOG.md +++ b/plugins/catalog-backend-module-bitbucket/CHANGELOG.md @@ -1,5 +1,33 @@ # @backstage/plugin-catalog-backend-module-bitbucket +## 0.2.20-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-bitbucket-cloud-common@0.2.13-next.0 + +## 0.2.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.13-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-node@1.4.6-next.0 + ## 0.2.18 ### Patch Changes diff --git a/plugins/catalog-backend-module-bitbucket/package.json b/plugins/catalog-backend-module-bitbucket/package.json index 5fba12c51d..41827dc369 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.18", + "version": "0.2.20-next.1", "deprecated": true, "main": "src/index.ts", "types": "src/index.ts", diff --git a/plugins/catalog-backend-module-gcp/CHANGELOG.md b/plugins/catalog-backend-module-gcp/CHANGELOG.md index 43f6f8dc03..0b50b8bf3b 100644 --- a/plugins/catalog-backend-module-gcp/CHANGELOG.md +++ b/plugins/catalog-backend-module-gcp/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-catalog-backend-module-gcp +## 0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/plugin-kubernetes-common@0.7.0-next.0 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + +## 0.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/plugin-catalog-node@1.4.6-next.0 + - @backstage/plugin-kubernetes-common@0.6.6 + ## 0.1.3 ### Patch Changes diff --git a/plugins/catalog-backend-module-gcp/package.json b/plugins/catalog-backend-module-gcp/package.json index 6c802154f4..dc3ae7395d 100644 --- a/plugins/catalog-backend-module-gcp/package.json +++ b/plugins/catalog-backend-module-gcp/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-gcp", "description": "A Backstage catalog backend module that helps integrate towards GCP", - "version": "0.1.3", + "version": "0.1.5-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-gerrit/CHANGELOG.md b/plugins/catalog-backend-module-gerrit/CHANGELOG.md index 6e265c7fa7..cbfd993b9f 100644 --- a/plugins/catalog-backend-module-gerrit/CHANGELOG.md +++ b/plugins/catalog-backend-module-gerrit/CHANGELOG.md @@ -1,5 +1,34 @@ # @backstage/plugin-catalog-backend-module-gerrit +## 0.1.21-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + +## 0.1.21-next.0 + +### Patch Changes + +- 890e3b5ad4: Make sure to include the error message when ingestion fails +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/plugin-catalog-node@1.4.6-next.0 + ## 0.1.19 ### Patch Changes diff --git a/plugins/catalog-backend-module-gerrit/package.json b/plugins/catalog-backend-module-gerrit/package.json index 7fae34fa1f..9690978a3b 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.19", + "version": "0.1.21-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-gerrit/src/providers/GerritEntityProvider.ts b/plugins/catalog-backend-module-gerrit/src/providers/GerritEntityProvider.ts index 76cccaf37b..c773004532 100644 --- a/plugins/catalog-backend-module-gerrit/src/providers/GerritEntityProvider.ts +++ b/plugins/catalog-backend-module-gerrit/src/providers/GerritEntityProvider.ts @@ -129,7 +129,10 @@ export class GerritEntityProvider implements EntityProvider { try { await this.refresh(logger); } catch (error) { - logger.error(`${this.getProviderName()} refresh failed`, error); + logger.error( + `${this.getProviderName()} refresh failed, ${error}`, + error, + ); } }, }); diff --git a/plugins/catalog-backend-module-github/CHANGELOG.md b/plugins/catalog-backend-module-github/CHANGELOG.md index a3def0e7f2..1cb45ad261 100644 --- a/plugins/catalog-backend-module-github/CHANGELOG.md +++ b/plugins/catalog-backend-module-github/CHANGELOG.md @@ -1,5 +1,45 @@ # @backstage/plugin-catalog-backend-module-github +## 0.4.3-next.1 + +### Patch Changes + +- b4b1cbf9fa: Make `defaultUserTransformer` resolve to `UserEntity` instead of `Entity` +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-backend@1.14.0-next.1 + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-events-node@0.2.14-next.1 + +## 0.4.3-next.0 + +### Patch Changes + +- 890e3b5ad4: Make sure to include the error message when ingestion fails +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/plugin-catalog-backend@1.14.0-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-catalog-node@1.4.6-next.0 + - @backstage/plugin-events-node@0.2.14-next.0 + ## 0.4.0 ### Minor Changes diff --git a/plugins/catalog-backend-module-github/api-report.md b/plugins/catalog-backend-module-github/api-report.md index 12ab6d35e7..4c44f95b61 100644 --- a/plugins/catalog-backend-module-github/api-report.md +++ b/plugins/catalog-backend-module-github/api-report.md @@ -24,12 +24,16 @@ import { ScmIntegrationRegistry } from '@backstage/integration'; import { ScmLocationAnalyzer } from '@backstage/plugin-catalog-backend'; import { TaskRunner } from '@backstage/backend-tasks'; import { TokenManager } from '@backstage/backend-common'; +import { UserEntity } from '@backstage/catalog-model'; // @public export const defaultOrganizationTeamTransformer: TeamTransformer; // @public -export const defaultUserTransformer: UserTransformer; +export const defaultUserTransformer: ( + item: GithubUser, + _ctx: TransformerContext, +) => Promise<UserEntity | undefined>; // @public export class GithubDiscoveryProcessor implements CatalogProcessor { diff --git a/plugins/catalog-backend-module-github/package.json b/plugins/catalog-backend-module-github/package.json index 4e7d4bd933..8f22af5f62 100644 --- a/plugins/catalog-backend-module-github/package.json +++ b/plugins/catalog-backend-module-github/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-github", "description": "A Backstage catalog backend module that helps integrate towards GitHub", - "version": "0.4.0", + "version": "0.4.3-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-github/src/lib/defaultTransformers.ts b/plugins/catalog-backend-module-github/src/lib/defaultTransformers.ts index 71613d88d2..6befd32056 100644 --- a/plugins/catalog-backend-module-github/src/lib/defaultTransformers.ts +++ b/plugins/catalog-backend-module-github/src/lib/defaultTransformers.ts @@ -58,9 +58,10 @@ export type TeamTransformer = ( * * @public */ -export const defaultUserTransformer: UserTransformer = async ( +export const defaultUserTransformer = async ( item: GithubUser, -) => { + _ctx: TransformerContext, +): Promise<UserEntity | undefined> => { const entity: UserEntity = { apiVersion: 'backstage.io/v1alpha1', kind: 'User', diff --git a/plugins/catalog-backend-module-github/src/providers/GithubEntityProvider.ts b/plugins/catalog-backend-module-github/src/providers/GithubEntityProvider.ts index e91cc328f7..0dd6259f1c 100644 --- a/plugins/catalog-backend-module-github/src/providers/GithubEntityProvider.ts +++ b/plugins/catalog-backend-module-github/src/providers/GithubEntityProvider.ts @@ -163,7 +163,10 @@ export class GithubEntityProvider implements EntityProvider, EventSubscriber { try { await this.refresh(logger); } catch (error) { - logger.error(`${this.getProviderName()} refresh failed`, error); + logger.error( + `${this.getProviderName()} refresh failed, ${error}`, + error, + ); } }, }); diff --git a/plugins/catalog-backend-module-github/src/providers/GithubMultiOrgEntityProvider.ts b/plugins/catalog-backend-module-github/src/providers/GithubMultiOrgEntityProvider.ts index 7e15c4ce68..cabb9e21ce 100644 --- a/plugins/catalog-backend-module-github/src/providers/GithubMultiOrgEntityProvider.ts +++ b/plugins/catalog-backend-module-github/src/providers/GithubMultiOrgEntityProvider.ts @@ -831,7 +831,10 @@ export class GithubMultiOrgEntityProvider implements EntityProvider { try { await this.read({ logger }); } catch (error) { - logger.error(`${this.getProviderName()} refresh failed`, error); + logger.error( + `${this.getProviderName()} refresh failed, ${error}`, + error, + ); } }, }); diff --git a/plugins/catalog-backend-module-github/src/providers/GithubOrgEntityProvider.ts b/plugins/catalog-backend-module-github/src/providers/GithubOrgEntityProvider.ts index 4e43b5d67e..0fe61aa229 100644 --- a/plugins/catalog-backend-module-github/src/providers/GithubOrgEntityProvider.ts +++ b/plugins/catalog-backend-module-github/src/providers/GithubOrgEntityProvider.ts @@ -584,7 +584,10 @@ export class GithubOrgEntityProvider try { await this.read({ logger }); } catch (error) { - logger.error(`${this.getProviderName()} refresh failed`, error); + logger.error( + `${this.getProviderName()} refresh failed, ${error}`, + error, + ); } }, }); diff --git a/plugins/catalog-backend-module-gitlab/CHANGELOG.md b/plugins/catalog-backend-module-gitlab/CHANGELOG.md index ff2043d1c8..6a3633aa8a 100644 --- a/plugins/catalog-backend-module-gitlab/CHANGELOG.md +++ b/plugins/catalog-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,37 @@ # @backstage/plugin-catalog-backend-module-gitlab +## 0.3.2-next.1 + +### Patch Changes + +- 6ae7f12abb: Make sure the archived projects are skipped with the Gitlab API +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/types@1.1.1 + +## 0.3.2-next.0 + +### Patch Changes + +- 890e3b5ad4: Make sure to include the error message when ingestion fails +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-node@1.4.6-next.0 + ## 0.3.0 ### Minor Changes diff --git a/plugins/catalog-backend-module-gitlab/package.json b/plugins/catalog-backend-module-gitlab/package.json index b03f96aedd..b3fc853c26 100644 --- a/plugins/catalog-backend-module-gitlab/package.json +++ b/plugins/catalog-backend-module-gitlab/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-gitlab", "description": "A Backstage catalog backend module that helps integrate towards GitLab", - "version": "0.3.0", + "version": "0.3.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-gitlab/src/GitLabDiscoveryProcessor.test.ts b/plugins/catalog-backend-module-gitlab/src/GitLabDiscoveryProcessor.test.ts index a56c229105..f836500c6e 100644 --- a/plugins/catalog-backend-module-gitlab/src/GitLabDiscoveryProcessor.test.ts +++ b/plugins/catalog-backend-module-gitlab/src/GitLabDiscoveryProcessor.test.ts @@ -237,14 +237,6 @@ describe('GitlabDiscoveryProcessor', () => { web_url: 'https://gitlab.fake/3', path_with_namespace: '3', }, - { - id: 4, - archived: true, // ARCHIVED - default_branch: 'master', - last_activity_at: '2021-08-05T11:03:05.774Z', - web_url: 'https://gitlab.fake/4', - path_with_namespace: '4', - }, { id: 5, archived: false, diff --git a/plugins/catalog-backend-module-gitlab/src/lib/client.test.ts b/plugins/catalog-backend-module-gitlab/src/lib/client.test.ts index dda30fd86a..dad126e3e4 100644 --- a/plugins/catalog-backend-module-gitlab/src/lib/client.test.ts +++ b/plugins/catalog-backend-module-gitlab/src/lib/client.test.ts @@ -120,6 +120,14 @@ function setupFakeHasFileEndpoint(srv: SetupServer, apiBaseUrl: string) { ); } +function setupFakeURLReturnEndpoint(srv: SetupServer, url: string) { + srv.use( + rest.get(url, (req, res, ctx) => { + return res(ctx.json([{ endpoint: req.url.toString() }])); + }), + ); +} + describe('GitLabClient', () => { describe('isSelfManaged', () => { it('returns true if self managed instance', () => { @@ -933,3 +941,84 @@ describe('hasFile', () => { expect(hasFile).toBe(false); }); }); + +describe('pagedRequest search params', () => { + beforeEach(() => { + // setup fake paginated endpoint with 4 pages each returning one item + setupFakeURLReturnEndpoint(server, FAKE_PAGED_URL); + }); + + it('no search params provided', async () => { + const client = new GitLabClient({ + config: MOCK_CONFIG, + logger: getVoidLogger(), + }); + + const { items } = await client.pagedRequest<{ endpoint: string }>( + FAKE_PAGED_ENDPOINT, + ); + // fake page contains exactly one item + expect(items).toHaveLength(1); + expect(items).toEqual([ + { endpoint: 'https://example.com/api/v4/some-endpoint' }, + ]); + }); + + it('defined numeric search params', async () => { + const client = new GitLabClient({ + config: MOCK_CONFIG, + logger: getVoidLogger(), + }); + + const { items } = await client.pagedRequest<{ endpoint: string }>( + FAKE_PAGED_ENDPOINT, + { page: 1, per_page: 50 }, + ); + // fake page contains exactly one item + expect(items).toHaveLength(1); + expect(items).toEqual([ + { + endpoint: 'https://example.com/api/v4/some-endpoint?page=1&per_page=50', + }, + ]); + }); + + it('defined string search params', async () => { + const client = new GitLabClient({ + config: MOCK_CONFIG, + logger: getVoidLogger(), + }); + + const { items } = await client.pagedRequest<{ endpoint: string }>( + FAKE_PAGED_ENDPOINT, + { test: 'value', empty: '' }, + ); + // fake page contains exactly one item + expect(items).toHaveLength(1); + expect(items).toEqual([ + { + endpoint: 'https://example.com/api/v4/some-endpoint?test=value', + }, + ]); + }); + + it('defined boolean search params', async () => { + const client = new GitLabClient({ + config: MOCK_CONFIG, + logger: getVoidLogger(), + }); + + const { items } = await client.pagedRequest<{ endpoint: string }>( + FAKE_PAGED_ENDPOINT, + { active: true, archived: false }, + ); + // fake page contains exactly one item + expect(items).toHaveLength(1); + expect(items).toEqual([ + { + endpoint: + 'https://example.com/api/v4/some-endpoint?active=true&archived=false', + }, + ]); + }); +}); diff --git a/plugins/catalog-backend-module-gitlab/src/lib/client.ts b/plugins/catalog-backend-module-gitlab/src/lib/client.ts index 79ae328ce2..daf82245e8 100644 --- a/plugins/catalog-backend-module-gitlab/src/lib/client.ts +++ b/plugins/catalog-backend-module-gitlab/src/lib/client.ts @@ -309,7 +309,7 @@ export class GitLabClient { ): Promise<PagedResponse<T>> { const request = new URL(`${this.config.apiBaseUrl}${endpoint}`); for (const key in options) { - if (options[key]) { + if (options[key] !== undefined && options[key] !== '') { request.searchParams.append(key, options[key]!.toString()); } } diff --git a/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.ts b/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.ts index ce7a304746..32da64f819 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.ts @@ -133,7 +133,10 @@ export class GitlabDiscoveryEntityProvider implements EntityProvider { try { await this.refresh(logger); } catch (error) { - logger.error(`${this.getProviderName()} refresh failed`, error); + logger.error( + `${this.getProviderName()} refresh failed, ${error}`, + error, + ); } }, }); diff --git a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts index 0ef0e2b23c..fcf6a33a22 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts @@ -155,7 +155,10 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { try { await this.refresh(logger); } catch (error) { - logger.error(`${this.getProviderName()} refresh failed`, error); + logger.error( + `${this.getProviderName()} refresh failed, ${error}`, + error, + ); } }, }); diff --git a/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md b/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md index 44ee123ceb..870514fc08 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md +++ b/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md @@ -1,5 +1,37 @@ # @backstage/plugin-catalog-backend-module-incremental-ingestion +## 0.4.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-backend@1.14.0-next.1 + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/plugin-events-node@0.2.14-next.1 + - @backstage/plugin-permission-common@0.7.8 + +## 0.4.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.14.0-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/plugin-catalog-node@1.4.6-next.0 + - @backstage/plugin-events-node@0.2.14-next.0 + - @backstage/plugin-permission-common@0.7.8 + ## 0.4.6 ### Patch Changes diff --git a/plugins/catalog-backend-module-incremental-ingestion/package.json b/plugins/catalog-backend-module-incremental-ingestion/package.json index a5d1dc29eb..1d0709b7da 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/package.json +++ b/plugins/catalog-backend-module-incremental-ingestion/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-incremental-ingestion", "description": "An entity provider for streaming large asset sources into the catalog", - "version": "0.4.6", + "version": "0.4.9-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-ldap/CHANGELOG.md b/plugins/catalog-backend-module-ldap/CHANGELOG.md index bf2b433fff..cdf7473ff9 100644 --- a/plugins/catalog-backend-module-ldap/CHANGELOG.md +++ b/plugins/catalog-backend-module-ldap/CHANGELOG.md @@ -1,5 +1,32 @@ # @backstage/plugin-catalog-backend-module-ldap +## 0.5.20-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.16 + +## 0.5.20-next.0 + +### Patch Changes + +- 890e3b5ad4: Make sure to include the error message when ingestion fails +- Updated dependencies + - @backstage/config@1.1.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-catalog-node@1.4.6-next.0 + ## 0.5.18 ### Patch Changes diff --git a/plugins/catalog-backend-module-ldap/package.json b/plugins/catalog-backend-module-ldap/package.json index 3e5ae84ad2..d38d746563 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.18", + "version": "0.5.20-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-ldap/src/processors/LdapOrgEntityProvider.ts b/plugins/catalog-backend-module-ldap/src/processors/LdapOrgEntityProvider.ts index 811f451b26..d4f19d0522 100644 --- a/plugins/catalog-backend-module-ldap/src/processors/LdapOrgEntityProvider.ts +++ b/plugins/catalog-backend-module-ldap/src/processors/LdapOrgEntityProvider.ts @@ -225,7 +225,10 @@ export class LdapOrgEntityProvider implements EntityProvider { try { await this.read({ logger }); } catch (error) { - logger.error(`${this.getProviderName()} refresh failed`, error); + logger.error( + `${this.getProviderName()} refresh failed, ${error}`, + error, + ); } }, }); diff --git a/plugins/catalog-backend-module-msgraph/CHANGELOG.md b/plugins/catalog-backend-module-msgraph/CHANGELOG.md index 32ca5ec085..7d7f6f3039 100644 --- a/plugins/catalog-backend-module-msgraph/CHANGELOG.md +++ b/plugins/catalog-backend-module-msgraph/CHANGELOG.md @@ -1,5 +1,32 @@ # @backstage/plugin-catalog-backend-module-msgraph +## 0.5.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/plugin-catalog-common@1.0.16 + +## 0.5.12-next.0 + +### Patch Changes + +- 890e3b5ad4: Make sure to include the error message when ingestion fails +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-catalog-node@1.4.6-next.0 + ## 0.5.10 ### Patch Changes diff --git a/plugins/catalog-backend-module-msgraph/package.json b/plugins/catalog-backend-module-msgraph/package.json index 9aa539105a..112d0b7c34 100644 --- a/plugins/catalog-backend-module-msgraph/package.json +++ b/plugins/catalog-backend-module-msgraph/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-msgraph", "description": "A Backstage catalog backend module that helps integrate towards Microsoft Graph", - "version": "0.5.10", + "version": "0.5.12-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-msgraph/src/processors/MicrosoftGraphOrgEntityProvider.ts b/plugins/catalog-backend-module-msgraph/src/processors/MicrosoftGraphOrgEntityProvider.ts index 3ef02344eb..160696e2e7 100644 --- a/plugins/catalog-backend-module-msgraph/src/processors/MicrosoftGraphOrgEntityProvider.ts +++ b/plugins/catalog-backend-module-msgraph/src/processors/MicrosoftGraphOrgEntityProvider.ts @@ -352,7 +352,10 @@ export class MicrosoftGraphOrgEntityProvider implements EntityProvider { try { await this.read({ logger }); } catch (error) { - logger.error(`${this.getProviderName()} refresh failed`, error); + logger.error( + `${this.getProviderName()} refresh failed, ${error}`, + error, + ); } }, }); diff --git a/plugins/catalog-backend-module-openapi/CHANGELOG.md b/plugins/catalog-backend-module-openapi/CHANGELOG.md index 0c3895b20a..b103bd920d 100644 --- a/plugins/catalog-backend-module-openapi/CHANGELOG.md +++ b/plugins/catalog-backend-module-openapi/CHANGELOG.md @@ -1,5 +1,33 @@ # @backstage/plugin-catalog-backend-module-openapi +## 0.1.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.14.0-next.1 + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.16 + +## 0.1.22-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/plugin-catalog-backend@1.14.0-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-catalog-node@1.4.6-next.0 + ## 0.1.19 ### Patch Changes diff --git a/plugins/catalog-backend-module-openapi/package.json b/plugins/catalog-backend-module-openapi/package.json index 868c75a435..52659c8d03 100644 --- a/plugins/catalog-backend-module-openapi/package.json +++ b/plugins/catalog-backend-module-openapi/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-openapi", "description": "A Backstage catalog backend module that helps with OpenAPI specifications", - "version": "0.1.19", + "version": "0.1.22-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-puppetdb/CHANGELOG.md b/plugins/catalog-backend-module-puppetdb/CHANGELOG.md index a2b920105a..7e74c43039 100644 --- a/plugins/catalog-backend-module-puppetdb/CHANGELOG.md +++ b/plugins/catalog-backend-module-puppetdb/CHANGELOG.md @@ -1,5 +1,34 @@ # @backstage/plugin-catalog-backend-module-puppetdb +## 0.1.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + +## 0.1.10-next.0 + +### Patch Changes + +- 890e3b5ad4: Make sure to include the error message when ingestion fails +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-node@1.4.6-next.0 + ## 0.1.8 ### Patch Changes diff --git a/plugins/catalog-backend-module-puppetdb/package.json b/plugins/catalog-backend-module-puppetdb/package.json index 7eaf63b932..3ec71d1042 100644 --- a/plugins/catalog-backend-module-puppetdb/package.json +++ b/plugins/catalog-backend-module-puppetdb/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-puppetdb", "description": "A Backstage catalog backend module that helps integrate towards PuppetDB", - "version": "0.1.8", + "version": "0.1.10-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-puppetdb/src/providers/PuppetDbEntityProvider.ts b/plugins/catalog-backend-module-puppetdb/src/providers/PuppetDbEntityProvider.ts index a5286a9d70..0055e95589 100644 --- a/plugins/catalog-backend-module-puppetdb/src/providers/PuppetDbEntityProvider.ts +++ b/plugins/catalog-backend-module-puppetdb/src/providers/PuppetDbEntityProvider.ts @@ -148,7 +148,10 @@ export class PuppetDbEntityProvider implements EntityProvider { try { await this.refresh(logger); } catch (error) { - logger.error(`${this.getProviderName()} refresh failed`, error); + logger.error( + `${this.getProviderName()} refresh failed, ${error}`, + error, + ); } }, }); diff --git a/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md b/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md index c0de55d782..1be951bf47 100644 --- a/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md +++ b/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-catalog-backend-module-scaffolder-entity-model +## 0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/catalog-model@1.4.2 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-scaffolder-common@1.4.1 + +## 0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-catalog-node@1.4.6-next.0 + - @backstage/plugin-scaffolder-common@1.4.1 + ## 0.1.0 ### Minor Changes diff --git a/plugins/catalog-backend-module-scaffolder-entity-model/package.json b/plugins/catalog-backend-module-scaffolder-entity-model/package.json index f0f3ce59cf..35f573ec1e 100644 --- a/plugins/catalog-backend-module-scaffolder-entity-model/package.json +++ b/plugins/catalog-backend-module-scaffolder-entity-model/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-scaffolder-entity-model", "description": "Adds support for the scaffolder specific entity model (e.g. the Template kind) to the catalog backend plugin.", - "version": "0.1.0", + "version": "0.1.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-unprocessed/CHANGELOG.md b/plugins/catalog-backend-module-unprocessed/CHANGELOG.md index 9b8201e59f..2c229f113e 100644 --- a/plugins/catalog-backend-module-unprocessed/CHANGELOG.md +++ b/plugins/catalog-backend-module-unprocessed/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-catalog-backend-module-unprocessed +## 0.3.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/catalog-model@1.4.2 + +## 0.3.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/catalog-model@1.4.2 + ## 0.3.0 ### Minor Changes diff --git a/plugins/catalog-backend-module-unprocessed/package.json b/plugins/catalog-backend-module-unprocessed/package.json index 8cff3514ec..2a923fdf87 100644 --- a/plugins/catalog-backend-module-unprocessed/package.json +++ b/plugins/catalog-backend-module-unprocessed/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-unprocessed", "description": "Backstage Catalog module to view unprocessed entities", - "version": "0.3.0", + "version": "0.3.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend/CHANGELOG.md b/plugins/catalog-backend/CHANGELOG.md index 49ba2517f7..6e74d0d408 100644 --- a/plugins/catalog-backend/CHANGELOG.md +++ b/plugins/catalog-backend/CHANGELOG.md @@ -1,5 +1,62 @@ # @backstage/plugin-catalog-backend +## 1.14.0-next.1 + +### Patch Changes + +- 7a2e2924c7: Marked the `LocationEntityProcessor` as deprecated, as it is no longer used internally since way back and can even be harmful at this point. +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-search-backend-module-catalog@0.1.9-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/plugin-permission-node@0.7.16-next.1 + - @backstage/config@1.1.0 + - @backstage/backend-openapi-utils@0.0.4 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-events-node@0.2.14-next.1 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-scaffolder-common@1.4.1 + - @backstage/plugin-search-common@1.2.6 + +## 1.14.0-next.0 + +### Minor Changes + +- 78af9433c8: Instrumenting some missing metrics with `OpenTelemetry` + +### Patch Changes + +- 348e8c1cdb: Fixes a bug where eagerly deleted entities did not properly trigger re-stitching of entities that they had relations to. +- b97e9790f0: Internal refactors, laying the foundation for later introducing deferred stitching (see #18062). +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-openapi-utils@0.0.4 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-catalog-node@1.4.6-next.0 + - @backstage/plugin-events-node@0.2.14-next.0 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-permission-node@0.7.16-next.0 + - @backstage/plugin-scaffolder-common@1.4.1 + - @backstage/plugin-search-backend-module-catalog@0.1.9-next.0 + - @backstage/plugin-search-common@1.2.6 + ## 1.13.0 ### Minor Changes diff --git a/plugins/catalog-backend/api-report.md b/plugins/catalog-backend/api-report.md index 345874d919..e426ca1d75 100644 --- a/plugins/catalog-backend/api-report.md +++ b/plugins/catalog-backend/api-report.md @@ -365,7 +365,7 @@ export type LocationAnalyzer = { ): Promise<AnalyzeLocationResponse>; }; -// @public (undocumented) +// @public @deprecated export class LocationEntityProcessor implements CatalogProcessor_2 { constructor(options: LocationEntityProcessorOptions); // (undocumented) @@ -378,7 +378,7 @@ export class LocationEntityProcessor implements CatalogProcessor_2 { ): Promise<Entity>; } -// @public (undocumented) +// @public @deprecated (undocumented) export type LocationEntityProcessorOptions = { integrations: ScmIntegrationRegistry; }; diff --git a/plugins/catalog-backend/package.json b/plugins/catalog-backend/package.json index a1a47ed13a..45826a1f39 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.13.0", + "version": "1.14.0-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend/src/database/DefaultProcessingDatabase.ts b/plugins/catalog-backend/src/database/DefaultProcessingDatabase.ts index 01025f73dd..2daf8e6fc5 100644 --- a/plugins/catalog-backend/src/database/DefaultProcessingDatabase.ts +++ b/plugins/catalog-backend/src/database/DefaultProcessingDatabase.ts @@ -42,7 +42,6 @@ import { import { checkLocationKeyConflict } from './operations/refreshState/checkLocationKeyConflict'; import { insertUnprocessedEntity } from './operations/refreshState/insertUnprocessedEntity'; import { updateUnprocessedEntity } from './operations/refreshState/updateUnprocessedEntity'; -import { deleteOrphanedEntities } from './operations/util/deleteOrphanedEntities'; import { generateStableHash } from './util'; import { EventBroker, EventParams } from '@backstage/plugin-events-node'; import { DateTime } from 'luxon'; @@ -275,11 +274,6 @@ export class DefaultProcessingDatabase implements ProcessingDatabase { return { entityRefs }; } - async deleteOrphanedEntities(txOpaque: Transaction): Promise<number> { - const tx = txOpaque as Knex.Transaction; - return await deleteOrphanedEntities({ tx }); - } - async transaction<T>(fn: (tx: Transaction) => Promise<T>): Promise<T> { try { let result: T | undefined = undefined; diff --git a/plugins/catalog-backend/src/database/metrics.ts b/plugins/catalog-backend/src/database/metrics.ts index b6c4e248dc..8eb307ea46 100644 --- a/plugins/catalog-backend/src/database/metrics.ts +++ b/plugins/catalog-backend/src/database/metrics.ts @@ -17,13 +17,17 @@ import { Knex } from 'knex'; import { createGaugeMetric } from '../util/metrics'; import { DbRefreshStateRow, DbRelationsRow, DbLocationsRow } from './tables'; +import { metrics } from '@opentelemetry/api'; +import { parseEntityRef } from '@backstage/catalog-model'; export function initDatabaseMetrics(knex: Knex) { + const seenProm = new Set<string>(); const seen = new Set<string>(); + const meter = metrics.getMeter('default'); return { - entities_count: createGaugeMetric({ + entities_count_prom: createGaugeMetric({ name: 'catalog_entities_count', - help: 'Total amount of entities in the catalog', + help: 'Total amount of entities in the catalog. DEPRECATED: Please use opentelemetry metrics instead.', labelNames: ['kind'], async collect() { const result = await knex<DbRefreshStateRow>('refresh_state').select( @@ -34,22 +38,22 @@ export function initDatabaseMetrics(knex: Knex) { .reduce((acc, e) => acc.set(e, (acc.get(e) || 0) + 1), new Map()); results.forEach((value, key) => { - seen.add(key); + seenProm.add(key); this.set({ kind: key }, value); }); - // Set all the entities that were not seen to 0 and delete them from the seen set. - seen.forEach(key => { + // Set all the entities that were not seenProm to 0 and delete them from the seenProm set. + seenProm.forEach(key => { if (!results.has(key)) { this.set({ kind: key }, 0); - seen.delete(key); + seenProm.delete(key); } }); }, }), - registered_locations: createGaugeMetric({ + registered_locations_prom: createGaugeMetric({ name: 'catalog_registered_locations_count', - help: 'Total amount of registered locations in the catalog', + help: 'Total amount of registered locations in the catalog. DEPRECATED: Please use opentelemetry metrics instead.', async collect() { const total = await knex<DbLocationsRow>('locations').count({ count: '*', @@ -57,9 +61,9 @@ export function initDatabaseMetrics(knex: Knex) { this.set(Number(total[0].count)); }, }), - relations: createGaugeMetric({ + relations_prom: createGaugeMetric({ name: 'catalog_relations_count', - help: 'Total amount of relations between entities', + help: 'Total amount of relations between entities. DEPRECATED: Please use opentelemetry metrics instead.', async collect() { const total = await knex<DbRelationsRow>('relations').count({ count: '*', @@ -67,5 +71,50 @@ export function initDatabaseMetrics(knex: Knex) { this.set(Number(total[0].count)); }, }), + entities_count: meter + .createObservableGauge('catalog_entities_count', { + description: 'Total amount of entities in the catalog', + }) + .addCallback(async gauge => { + const result = await knex<DbRefreshStateRow>('refresh_state').select( + 'entity_ref', + ); + const results = result + .map(row => parseEntityRef(row.entity_ref).kind) + .reduce((acc, e) => acc.set(e, (acc.get(e) || 0) + 1), new Map()); + + results.forEach((value, key) => { + seen.add(key); + gauge.observe(value, { kind: key }); + }); + + // Set all the entities that were not seen to 0 and delete them from the seen set. + seen.forEach(key => { + if (!results.has(key)) { + gauge.observe(0, { kind: key }); + seen.delete(key); + } + }); + }), + registered_locations: meter + .createObservableGauge('catalog_registered_locations_count', { + description: 'Total amount of registered locations in the catalog', + }) + .addCallback(async gauge => { + const total = await knex<DbLocationsRow>('locations').count({ + count: '*', + }); + gauge.observe(Number(total[0].count)); + }), + relations: meter + .createObservableGauge('catalog_relations_count', { + description: 'Total amount of relations between entities', + }) + .addCallback(async gauge => { + const total = await knex<DbRelationsRow>('relations').count({ + count: '*', + }); + gauge.observe(Number(total[0].count)); + }), }; } diff --git a/plugins/catalog-backend/src/database/operations/provider/deleteWithEagerPruningOfChildren.test.ts b/plugins/catalog-backend/src/database/operations/provider/deleteWithEagerPruningOfChildren.test.ts index dcd87613de..830cc20480 100644 --- a/plugins/catalog-backend/src/database/operations/provider/deleteWithEagerPruningOfChildren.test.ts +++ b/plugins/catalog-backend/src/database/operations/provider/deleteWithEagerPruningOfChildren.test.ts @@ -18,7 +18,11 @@ import { TestDatabaseId, TestDatabases } from '@backstage/backend-test-utils'; import { Knex } from 'knex'; import * as uuid from 'uuid'; import { applyDatabaseMigrations } from '../../migrations'; -import { DbRefreshStateReferencesRow, DbRefreshStateRow } from '../../tables'; +import { + DbRefreshStateReferencesRow, + DbRefreshStateRow, + DbRelationsRow, +} from '../../tables'; import { deleteWithEagerPruningOfChildren } from './deleteWithEagerPruningOfChildren'; jest.setTimeout(60_000); @@ -43,6 +47,22 @@ describe('deleteWithEagerPruningOfChildren', () => { ); } + async function insertRelation( + knex: Knex, + ...relations: { from: string; to: string }[] + ) { + for (const rel of relations) { + await knex<DbRelationsRow>('relations').insert({ + originating_entity_id: await knex<DbRefreshStateRow>('refresh_state') + .select('entity_id') + .then(rows => rows[0].entity_id), // doesn't matter which one, this is consumed pre-deletion + source_entity_ref: rel.from, + target_entity_ref: rel.to, + type: 'fake', + }); + } + } + async function insertEntity(knex: Knex, ...entityRefs: string[]) { for (const ref of entityRefs) { await knex<DbRefreshStateRow>('refresh_state').insert({ @@ -64,6 +84,14 @@ describe('deleteWithEagerPruningOfChildren', () => { return rows.map(r => r.entity_ref); } + async function entitiesMarkedForStitching(knex: Knex) { + const rows = await knex<DbRefreshStateRow>('refresh_state') + .orderBy('entity_ref') + .select('entity_ref') + .where('result_hash', '=', 'force-stitching'); + return rows.map(r => r.entity_ref); + } + it.each(databases.eachSupportedId())( 'works for the simple path, %p', async databaseId => { @@ -78,7 +106,7 @@ describe('deleteWithEagerPruningOfChildren', () => { Scenario: P1 issues delete for E1 and E3 - Result: E1, E2, and E3 deleted; E4 and E5 remain + Result: E1, E2, and E3 deleted; E4 and E5 remain; E4 marked for stitching because it had a relation to a deleted entity */ const knex = await createDatabase(databaseId); await insertEntity(knex, 'E1', 'E2', 'E3', 'E4', 'E5'); @@ -90,12 +118,14 @@ describe('deleteWithEagerPruningOfChildren', () => { { source_key: 'P1', target_entity_ref: 'E4' }, { source_key: 'P2', target_entity_ref: 'E5' }, ); + await insertRelation(knex, { from: 'E4', to: 'E2' }); await deleteWithEagerPruningOfChildren({ knex, sourceKey: 'P1', entityRefs: ['E1', 'E3'], }); await expect(remainingEntities(knex)).resolves.toEqual(['E4', 'E5']); + await expect(entitiesMarkedForStitching(knex)).resolves.toEqual(['E4']); }, ); @@ -113,7 +143,7 @@ describe('deleteWithEagerPruningOfChildren', () => { Scenario: P1 issues delete for E1 - Result: E1 deleted; E2 remains + Result: E1 deleted; E2 remains; E2 marked for stitching because it had a relation to a deleted entity */ const knex = await createDatabase(databaseId); await insertEntity(knex, 'E1', 'E2'); @@ -123,12 +153,14 @@ describe('deleteWithEagerPruningOfChildren', () => { { source_key: 'P1', target_entity_ref: 'E1' }, { source_key: 'P1', target_entity_ref: 'E2' }, ); + await insertRelation(knex, { from: 'E2', to: 'E1' }); await deleteWithEagerPruningOfChildren({ knex, sourceKey: 'P1', entityRefs: ['E1'], }); await expect(remainingEntities(knex)).resolves.toEqual(['E2']); + await expect(entitiesMarkedForStitching(knex)).resolves.toEqual(['E2']); }, ); @@ -144,7 +176,7 @@ describe('deleteWithEagerPruningOfChildren', () => { Scenario: P1 issues delete for E1 - Result: E1 deleted; E2 and E3 remain + Result: E1 deleted; E2 and E3 remain; E2 marked for stitching because it had a relation to a deleted entity */ const knex = await createDatabase(databaseId); await insertEntity(knex, 'E1', 'E2', 'E3'); @@ -155,12 +187,18 @@ describe('deleteWithEagerPruningOfChildren', () => { { source_key: 'P2', target_entity_ref: 'E3' }, { source_entity_ref: 'E3', target_entity_ref: 'E2' }, ); + await insertRelation( + knex, + { from: 'E2', to: 'E1' }, + { from: 'E3', to: 'E2' }, + ); await deleteWithEagerPruningOfChildren({ knex, sourceKey: 'P1', entityRefs: ['E1'], }); await expect(remainingEntities(knex)).resolves.toEqual(['E2', 'E3']); + await expect(entitiesMarkedForStitching(knex)).resolves.toEqual(['E2']); }, ); @@ -193,6 +231,7 @@ describe('deleteWithEagerPruningOfChildren', () => { entityRefs: ['E1'], }); await expect(remainingEntities(knex)).resolves.toEqual(['E2', 'E3']); + await expect(entitiesMarkedForStitching(knex)).resolves.toEqual([]); }, ); @@ -208,7 +247,7 @@ describe('deleteWithEagerPruningOfChildren', () => { Scenario: P1 issues delete for E1, then for E3 - Result: Everything deleted, but in two steps + Result: Everything deleted, but in two steps; E4 marked for stitching in the first step because it had a relation to a deleted entity */ const knex = await createDatabase(databaseId); await insertEntity(knex, 'E1', 'E2', 'E3', 'E4', 'E5', 'E6'); @@ -224,6 +263,7 @@ describe('deleteWithEagerPruningOfChildren', () => { { source_entity_ref: 'E3', target_entity_ref: 'E5' }, { source_entity_ref: 'E5', target_entity_ref: 'E6' }, ); + await insertRelation(knex, { from: 'E4', to: 'E2' }); await deleteWithEagerPruningOfChildren({ knex, sourceKey: 'P1', @@ -235,12 +275,14 @@ describe('deleteWithEagerPruningOfChildren', () => { 'E5', 'E6', ]); + await expect(entitiesMarkedForStitching(knex)).resolves.toEqual(['E4']); await deleteWithEagerPruningOfChildren({ knex, sourceKey: 'P1', entityRefs: ['E3'], }); await expect(remainingEntities(knex)).resolves.toEqual([]); + await expect(entitiesMarkedForStitching(knex)).resolves.toEqual([]); }, ); @@ -277,6 +319,7 @@ describe('deleteWithEagerPruningOfChildren', () => { 'E2', 'E4', ]); + await expect(entitiesMarkedForStitching(knex)).resolves.toEqual([]); }, ); }); diff --git a/plugins/catalog-backend/src/database/operations/provider/deleteWithEagerPruningOfChildren.ts b/plugins/catalog-backend/src/database/operations/provider/deleteWithEagerPruningOfChildren.ts index 027860fcc6..70f7d08ed1 100644 --- a/plugins/catalog-backend/src/database/operations/provider/deleteWithEagerPruningOfChildren.ts +++ b/plugins/catalog-backend/src/database/operations/provider/deleteWithEagerPruningOfChildren.ts @@ -16,7 +16,11 @@ import { Knex } from 'knex'; import lodash from 'lodash'; -import { DbRefreshStateReferencesRow } from '../../tables'; +import { + DbFinalEntitiesRow, + DbRefreshStateReferencesRow, + DbRefreshStateRow, +} from '../../tables'; /** * Given a number of entity refs originally created by a given entity provider @@ -36,152 +40,24 @@ export async function deleteWithEagerPruningOfChildren(options: { // limits for the number of permitted bindings on a precompiled statement let removedCount = 0; for (const refs of lodash.chunk(entityRefs, 1000)) { - removedCount += await knex - .delete() - .from('refresh_state') - .whereIn('entity_ref', orphans => - orphans - // First find all nodes that can be reached downwards from the roots - // (deletion targets), including the roots themselves, by traversing - // down the refresh_state_references table. Note that this query - // starts with a condition that source_key = our source key, and - // target_entity_ref is one of the deletion targets. This has two - // effects: it won't match attempts at deleting something that didn't - // originate from us in the first place, and also won't match non-root - // entities (source_key would be null for those). - // - // KeyA - R1 - R2 Legend: - // \ ----------------------------------------- - // R3 Key* Source key - // / R* Entity ref - // KeyA - R4 - R5 lines Individual references; sources to - // / the left and targets to the right - // KeyB --- R6 - // - // The scenario is that KeyA wants to delete R1. - // - // The query starts with the KeyA-R1 reference, and then traverses - // down to also find R2 and R3. It uses union instead of union all, - // because it wants to find the set of unique descendants even if - // the tree has unexpected loops etc. - .withRecursive('descendants', ['entity_ref'], initial => - initial - .select('target_entity_ref') - .from('refresh_state_references') - .where('source_key', '=', sourceKey) - .whereIn('target_entity_ref', refs) - .union(recursive => - recursive - .select('refresh_state_references.target_entity_ref') - .from('descendants') - .join( - 'refresh_state_references', - 'descendants.entity_ref', - 'refresh_state_references.source_entity_ref', - ), - ), - ) - // Then for each descendant, traverse all the way back upwards through - // the refresh_state_references table to get an exhaustive list of all - // references that are part of keeping that particular descendant - // alive. - // - // Continuing the scenario from above, starting from R3, it goes - // upwards to find every pair along every relation line. - // - // Top branch: R2-R3, R1-R2, KeyA-R1 - // Middle branch: R5-R3, R4-R5, KeyA-R4 - // Bottom branch: R6-R5, KeyB-R6 - // - // Note that this all applied to the subject R3. The exact same thing - // will be done starting from each other descendant (R2 and R1). They - // only have one and two references to find, respectively. - // - // This query also uses union instead of union all, to get the set of - // distinct relations even if the tree has unexpected loops etc. - .withRecursive( - 'ancestors', - ['source_key', 'source_entity_ref', 'target_entity_ref', 'subject'], - initial => - initial - .select( - 'refresh_state_references.source_key', - 'refresh_state_references.source_entity_ref', - 'refresh_state_references.target_entity_ref', - 'descendants.entity_ref', - ) - .from('descendants') - .join( - 'refresh_state_references', - 'refresh_state_references.target_entity_ref', - 'descendants.entity_ref', - ) - .union(recursive => - recursive - .select( - 'refresh_state_references.source_key', - 'refresh_state_references.source_entity_ref', - 'refresh_state_references.target_entity_ref', - 'ancestors.subject', - ) - .from('ancestors') - .join( - 'refresh_state_references', - 'refresh_state_references.target_entity_ref', - 'ancestors.source_entity_ref', - ), - ), - ) - // Finally, from that list of ancestor relations per descendant, pick - // out the ones that are roots (have a source_key). Specifically, find - // ones that seem to be be either (1) from another source, or (2) - // aren't part of the deletion targets. Those are markers that tell us - // that the corresponding descendant should be kept alive and NOT - // subject to eager deletion, because there's "something else" (not - // targeted for deletion) that has references down through the tree to - // it. - // - // Continuing the scenario from above, for R3 we have - // - // KeyA-R1, KeyA-R4, KeyB-R6 - // - // This tells us that R3 should be kept alive for two reasons: it's - // referenced by a node that isn't being deleted (R4), and also by - // another source (KeyB). What about R1 and R2? They both have - // - // KeyA-R1 - // - // So those should be deleted, since they are definitely only being - // kept alive by something that's about to be deleted. - // - // Final shape of the tree: - // - // R3 - // / - // KeyA - R4 - R5 - // / - // KeyB --- R6 - .with('retained', ['entity_ref'], notPartOfDeletion => - notPartOfDeletion - .select('subject') - .from('ancestors') - .whereNotNull('ancestors.source_key') - .where(foreignKeyOrRef => - foreignKeyOrRef - .where('ancestors.source_key', '!=', sourceKey) - .orWhereNotIn('ancestors.target_entity_ref', refs), - ), - ) - // Return all descendants minus the retained ones - .select('descendants.entity_ref') - .from('descendants') - .leftOuterJoin( - 'retained', - 'retained.entity_ref', - 'descendants.entity_ref', - ) - .whereNull('retained.entity_ref'), - ); + const { orphanEntityRefs } = + await findDescendantsThatWouldHaveBeenOrphanedByDeletion({ + knex: options.knex, + refs, + sourceKey, + }); + + // Chunk again - these can be many more than the outer chunk size + for (const refsToDelete of lodash.chunk(orphanEntityRefs, 1000)) { + await markEntitiesAffectedByDeletionForStitching({ + knex: options.knex, + entityRefs: refsToDelete, + }); + await knex + .delete() + .from('refresh_state') + .whereIn('entity_ref', refsToDelete); + } // Delete the references that originate only from this entity provider. Note // that there may be more than one entity provider making a "claim" for a @@ -190,7 +66,202 @@ export async function deleteWithEagerPruningOfChildren(options: { .where('source_key', '=', sourceKey) .whereIn('target_entity_ref', refs) .delete(); + + removedCount += orphanEntityRefs.length; } return removedCount; } + +async function findDescendantsThatWouldHaveBeenOrphanedByDeletion(options: { + knex: Knex | Knex.Transaction; + refs: string[]; + sourceKey: string; +}): Promise<{ orphanEntityRefs: string[] }> { + const { knex, refs, sourceKey } = options; + + const orphans: string[] = + // First find all nodes that can be reached downwards from the roots + // (deletion targets), including the roots themselves, by traversing + // down the refresh_state_references table. Note that this query + // starts with a condition that source_key = our source key, and + // target_entity_ref is one of the deletion targets. This has two + // effects: it won't match attempts at deleting something that didn't + // originate from us in the first place, and also won't match non-root + // entities (source_key would be null for those). + // + // KeyA - R1 - R2 Legend: + // \ ----------------------------------------- + // R3 Key* Source key + // / R* Entity ref + // KeyA - R4 - R5 lines Individual references; sources to + // / the left and targets to the right + // KeyB --- R6 + // + // The scenario is that KeyA wants to delete R1. + // + // The query starts with the KeyA-R1 reference, and then traverses + // down to also find R2 and R3. It uses union instead of union all, + // because it wants to find the set of unique descendants even if + // the tree has unexpected loops etc. + await knex + .withRecursive('descendants', ['entity_ref'], initial => + initial + .select('target_entity_ref') + .from('refresh_state_references') + .where('source_key', '=', sourceKey) + .whereIn('target_entity_ref', refs) + .union(recursive => + recursive + .select('refresh_state_references.target_entity_ref') + .from('descendants') + .join( + 'refresh_state_references', + 'descendants.entity_ref', + 'refresh_state_references.source_entity_ref', + ), + ), + ) + // Then for each descendant, traverse all the way back upwards through + // the refresh_state_references table to get an exhaustive list of all + // references that are part of keeping that particular descendant + // alive. + // + // Continuing the scenario from above, starting from R3, it goes + // upwards to find every pair along every relation line. + // + // Top branch: R2-R3, R1-R2, KeyA-R1 + // Middle branch: R5-R3, R4-R5, KeyA-R4 + // Bottom branch: R6-R5, KeyB-R6 + // + // Note that this all applied to the subject R3. The exact same thing + // will be done starting from each other descendant (R2 and R1). They + // only have one and two references to find, respectively. + // + // This query also uses union instead of union all, to get the set of + // distinct relations even if the tree has unexpected loops etc. + .withRecursive( + 'ancestors', + ['source_key', 'source_entity_ref', 'target_entity_ref', 'subject'], + initial => + initial + .select( + 'refresh_state_references.source_key', + 'refresh_state_references.source_entity_ref', + 'refresh_state_references.target_entity_ref', + 'descendants.entity_ref', + ) + .from('descendants') + .join( + 'refresh_state_references', + 'refresh_state_references.target_entity_ref', + 'descendants.entity_ref', + ) + .union(recursive => + recursive + .select( + 'refresh_state_references.source_key', + 'refresh_state_references.source_entity_ref', + 'refresh_state_references.target_entity_ref', + 'ancestors.subject', + ) + .from('ancestors') + .join( + 'refresh_state_references', + 'refresh_state_references.target_entity_ref', + 'ancestors.source_entity_ref', + ), + ), + ) + // Finally, from that list of ancestor relations per descendant, pick + // out the ones that are roots (have a source_key). Specifically, find + // ones that seem to be be either (1) from another source, or (2) + // aren't part of the deletion targets. Those are markers that tell us + // that the corresponding descendant should be kept alive and NOT + // subject to eager deletion, because there's "something else" (not + // targeted for deletion) that has references down through the tree to + // it. + // + // Continuing the scenario from above, for R3 we have + // + // KeyA-R1, KeyA-R4, KeyB-R6 + // + // This tells us that R3 should be kept alive for two reasons: it's + // referenced by a node that isn't being deleted (R4), and also by + // another source (KeyB). What about R1 and R2? They both have + // + // KeyA-R1 + // + // So those should be deleted, since they are definitely only being + // kept alive by something that's about to be deleted. + // + // Final shape of the tree: + // + // R3 + // / + // KeyA - R4 - R5 + // / + // KeyB --- R6 + .with('retained', ['entity_ref'], notPartOfDeletion => + notPartOfDeletion + .select('subject') + .from('ancestors') + .whereNotNull('ancestors.source_key') + .where(foreignKeyOrRef => + foreignKeyOrRef + .where('ancestors.source_key', '!=', sourceKey) + .orWhereNotIn('ancestors.target_entity_ref', refs), + ), + ) + // Return all descendants minus the retained ones + .select('descendants.entity_ref AS entity_ref') + .from('descendants') + .leftOuterJoin( + 'retained', + 'retained.entity_ref', + 'descendants.entity_ref', + ) + .whereNull('retained.entity_ref') + .then(rows => rows.map(row => row.entity_ref)); + + return { orphanEntityRefs: orphans }; +} + +async function markEntitiesAffectedByDeletionForStitching(options: { + knex: Knex | Knex.Transaction; + entityRefs: string[]; +}) { + const { knex, entityRefs } = options; + + // We want to re-stitch anything that has a relation pointing to the + // soon-to-be-deleted entity. In many circumstances we also re-stitch children + // in the refresh_state_references graph because their orphan state might + // change, but not here - this code by its very definition is meant to not + // leave any orphans behind, so we can simplify away that. + const affectedIds = await knex + .select('refresh_state.entity_id AS entity_id') + .from('relations') + .join( + 'refresh_state', + 'relations.source_entity_ref', + 'refresh_state.entity_ref', + ) + .whereIn('relations.target_entity_ref', entityRefs) + .then(rows => rows.map(row => row.entity_id)); + + for (const ids of lodash.chunk(affectedIds, 1000)) { + await knex + .table<DbFinalEntitiesRow>('final_entities') + .update({ + hash: 'force-stitching', + }) + .whereIn('entity_id', ids); + await knex + .table<DbRefreshStateRow>('refresh_state') + .update({ + result_hash: 'force-stitching', + next_update_at: knex.fn.now(), + }) + .whereIn('entity_id', ids); + } +} diff --git a/plugins/catalog-backend/src/stitching/buildEntitySearch.test.ts b/plugins/catalog-backend/src/database/operations/stitcher/buildEntitySearch.test.ts similarity index 99% rename from plugins/catalog-backend/src/stitching/buildEntitySearch.test.ts rename to plugins/catalog-backend/src/database/operations/stitcher/buildEntitySearch.test.ts index 384794d230..8bc5ba57a9 100644 --- a/plugins/catalog-backend/src/stitching/buildEntitySearch.test.ts +++ b/plugins/catalog-backend/src/database/operations/stitcher/buildEntitySearch.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { Entity, DEFAULT_NAMESPACE } from '@backstage/catalog-model'; +import { DEFAULT_NAMESPACE, Entity } from '@backstage/catalog-model'; import { buildEntitySearch, mapToRows, traverse } from './buildEntitySearch'; describe('buildEntitySearch', () => { diff --git a/plugins/catalog-backend/src/stitching/buildEntitySearch.ts b/plugins/catalog-backend/src/database/operations/stitcher/buildEntitySearch.ts similarity index 98% rename from plugins/catalog-backend/src/stitching/buildEntitySearch.ts rename to plugins/catalog-backend/src/database/operations/stitcher/buildEntitySearch.ts index b97083f207..30f2987cb5 100644 --- a/plugins/catalog-backend/src/stitching/buildEntitySearch.ts +++ b/plugins/catalog-backend/src/database/operations/stitcher/buildEntitySearch.ts @@ -14,9 +14,9 @@ * limitations under the License. */ -import { Entity, DEFAULT_NAMESPACE } from '@backstage/catalog-model'; +import { DEFAULT_NAMESPACE, Entity } from '@backstage/catalog-model'; import { InputError } from '@backstage/errors'; -import { DbSearchRow } from '../database/tables'; +import { DbSearchRow } from '../../tables'; // These are excluded in the generic loop, either because they do not make sense // to index, or because they are special-case always inserted whether they are diff --git a/plugins/catalog-backend/src/database/operations/stitcher/markForStitching.test.ts b/plugins/catalog-backend/src/database/operations/stitcher/markForStitching.test.ts new file mode 100644 index 0000000000..ce44fe15d8 --- /dev/null +++ b/plugins/catalog-backend/src/database/operations/stitcher/markForStitching.test.ts @@ -0,0 +1,260 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { TestDatabases } from '@backstage/backend-test-utils'; +import { applyDatabaseMigrations } from '../../migrations'; +import { markForStitching } from './markForStitching'; +import { DbFinalEntitiesRow, DbRefreshStateRow } from '../../tables'; + +jest.setTimeout(60_000); + +describe('markForStitching', () => { + const databases = TestDatabases.create({ + ids: ['MYSQL_8', 'POSTGRES_13', 'POSTGRES_9', 'SQLITE_3'], + }); + + it.each(databases.eachSupportedId())( + 'marks the right rows in immediate mode %p', + async databaseId => { + const knex = await databases.init(databaseId); + await applyDatabaseMigrations(knex); + + await knex<DbRefreshStateRow>('refresh_state').insert([ + { + entity_id: '1', + entity_ref: 'k:ns/one', + unprocessed_entity: '{}', + processed_entity: '{}', + result_hash: 'old', + errors: '[]', + next_update_at: knex.fn.now(), + last_discovery_at: knex.fn.now(), + }, + { + entity_id: '2', + entity_ref: 'k:ns/two', + unprocessed_entity: '{}', + processed_entity: '{}', + result_hash: 'old', + errors: '[]', + next_update_at: knex.fn.now(), + last_discovery_at: knex.fn.now(), + }, + { + entity_id: '3', + entity_ref: 'k:ns/three', + unprocessed_entity: '{}', + processed_entity: '{}', + result_hash: 'old', + errors: '[]', + next_update_at: knex.fn.now(), + last_discovery_at: knex.fn.now(), + }, + { + entity_id: '4', + entity_ref: 'k:ns/four', + unprocessed_entity: '{}', + processed_entity: '{}', + result_hash: 'old', + errors: '[]', + next_update_at: knex.fn.now(), + last_discovery_at: knex.fn.now(), + }, + ]); + await knex<DbFinalEntitiesRow>('final_entities').insert([ + { + entity_id: '1', + final_entity: '{}', + hash: 'old', + stitch_ticket: 'old', + }, + { + entity_id: '2', + final_entity: '{}', + hash: 'old', + stitch_ticket: 'old', + }, + { + entity_id: '3', + final_entity: '{}', + hash: 'old', + stitch_ticket: 'old', + }, + { + entity_id: '4', + final_entity: '{}', + hash: 'old', + stitch_ticket: 'old', + }, + ]); + + async function result() { + return knex<DbRefreshStateRow>('refresh_state') + .leftJoin( + 'final_entities', + 'final_entities.entity_id', + 'refresh_state.entity_id', + ) + .select({ + entity_id: 'refresh_state.entity_id', + next_update_at: 'refresh_state.next_update_at', + refresh_state_hash: 'refresh_state.result_hash', + final_entities_hash: 'final_entities.hash', + }) + .orderBy('entity_id', 'asc'); + } + + // Ensure that now() isn't evaluating to the same thing + await new Promise(resolve => setTimeout(resolve, 1100)); + + const original = await result(); + + await markForStitching({ + knex, + strategy: { mode: 'immediate' }, + entityRefs: new Set(), + }); + await expect(result()).resolves.toEqual([ + { + entity_id: '1', + next_update_at: expect.anything(), + refresh_state_hash: 'old', + final_entities_hash: 'old', + }, + { + entity_id: '2', + next_update_at: expect.anything(), + refresh_state_hash: 'old', + final_entities_hash: 'old', + }, + { + entity_id: '3', + next_update_at: expect.anything(), + refresh_state_hash: 'old', + final_entities_hash: 'old', + }, + { + entity_id: '4', + next_update_at: expect.anything(), + refresh_state_hash: 'old', + final_entities_hash: 'old', + }, + ]); + + await markForStitching({ + knex, + strategy: { mode: 'immediate' }, + entityRefs: new Set(['k:ns/one']), + }); + await expect(result()).resolves.toEqual([ + { + entity_id: '1', + next_update_at: expect.anything(), + refresh_state_hash: 'force-stitching', + final_entities_hash: 'force-stitching', + }, + { + entity_id: '2', + next_update_at: expect.anything(), + refresh_state_hash: 'old', + final_entities_hash: 'old', + }, + { + entity_id: '3', + next_update_at: expect.anything(), + refresh_state_hash: 'old', + final_entities_hash: 'old', + }, + { + entity_id: '4', + next_update_at: expect.anything(), + refresh_state_hash: 'old', + final_entities_hash: 'old', + }, + ]); + + await markForStitching({ + knex, + strategy: { mode: 'immediate' }, + entityRefs: ['k:ns/two'], + }); + await expect(result()).resolves.toEqual([ + { + entity_id: '1', + next_update_at: expect.anything(), + refresh_state_hash: 'force-stitching', + final_entities_hash: 'force-stitching', + }, + { + entity_id: '2', + next_update_at: expect.anything(), + refresh_state_hash: 'force-stitching', + final_entities_hash: 'force-stitching', + }, + { + entity_id: '3', + next_update_at: expect.anything(), + refresh_state_hash: 'old', + final_entities_hash: 'old', + }, + { + entity_id: '4', + next_update_at: expect.anything(), + refresh_state_hash: 'old', + final_entities_hash: 'old', + }, + ]); + + await markForStitching({ + knex, + strategy: { mode: 'immediate' }, + entityIds: ['3', '4'], + }); + await expect(result()).resolves.toEqual([ + { + entity_id: '1', + next_update_at: expect.anything(), + refresh_state_hash: 'force-stitching', + final_entities_hash: 'force-stitching', + }, + { + entity_id: '2', + next_update_at: expect.anything(), + refresh_state_hash: 'force-stitching', + final_entities_hash: 'force-stitching', + }, + { + entity_id: '3', + next_update_at: expect.anything(), + refresh_state_hash: 'force-stitching', + final_entities_hash: 'force-stitching', + }, + { + entity_id: '4', + next_update_at: expect.anything(), + refresh_state_hash: 'force-stitching', + final_entities_hash: 'force-stitching', + }, + ]); + + // It overwrites timers + const final = await result(); + for (let i = 0; i < final.length; ++i) { + expect(original[i].next_update_at).not.toEqual(final[i].next_update_at); + } + }, + ); +}); diff --git a/plugins/catalog-backend/src/database/operations/stitcher/markForStitching.ts b/plugins/catalog-backend/src/database/operations/stitcher/markForStitching.ts new file mode 100644 index 0000000000..7ab9bda1c0 --- /dev/null +++ b/plugins/catalog-backend/src/database/operations/stitcher/markForStitching.ts @@ -0,0 +1,82 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Knex } from 'knex'; +import splitToChunks from 'lodash/chunk'; +import { StitchingStrategy } from '../../../stitching/types'; +import { DbFinalEntitiesRow, DbRefreshStateRow } from '../../tables'; + +/** + * Marks a number of entities for deferred stitching some time in the near + * future. + * + * @remarks + */ +export async function markForStitching(options: { + knex: Knex | Knex.Transaction; + strategy: StitchingStrategy; + entityRefs?: Iterable<string>; + entityIds?: Iterable<string>; +}): Promise<void> { + // Splitting to chunks just to cover pathological cases that upset the db + const entityRefs = split(options.entityRefs); + const entityIds = split(options.entityIds); + const knex = options.knex; + + for (const chunk of entityRefs) { + await knex + .table<DbFinalEntitiesRow>('final_entities') + .update({ + hash: 'force-stitching', + }) + .whereIn( + 'entity_id', + knex<DbRefreshStateRow>('refresh_state') + .select('entity_id') + .whereIn('entity_ref', chunk), + ); + await knex + .table<DbRefreshStateRow>('refresh_state') + .update({ + result_hash: 'force-stitching', + next_update_at: knex.fn.now(), + }) + .whereIn('entity_ref', chunk); + } + + for (const chunk of entityIds) { + await knex + .table<DbFinalEntitiesRow>('final_entities') + .update({ + hash: 'force-stitching', + }) + .whereIn('entity_id', chunk); + await knex + .table<DbRefreshStateRow>('refresh_state') + .update({ + result_hash: 'force-stitching', + next_update_at: knex.fn.now(), + }) + .whereIn('entity_id', chunk); + } +} + +function split(input: Iterable<string> | undefined): string[][] { + if (!input) { + return []; + } + return splitToChunks(Array.isArray(input) ? input : [...input], 200); +} diff --git a/plugins/catalog-backend/src/database/operations/stitcher/performStitching.test.ts b/plugins/catalog-backend/src/database/operations/stitcher/performStitching.test.ts new file mode 100644 index 0000000000..a864cbdef4 --- /dev/null +++ b/plugins/catalog-backend/src/database/operations/stitcher/performStitching.test.ts @@ -0,0 +1,287 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { getVoidLogger } from '@backstage/backend-common'; +import { TestDatabases } from '@backstage/backend-test-utils'; +import { Entity } from '@backstage/catalog-model'; +import { applyDatabaseMigrations } from '../../migrations'; +import { + DbFinalEntitiesRow, + DbRefreshStateReferencesRow, + DbRefreshStateRow, + DbRelationsRow, + DbSearchRow, +} from '../../tables'; +import { performStitching } from './performStitching'; + +jest.setTimeout(60_000); + +describe('performStitching', () => { + const databases = TestDatabases.create({ + ids: ['MYSQL_8', 'POSTGRES_13', 'POSTGRES_9', 'SQLITE_3'], + }); + const logger = getVoidLogger(); + + it.each(databases.eachSupportedId())( + 'runs the happy path in immediate mode for %p', + async databaseId => { + const knex = await databases.init(databaseId); + await applyDatabaseMigrations(knex); + + let entities: DbFinalEntitiesRow[]; + let entity: Entity; + + await knex<DbRefreshStateRow>('refresh_state').insert([ + { + entity_id: 'my-id', + entity_ref: 'k:ns/n', + unprocessed_entity: JSON.stringify({}), + processed_entity: JSON.stringify({ + apiVersion: 'a', + kind: 'k', + metadata: { + name: 'n', + namespace: 'ns', + }, + spec: { + k: 'v', + }, + }), + errors: '[]', + next_update_at: knex.fn.now(), + last_discovery_at: knex.fn.now(), + }, + ]); + await knex<DbRefreshStateReferencesRow>( + 'refresh_state_references', + ).insert([{ source_key: 'a', target_entity_ref: 'k:ns/n' }]); + await knex<DbRelationsRow>('relations').insert([ + { + originating_entity_id: 'my-id', + source_entity_ref: 'k:ns/n', + type: 'looksAt', + target_entity_ref: 'k:ns/other', + }, + // handles and ignores duplicates + { + originating_entity_id: 'my-id', + source_entity_ref: 'k:ns/n', + type: 'looksAt', + target_entity_ref: 'k:ns/other', + }, + ]); + + await performStitching({ + knex, + logger, + strategy: { mode: 'immediate' }, + entityRef: 'k:ns/n', + }); + + entities = await knex<DbFinalEntitiesRow>('final_entities'); + + expect(entities.length).toBe(1); + entity = JSON.parse(entities[0].final_entity!); + expect(entity).toEqual({ + relations: [ + { + type: 'looksAt', + targetRef: 'k:ns/other', + }, + ], + apiVersion: 'a', + kind: 'k', + metadata: { + name: 'n', + namespace: 'ns', + etag: expect.any(String), + uid: 'my-id', + }, + spec: { + k: 'v', + }, + }); + + expect(entity.metadata.etag).toEqual(entities[0].hash); + const last_updated_at = entities[0].last_updated_at; + expect(last_updated_at).not.toBeNull(); + const firstHash = entities[0].hash; + + const search = await knex<DbSearchRow>('search'); + expect(search).toEqual( + expect.arrayContaining([ + { + entity_id: 'my-id', + key: 'relations.looksat', + original_value: 'k:ns/other', + value: 'k:ns/other', + }, + { + entity_id: 'my-id', + key: 'apiversion', + original_value: 'a', + value: 'a', + }, + { + entity_id: 'my-id', + key: 'kind', + original_value: 'k', + value: 'k', + }, + { + entity_id: 'my-id', + key: 'metadata.name', + original_value: 'n', + value: 'n', + }, + { + entity_id: 'my-id', + key: 'metadata.namespace', + original_value: 'ns', + value: 'ns', + }, + { + entity_id: 'my-id', + key: 'metadata.uid', + original_value: 'my-id', + value: 'my-id', + }, + { + entity_id: 'my-id', + key: 'spec.k', + original_value: 'v', + value: 'v', + }, + ]), + ); + + // Re-stitch without any changes + await performStitching({ + knex, + logger, + strategy: { mode: 'immediate' }, + entityRef: 'k:ns/n', + }); + + entities = await knex<DbFinalEntitiesRow>('final_entities'); + expect(entities.length).toBe(1); + entity = JSON.parse(entities[0].final_entity!); + expect(entities[0].hash).toEqual(firstHash); + expect(entity.metadata.etag).toEqual(firstHash); + + // Now add one more relation and re-stitch + await knex<DbRelationsRow>('relations').insert([ + { + originating_entity_id: 'my-id', + source_entity_ref: 'k:ns/n', + type: 'looksAt', + target_entity_ref: 'k:ns/third', + }, + ]); + + await performStitching({ + knex, + logger, + strategy: { mode: 'immediate' }, + entityRef: 'k:ns/n', + }); + + entities = await knex<DbFinalEntitiesRow>('final_entities'); + + expect(entities.length).toBe(1); + entity = JSON.parse(entities[0].final_entity!); + expect(entity).toEqual({ + relations: expect.arrayContaining([ + { + type: 'looksAt', + targetRef: 'k:ns/other', + }, + { + type: 'looksAt', + targetRef: 'k:ns/third', + }, + ]), + apiVersion: 'a', + kind: 'k', + metadata: { + name: 'n', + namespace: 'ns', + etag: expect.any(String), + uid: 'my-id', + }, + spec: { + k: 'v', + }, + }); + + expect(entities[0].hash).not.toEqual(firstHash); + expect(entities[0].hash).toEqual(entity.metadata.etag); + + expect(await knex<DbSearchRow>('search')).toEqual( + expect.arrayContaining([ + { + entity_id: 'my-id', + key: 'relations.looksat', + original_value: 'k:ns/other', + value: 'k:ns/other', + }, + { + entity_id: 'my-id', + key: 'relations.looksat', + original_value: 'k:ns/third', + value: 'k:ns/third', + }, + { + entity_id: 'my-id', + key: 'apiversion', + original_value: 'a', + value: 'a', + }, + { + entity_id: 'my-id', + key: 'kind', + original_value: 'k', + value: 'k', + }, + { + entity_id: 'my-id', + key: 'metadata.name', + original_value: 'n', + value: 'n', + }, + { + entity_id: 'my-id', + key: 'metadata.namespace', + original_value: 'ns', + value: 'ns', + }, + { + entity_id: 'my-id', + key: 'metadata.uid', + original_value: 'my-id', + value: 'my-id', + }, + { + entity_id: 'my-id', + key: 'spec.k', + original_value: 'v', + value: 'v', + }, + ]), + ); + }, + ); +}); diff --git a/plugins/catalog-backend/src/database/operations/stitcher/performStitching.ts b/plugins/catalog-backend/src/database/operations/stitcher/performStitching.ts new file mode 100644 index 0000000000..bcb112690c --- /dev/null +++ b/plugins/catalog-backend/src/database/operations/stitcher/performStitching.ts @@ -0,0 +1,236 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ENTITY_STATUS_CATALOG_PROCESSING_TYPE } from '@backstage/catalog-client'; +import { + ANNOTATION_EDIT_URL, + ANNOTATION_VIEW_URL, + EntityRelation, +} from '@backstage/catalog-model'; +import { AlphaEntity, EntityStatusItem } from '@backstage/catalog-model/alpha'; +import { SerializedError } from '@backstage/errors'; +import { Knex } from 'knex'; +import { v4 as uuid } from 'uuid'; +import { Logger } from 'winston'; +import { StitchingStrategy } from '../../../stitching/types'; +import { + DbFinalEntitiesRow, + DbRefreshStateRow, + DbSearchRow, +} from '../../tables'; +import { buildEntitySearch } from './buildEntitySearch'; +import { BATCH_SIZE, generateStableHash } from './util'; + +// See https://github.com/facebook/react/blob/f0cf832e1d0c8544c36aa8b310960885a11a847c/packages/react-dom-bindings/src/shared/sanitizeURL.js +const scriptProtocolPattern = + // eslint-disable-next-line no-control-regex + /^[\u0000-\u001F ]*j[\r\n\t]*a[\r\n\t]*v[\r\n\t]*a[\r\n\t]*s[\r\n\t]*c[\r\n\t]*r[\r\n\t]*i[\r\n\t]*p[\r\n\t]*t[\r\n\t]*\:/i; + +/** + * Performs the act of stitching - to take all of the various outputs from the + * ingestion process, and stitching them together into the final entity JSON + * shape. + */ +export async function performStitching(options: { + knex: Knex | Knex.Transaction; + logger: Logger; + strategy: StitchingStrategy; + entityRef: string; + stitchTicket?: string; +}): Promise<'changed' | 'unchanged' | 'abandoned'> { + const { knex, logger, entityRef } = options; + const stitchTicket = options.stitchTicket ?? uuid(); + + const entityResult = await knex<DbRefreshStateRow>('refresh_state') + .where({ entity_ref: entityRef }) + .limit(1) + .select('entity_id'); + if (!entityResult.length) { + // Entity does no exist in refresh state table, no stitching required. + return 'abandoned'; + } + + // Insert stitching ticket that will be compared before inserting the final entity. + await knex<DbFinalEntitiesRow>('final_entities') + .insert({ + entity_id: entityResult[0].entity_id, + hash: '', + stitch_ticket: stitchTicket, + }) + .onConflict('entity_id') + .merge(['stitch_ticket']); + + // Selecting from refresh_state and final_entities should yield exactly + // one row (except in abnormal cases where the stitch was invoked for + // something that didn't exist at all, in which case it's zero rows). + // The join with the temporary incoming_references still gives one row. + const [processedResult, relationsResult] = await Promise.all([ + knex + .with('incoming_references', function incomingReferences(builder) { + return builder + .from('refresh_state_references') + .where({ target_entity_ref: entityRef }) + .count({ count: '*' }); + }) + .select({ + entityId: 'refresh_state.entity_id', + processedEntity: 'refresh_state.processed_entity', + errors: 'refresh_state.errors', + incomingReferenceCount: 'incoming_references.count', + previousHash: 'final_entities.hash', + }) + .from('refresh_state') + .where({ 'refresh_state.entity_ref': entityRef }) + .crossJoin(knex.raw('incoming_references')) + .leftOuterJoin('final_entities', { + 'final_entities.entity_id': 'refresh_state.entity_id', + }), + knex + .distinct({ + relationType: 'type', + relationTarget: 'target_entity_ref', + }) + .from('relations') + .where({ source_entity_ref: entityRef }) + .orderBy('relationType', 'asc') + .orderBy('relationTarget', 'asc'), + ]); + + // If there were no rows returned, it would mean that there was no + // matching row even in the refresh_state. This can happen for example + // if we emit a relation to something that hasn't been ingested yet. + // It's safe to ignore this stitch attempt in that case. + if (!processedResult.length) { + logger.debug( + `Unable to stitch ${entityRef}, item does not exist in refresh state table`, + ); + return 'abandoned'; + } + + const { + entityId, + processedEntity, + errors, + incomingReferenceCount, + previousHash, + } = processedResult[0]; + + // If there was no processed entity in place, the target hasn't been + // through the processing steps yet. It's safe to ignore this stitch + // attempt in that case, since another stitch will be triggered when + // that processing has finished. + if (!processedEntity) { + logger.debug( + `Unable to stitch ${entityRef}, the entity has not yet been processed`, + ); + return 'abandoned'; + } + + // Grab the processed entity and stitch all of the relevant data into + // it + const entity = JSON.parse(processedEntity) as AlphaEntity; + const isOrphan = Number(incomingReferenceCount) === 0; + let statusItems: EntityStatusItem[] = []; + + if (isOrphan) { + logger.debug(`${entityRef} is an orphan`); + entity.metadata.annotations = { + ...entity.metadata.annotations, + ['backstage.io/orphan']: 'true', + }; + } + if (errors) { + const parsedErrors = JSON.parse(errors) as SerializedError[]; + if (Array.isArray(parsedErrors) && parsedErrors.length) { + statusItems = parsedErrors.map(e => ({ + type: ENTITY_STATUS_CATALOG_PROCESSING_TYPE, + level: 'error', + message: `${e.name}: ${e.message}`, + error: e, + })); + } + } + // We opt to do this check here as we otherwise can't guarantee that it will be run after all processors + for (const annotation of [ANNOTATION_VIEW_URL, ANNOTATION_EDIT_URL]) { + const value = entity.metadata.annotations?.[annotation]; + if (typeof value === 'string' && scriptProtocolPattern.test(value)) { + entity.metadata.annotations![annotation] = + 'https://backstage.io/annotation-rejected-for-security-reasons'; + } + } + + // TODO: entityRef is lower case and should be uppercase in the final + // result + entity.relations = relationsResult + .filter(row => row.relationType /* exclude null row, if relevant */) + .map<EntityRelation>(row => ({ + type: row.relationType!, + targetRef: row.relationTarget!, + })); + if (statusItems.length) { + entity.status = { + ...entity.status, + items: [...(entity.status?.items ?? []), ...statusItems], + }; + } + + // If the output entity was actually not changed, just abort + const hash = generateStableHash(entity); + if (hash === previousHash) { + logger.debug(`Skipped stitching of ${entityRef}, no changes`); + return 'unchanged'; + } + + entity.metadata.uid = entityId; + if (!entity.metadata.etag) { + // If the original data source did not have its own etag handling, + // use the hash as a good-quality etag + entity.metadata.etag = hash; + } + + // This may throw if the entity is invalid, so we call it before + // the final_entities write, even though we may end up not needing + // to write the search index. + const searchEntries = buildEntitySearch(entityId, entity); + + const amountOfRowsChanged = await knex<DbFinalEntitiesRow>('final_entities') + .update({ + final_entity: JSON.stringify(entity), + hash, + last_updated_at: knex.fn.now(), + }) + .where('entity_id', entityId) + .where('stitch_ticket', stitchTicket) + .onConflict('entity_id') + .merge(['final_entity', 'hash', 'last_updated_at']); + + if (amountOfRowsChanged === 0) { + logger.debug(`Entity ${entityRef} is already stitched, skipping write.`); + return 'abandoned'; + } + + // TODO(freben): Search will probably need a similar safeguard against + // race conditions like the final_entities ticket handling above. + // Otherwise, it can be the case that: + // A writes the entity -> + // B writes the entity -> + // B writes search -> + // A writes search + await knex<DbSearchRow>('search').where({ entity_id: entityId }).delete(); + await knex.batchInsert('search', searchEntries, BATCH_SIZE); + + return 'changed'; +} diff --git a/plugins/catalog-backend/src/stitching/util.ts b/plugins/catalog-backend/src/database/operations/stitcher/util.ts similarity index 100% rename from plugins/catalog-backend/src/stitching/util.ts rename to plugins/catalog-backend/src/database/operations/stitcher/util.ts diff --git a/plugins/catalog-backend/src/database/operations/util/deleteOrphanedEntities.test.ts b/plugins/catalog-backend/src/database/operations/util/deleteOrphanedEntities.test.ts index 243b5db1b9..07ade1c4af 100644 --- a/plugins/catalog-backend/src/database/operations/util/deleteOrphanedEntities.test.ts +++ b/plugins/catalog-backend/src/database/operations/util/deleteOrphanedEntities.test.ts @@ -16,7 +16,7 @@ import { TestDatabaseId, TestDatabases } from '@backstage/backend-test-utils'; import { Knex } from 'knex'; -import * as uuid from 'uuid'; +import { StitchingStrategy } from '../../../stitching/types'; import { applyDatabaseMigrations } from '../../migrations'; import { DbFinalEntitiesRow, @@ -39,14 +39,14 @@ describe('deleteOrphanedEntities', () => { return knex; } - async function run(knex: Knex): Promise<number> { + async function run(knex: Knex, strategy: StitchingStrategy): Promise<number> { let result: number; await knex.transaction( async tx => { // We can't return here, as knex swallows the return type in case the // transaction is rolled back: // https://github.com/knex/knex/blob/e37aeaa31c8ef9c1b07d2e4d3ec6607e557d800d/lib/transaction.js#L136 - result = await deleteOrphanedEntities({ tx }); + result = await deleteOrphanedEntities({ knex: tx, strategy }); }, { // If we explicitly trigger a rollback, don't fail. @@ -58,9 +58,8 @@ describe('deleteOrphanedEntities', () => { async function insertEntity(knex: Knex, ...entityRefs: string[]) { for (const ref of entityRefs) { - const entityId = uuid.v4(); await knex<DbRefreshStateRow>('refresh_state').insert({ - entity_id: entityId, + entity_id: `id-${ref}`, entity_ref: ref, unprocessed_entity: '{}', processed_entity: '{}', @@ -70,7 +69,7 @@ describe('deleteOrphanedEntities', () => { result_hash: 'original', }); await knex<DbFinalEntitiesRow>('final_entities').insert({ - entity_id: entityId, + entity_id: `id-${ref}`, hash: 'original', stitch_ticket: '', }); @@ -120,7 +119,7 @@ describe('deleteOrphanedEntities', () => { } it.each(databases.eachSupportedId())( - 'works for some mixed paths, %p', + 'works for some mixed paths in immediate mode, %p', async databaseId => { /* In this graph, edges represent refresh state references, not entity relations: @@ -176,18 +175,31 @@ describe('deleteOrphanedEntities', () => { await insertRelation(knex, 'E1', 'E2'); await insertRelation(knex, 'E2', 'E3'); await insertRelation(knex, 'E10', 'E6'); - await expect(run(knex)).resolves.toEqual(5); + await insertRelation(knex, 'E7', 'E6'); + await expect(run(knex, { mode: 'immediate' })).resolves.toEqual(5); await expect(refreshState(knex)).resolves.toEqual([ { entity_ref: 'E1', result_hash: 'original' }, - { entity_ref: 'E2', result_hash: 'orphan-relation-deleted' }, - { entity_ref: 'E7', result_hash: 'original' }, + { + entity_ref: 'E2', + result_hash: 'force-stitching', + }, + { + entity_ref: 'E7', + result_hash: 'force-stitching', + }, { entity_ref: 'E8', result_hash: 'original' }, { entity_ref: 'E9', result_hash: 'original' }, ]); await expect(finalEntities(knex)).resolves.toEqual([ { entity_ref: 'E1', hash: 'original' }, - { entity_ref: 'E2', hash: 'orphan-relation-deleted' }, - { entity_ref: 'E7', hash: 'original' }, + { + entity_ref: 'E2', + hash: 'force-stitching', + }, + { + entity_ref: 'E7', + hash: 'force-stitching', + }, { entity_ref: 'E8', hash: 'original' }, { entity_ref: 'E9', hash: 'original' }, ]); diff --git a/plugins/catalog-backend/src/database/operations/util/deleteOrphanedEntities.ts b/plugins/catalog-backend/src/database/operations/util/deleteOrphanedEntities.ts index eeab85f59e..5e2e46cf89 100644 --- a/plugins/catalog-backend/src/database/operations/util/deleteOrphanedEntities.ts +++ b/plugins/catalog-backend/src/database/operations/util/deleteOrphanedEntities.ts @@ -16,7 +16,9 @@ import { Knex } from 'knex'; import uniq from 'lodash/uniq'; -import { DbFinalEntitiesRow, DbRefreshStateRow } from '../../tables'; +import { StitchingStrategy } from '../../../stitching/types'; +import { DbRefreshStateRow } from '../../tables'; +import { markForStitching } from '../stitcher/markForStitching'; /** * Finds and deletes all orphaned entities, i.e. entities that do not have any @@ -24,15 +26,16 @@ import { DbFinalEntitiesRow, DbRefreshStateRow } from '../../tables'; * that would otherwise become orphaned. */ export async function deleteOrphanedEntities(options: { - tx: Knex.Transaction | Knex; + knex: Knex.Transaction | Knex; + strategy: StitchingStrategy; }): Promise<number> { - const { tx } = options; + const { knex, strategy } = options; let total = 0; // Limit iterations for sanity for (let i = 0; i < 100; ++i) { - const candidates = await tx + const candidates = await knex .with('orphans', ['entity_id', 'entity_ref'], orphans => orphans .from('refresh_state') @@ -72,26 +75,17 @@ export async function deleteOrphanedEntities(options: { total += orphanIds.length; // Delete the orphans themselves - await tx + await knex .table<DbRefreshStateRow>('refresh_state') .delete() .whereIn('entity_id', orphanIds); - // Mark all of things that the orphans had relations to for processing and - // stitching - await tx - .table<DbFinalEntitiesRow>('final_entities') - .update({ - hash: 'orphan-relation-deleted', - }) - .whereIn('entity_id', orphanRelationIds); - await tx - .table<DbRefreshStateRow>('refresh_state') - .update({ - result_hash: 'orphan-relation-deleted', - next_update_at: tx.fn.now(), - }) - .whereIn('entity_id', orphanRelationIds); + // Mark all of the things that the orphans had relations to for stitching + await markForStitching({ + knex, + strategy, + entityIds: orphanRelationIds, + }); } return total; diff --git a/plugins/catalog-backend/src/database/tables.ts b/plugins/catalog-backend/src/database/tables.ts index e3f3efd1bb..a429dcde8d 100644 --- a/plugins/catalog-backend/src/database/tables.ts +++ b/plugins/catalog-backend/src/database/tables.ts @@ -29,17 +29,88 @@ export type DbLocationsRow = { target: string; }; +/** + * Represents the refresh_state table. + * + * @remarks + * + * Every unique entity ref emitted by a provider or a parent entity becomes a + * row in this table, even before processing has started on it. The actual final + * data, after processing and stitching completes, is instead in the + * final_entities table. + * + * Datetime columns are both string and Date, because different database engines + * return them in different forms on the client side. + */ export type DbRefreshStateRow = { + /** + * The unique ID of the entity. This is different to the entity ref, in that + * it gets regenerated randomly each time a row is added to the table, no + * matter what the original entity data was. + */ entity_id: string; + /** + * The entity string ref (on lowercase kind:namespace/name form) + */ entity_ref: string; + /** + * The JSON of the raw entity, as it was received from the entity provider. + */ unprocessed_entity: string; + /** + * A stable hash of the unprocessed entity, used to detect changed/unchanged + * data for a given entity over time. + */ unprocessed_hash?: string; + /** + * The JSON of the processed entity (if processing has run yet on it). + */ processed_entity?: string; + /** + * A stable hash of the processed entity AND all other emitted things during + * processing, such as relations. + */ result_hash?: string; + /** + * Per-entity cached data on JSON form. This is read and written by processors + * who wish to leverage this feature. + */ cache?: string; + /** + * The next point in time that this entity is due for processing. This + * continuously gets moved forward as items are picked up for processing. + */ next_update_at: string | Date; - last_discovery_at: string | Date; // remove? + /** + * The last time that this entity was emitted by somebody (the entity provider + * or a parent entity). + * + * @remarks + * + * Don't rely on this column more than at most as being loosely informative. + * Its semantics aren't fully settled yet. + */ + last_discovery_at: string | Date; + /** + * A JSON serialized array of errors (if any) encountered during processing. + */ errors?: string; + /** + * A conflict detection/resolution key for the entity. + * + * @remarks + * + * The exact value semantics differs, but may for example be a URL pointing to + * where the entity was sourced from. If a "competing" provider or parent + * entity tries to emit an entity that has the same entity ref but a different + * location key, a conflict is detected (you aren't allowed to "trample" over + * a previously existing entity). + * + * Some providers may choose to emit entities with no location key set at all. + * This is a signal that it's only loosely claimed, and that any other + * competing provider/parent is allowed to overwrite and claim it as theirs + * instead. + */ location_key?: string; }; diff --git a/plugins/catalog-backend/src/database/types.ts b/plugins/catalog-backend/src/database/types.ts index 592d5fe063..56e5f48f14 100644 --- a/plugins/catalog-backend/src/database/types.ts +++ b/plugins/catalog-backend/src/database/types.ts @@ -151,8 +151,6 @@ export interface ProcessingDatabase { txOpaque: Transaction, options: ListParentsOptions, ): Promise<ListParentsResult>; - - deleteOrphanedEntities(txOpaque: Transaction): Promise<number>; } /** diff --git a/plugins/catalog-backend/src/modules/core/LocationEntityProcessor.ts b/plugins/catalog-backend/src/modules/core/LocationEntityProcessor.ts index 1db74b3b56..7bfd7f33cd 100644 --- a/plugins/catalog-backend/src/modules/core/LocationEntityProcessor.ts +++ b/plugins/catalog-backend/src/modules/core/LocationEntityProcessor.ts @@ -42,12 +42,26 @@ export function toAbsoluteUrl( } } -/** @public */ +/** + * @public + * @deprecated This processor should no longer be used + */ export type LocationEntityProcessorOptions = { integrations: ScmIntegrationRegistry; }; -/** @public */ +/** + * Legacy processor, should not be used. + * + * @remarks + * + * In the old catalog architecture, this processor translated Location entities + * into URLs that should be fetched. This is no longer needed since the engine + * handles this internally. + * + * @public + * @deprecated This processor should no longer be used + */ export class LocationEntityProcessor implements CatalogProcessor { constructor(private readonly options: LocationEntityProcessorOptions) {} diff --git a/plugins/catalog-backend/src/processing/DefaultCatalogProcessingEngine.test.ts b/plugins/catalog-backend/src/processing/DefaultCatalogProcessingEngine.test.ts index 00235ef601..fba5e387a9 100644 --- a/plugins/catalog-backend/src/processing/DefaultCatalogProcessingEngine.test.ts +++ b/plugins/catalog-backend/src/processing/DefaultCatalogProcessingEngine.test.ts @@ -21,7 +21,7 @@ import waitForExpect from 'wait-for-expect'; import { DefaultProcessingDatabase } from '../database/DefaultProcessingDatabase'; import { DefaultCatalogProcessingEngine } from './DefaultCatalogProcessingEngine'; import { CatalogProcessingOrchestrator } from './types'; -import { Stitcher } from '../stitching/Stitcher'; +import { Stitcher } from '../stitching/types'; import { ConfigReader } from '@backstage/config'; describe('DefaultCatalogProcessingEngine', () => { @@ -66,6 +66,7 @@ describe('DefaultCatalogProcessingEngine', () => { config: new ConfigReader({}), logger: getVoidLogger(), processingDatabase: db, + knex: {} as any, orchestrator: orchestrator, stitcher: stitcher, createHash: () => hash, @@ -133,6 +134,7 @@ describe('DefaultCatalogProcessingEngine', () => { config: new ConfigReader({}), logger: getVoidLogger(), processingDatabase: db, + knex: {} as any, orchestrator: orchestrator, stitcher: stitcher, createHash: () => hash, @@ -216,6 +218,7 @@ describe('DefaultCatalogProcessingEngine', () => { config: new ConfigReader({}), logger: getVoidLogger(), processingDatabase: db, + knex: {} as any, orchestrator: orchestrator, stitcher: stitcher, createHash: () => hash, @@ -292,6 +295,7 @@ describe('DefaultCatalogProcessingEngine', () => { config: new ConfigReader({}), logger: getVoidLogger(), processingDatabase: db, + knex: {} as any, orchestrator: orchestrator, stitcher: stitcher, createHash: () => hash, @@ -350,6 +354,7 @@ describe('DefaultCatalogProcessingEngine', () => { config: new ConfigReader({}), logger: getVoidLogger(), processingDatabase: db, + knex: {} as any, orchestrator: orchestrator, stitcher: stitcher, createHash: () => hash, @@ -450,10 +455,10 @@ describe('DefaultCatalogProcessingEngine', () => { await waitForExpect(() => { expect(stitcher.stitch).toHaveBeenCalledTimes(2); }); - expect([...stitcher.stitch.mock.calls[0][0]]).toEqual( + expect([...stitcher.stitch.mock.calls[0][0].entityRefs!]).toEqual( expect.arrayContaining(['k:ns/me', 'k:ns/other1', 'k:ns/other2']), ); - expect([...stitcher.stitch.mock.calls[1][0]]).toEqual( + expect([...stitcher.stitch.mock.calls[1][0].entityRefs!]).toEqual( expect.arrayContaining(['k:ns/me', 'k:ns/other1', 'k:ns/other3']), ); await engine.stop(); @@ -464,6 +469,7 @@ describe('DefaultCatalogProcessingEngine', () => { config: new ConfigReader({}), logger: getVoidLogger(), processingDatabase: db, + knex: {} as any, orchestrator: orchestrator, stitcher: stitcher, createHash: () => hash, @@ -535,7 +541,7 @@ describe('DefaultCatalogProcessingEngine', () => { await waitForExpect(() => { expect(stitcher.stitch).toHaveBeenCalledTimes(1); }); - expect([...stitcher.stitch.mock.calls[0][0]]).toEqual( + expect([...stitcher.stitch.mock.calls[0][0].entityRefs!]).toEqual( expect.arrayContaining(['k:ns/me']), ); await engine.stop(); @@ -546,6 +552,7 @@ describe('DefaultCatalogProcessingEngine', () => { config: new ConfigReader({}), logger: getVoidLogger(), processingDatabase: db, + knex: {} as any, orchestrator: orchestrator, stitcher: stitcher, createHash: () => hash, @@ -622,7 +629,7 @@ describe('DefaultCatalogProcessingEngine', () => { await waitForExpect(() => { expect(stitcher.stitch).toHaveBeenCalledTimes(1); }); - expect([...stitcher.stitch.mock.calls[0][0]]).toEqual( + expect([...stitcher.stitch.mock.calls[0][0].entityRefs!]).toEqual( expect.arrayContaining(['k:ns/me', 'k:ns/other2']), ); await engine.stop(); @@ -633,6 +640,7 @@ describe('DefaultCatalogProcessingEngine', () => { config: new ConfigReader({}), logger: getVoidLogger(), processingDatabase: db, + knex: {} as any, orchestrator: orchestrator, stitcher: stitcher, createHash: () => hash, @@ -699,7 +707,7 @@ describe('DefaultCatalogProcessingEngine', () => { await waitForExpect(() => { expect(stitcher.stitch).toHaveBeenCalledTimes(1); }); - expect([...stitcher.stitch.mock.calls[0][0]]).toEqual( + expect([...stitcher.stitch.mock.calls[0][0].entityRefs!]).toEqual( expect.arrayContaining(['k:ns/me', 'k:ns/other2']), ); await engine.stop(); diff --git a/plugins/catalog-backend/src/processing/DefaultCatalogProcessingEngine.ts b/plugins/catalog-backend/src/processing/DefaultCatalogProcessingEngine.ts index bed1fe6f50..72f92b9b40 100644 --- a/plugins/catalog-backend/src/processing/DefaultCatalogProcessingEngine.ts +++ b/plugins/catalog-backend/src/processing/DefaultCatalogProcessingEngine.ts @@ -22,16 +22,13 @@ import { import { assertError, serializeError, stringifyError } from '@backstage/errors'; import { Hash } from 'crypto'; import stableStringify from 'fast-json-stable-stringify'; +import { Knex } from 'knex'; import { Logger } from 'winston'; import { metrics, trace } from '@opentelemetry/api'; import { ProcessingDatabase, RefreshStateItem } from '../database/types'; import { createCounterMetric, createSummaryMetric } from '../util/metrics'; -import { - CatalogProcessingEngine, - CatalogProcessingOrchestrator, - EntityProcessingResult, -} from './types'; -import { Stitcher } from '../stitching/Stitcher'; +import { CatalogProcessingOrchestrator, EntityProcessingResult } from './types'; +import { Stitcher } from '../stitching/types'; import { startTaskPipeline } from './TaskPipeline'; import { PluginTaskScheduler } from '@backstage/backend-tasks'; import { Config } from '@backstage/config'; @@ -40,6 +37,7 @@ import { TRACER_ID, withActiveSpan, } from '../util/opentelemetry'; +import { deleteOrphanedEntities } from '../database/operations/util/deleteOrphanedEntities'; const CACHE_TTL = 5; @@ -47,10 +45,17 @@ const tracer = trace.getTracer(TRACER_ID); export type ProgressTracker = ReturnType<typeof progressTracker>; -export class DefaultCatalogProcessingEngine implements CatalogProcessingEngine { +// NOTE(freben): Perhaps surprisingly, this class does not implement the +// CatalogProcessingEngine type. That type is externally visible and its name is +// the way it is for historic reasons. This class has no particular reason to +// implement that precise interface; nowadays there are several different +// engines "hiding" behind the CatalogProcessingEngine interface, of which this +// is just one. +export class DefaultCatalogProcessingEngine { private readonly config: Config; private readonly scheduler?: PluginTaskScheduler; private readonly logger: Logger; + private readonly knex: Knex; private readonly processingDatabase: ProcessingDatabase; private readonly orchestrator: CatalogProcessingOrchestrator; private readonly stitcher: Stitcher; @@ -69,6 +74,7 @@ export class DefaultCatalogProcessingEngine implements CatalogProcessingEngine { config: Config; scheduler?: PluginTaskScheduler; logger: Logger; + knex: Knex; processingDatabase: ProcessingDatabase; orchestrator: CatalogProcessingOrchestrator; stitcher: Stitcher; @@ -84,6 +90,7 @@ export class DefaultCatalogProcessingEngine implements CatalogProcessingEngine { this.config = options.config; this.scheduler = options.scheduler; this.logger = options.logger; + this.knex = options.knex; this.processingDatabase = options.processingDatabase; this.orchestrator = options.orchestrator; this.stitcher = options.stitcher; @@ -255,9 +262,11 @@ export class DefaultCatalogProcessingEngine implements CatalogProcessingEngine { resultHash, }); }); - await this.stitcher.stitch( - new Set([stringifyEntityRef(unprocessedEntity)]), - ); + + await this.stitcher.stitch({ + entityRefs: [stringifyEntityRef(unprocessedEntity)], + }); + track.markSuccessfulWithErrors(); return; } @@ -305,9 +314,11 @@ export class DefaultCatalogProcessingEngine implements CatalogProcessingEngine { } }); - await this.stitcher.stitch(setOfThingsToStitch); + await this.stitcher.stitch({ + entityRefs: setOfThingsToStitch, + }); - track.markSuccessfulWithChanges(setOfThingsToStitch.size); + track.markSuccessfulWithChanges(); } catch (error) { assertError(error); track.markFailed(error); @@ -318,20 +329,21 @@ export class DefaultCatalogProcessingEngine implements CatalogProcessingEngine { } private startOrphanCleanup(): () => void { - const strategy = + const orphanStrategy = this.config.getOptionalString('catalog.orphanStrategy') ?? 'keep'; - if (strategy !== 'delete') { + if (orphanStrategy !== 'delete') { return () => {}; } const runOnce = async () => { try { - await this.processingDatabase.transaction(async tx => { - const n = await this.processingDatabase.deleteOrphanedEntities(tx); - if (n > 0) { - this.logger.info(`Deleted ${n} orphaned entities`); - } + const n = await deleteOrphanedEntities({ + knex: this.knex, + strategy: { mode: 'immediate' }, }); + if (n > 0) { + this.logger.info(`Deleted ${n} orphaned entities`); + } } catch (error) { this.logger.warn(`Failed to delete orphaned entities`, error); } @@ -363,10 +375,6 @@ export class DefaultCatalogProcessingEngine implements CatalogProcessingEngine { // Helps wrap the timing and logging behaviors function progressTracker() { // prom-client metrics are deprecated in favour of OpenTelemetry metrics. - const promStitchedEntities = createCounterMetric({ - name: 'catalog_stitched_entities_count', - help: 'Amount of entities stitched. DEPRECATED, use OpenTelemetry metrics instead', - }); const promProcessedEntities = createCounterMetric({ name: 'catalog_processed_entities_count', help: 'Amount of entities processed, DEPRECATED, use OpenTelemetry metrics instead', @@ -388,11 +396,6 @@ function progressTracker() { }); const meter = metrics.getMeter('default'); - const stitchedEntities = meter.createCounter( - 'catalog.stitched.entities.count', - { description: 'Amount of entities stitched' }, - ); - const processedEntities = meter.createCounter( 'catalog.processed.entities.count', { description: 'Amount of entities processed' }, @@ -464,13 +467,11 @@ function progressTracker() { processedEntities.add(1, { result: 'errors' }); } - function markSuccessfulWithChanges(stitchedCount: number) { + function markSuccessfulWithChanges() { endOverallTimer({ result: 'changed' }); - promStitchedEntities.inc(stitchedCount); promProcessedEntities.inc({ result: 'changed' }, 1); processingDuration.record(endTime(), { result: 'changed' }); - stitchedEntities.add(stitchedCount); processedEntities.add(1, { result: 'changed' }); } diff --git a/plugins/catalog-backend/src/processing/types.ts b/plugins/catalog-backend/src/processing/types.ts index c0d0e5db0d..002747d4c4 100644 --- a/plugins/catalog-backend/src/processing/types.ts +++ b/plugins/catalog-backend/src/processing/types.ts @@ -64,8 +64,8 @@ export interface CatalogProcessingOrchestrator { } /** - * Represents the engine that drives the processing loops. Some backend - * instances may choose to not call start, if they focus only on API + * Represents the engine that drives the processing and stitching loops. Some + * backend instances may choose to not call start, if they focus only on API * interactions. * * @public diff --git a/plugins/catalog-backend/src/service/CatalogBuilder.ts b/plugins/catalog-backend/src/service/CatalogBuilder.ts index 531bb91dd2..c12178e888 100644 --- a/plugins/catalog-backend/src/service/CatalogBuilder.ts +++ b/plugins/catalog-backend/src/service/CatalogBuilder.ts @@ -65,7 +65,7 @@ import { DefaultCatalogProcessingEngine } from '../processing/DefaultCatalogProc import { DefaultLocationService } from './DefaultLocationService'; import { DefaultEntitiesCatalog } from './DefaultEntitiesCatalog'; import { DefaultCatalogProcessingOrchestrator } from '../processing/DefaultCatalogProcessingOrchestrator'; -import { Stitcher } from '../stitching/Stitcher'; +import { DefaultStitcher } from '../stitching/DefaultStitcher'; import { createRandomProcessingInterval, ProcessingIntervalFunction, @@ -449,6 +449,11 @@ export class CatalogBuilder { await applyDatabaseMigrations(dbClient); } + const stitcher = DefaultStitcher.fromConfig(config, { + knex: dbClient, + logger, + }); + const processingDatabase = new DefaultProcessingDatabase({ database: dbClient, logger, @@ -474,7 +479,6 @@ export class CatalogBuilder { policy, legacySingleProcessorValidation: this.legacySingleProcessorValidation, }); - const stitcher = new Stitcher(dbClient, logger); const unauthorizedEntitiesCatalog = new DefaultEntitiesCatalog({ database: dbClient, logger, @@ -535,6 +539,7 @@ export class CatalogBuilder { config, scheduler, logger, + knex: dbClient, processingDatabase, orchestrator, stitcher, @@ -572,7 +577,16 @@ export class CatalogBuilder { await connectEntityProviders(providerDatabase, entityProviders); return { - processingEngine, + processingEngine: { + async start() { + await processingEngine.start(); + await stitcher.start(); + }, + async stop() { + await processingEngine.stop(); + await stitcher.stop(); + }, + }, router, }; } diff --git a/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.test.ts b/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.test.ts index 4f011813e6..fde3408c4b 100644 --- a/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.test.ts +++ b/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.test.ts @@ -30,10 +30,10 @@ import { DbRefreshStateRow, DbSearchRow, } from '../database/tables'; -import { Stitcher } from '../stitching/Stitcher'; -import { buildEntitySearch } from '../stitching/buildEntitySearch'; +import { Stitcher } from '../stitching/types'; import { DefaultEntitiesCatalog } from './DefaultEntitiesCatalog'; import { EntitiesRequest } from '../catalog/types'; +import { buildEntitySearch } from '../database/operations/stitcher/buildEntitySearch'; jest.setTimeout(60_000); @@ -1684,9 +1684,9 @@ describe('DefaultEntitiesCatalog', () => { { entity_ref: 'k:default/unrelated1', result_hash: 'not-changed' }, { entity_ref: 'k:default/unrelated2', result_hash: 'not-changed' }, ]); - expect(stitch).toHaveBeenCalledWith( - new Set(['k:default/unrelated1', 'k:default/unrelated2']), - ); + expect(stitch).toHaveBeenCalledWith({ + entityRefs: new Set(['k:default/unrelated1', 'k:default/unrelated2']), + }); }, ); }); diff --git a/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.ts b/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.ts index c328c83823..24f0432419 100644 --- a/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.ts +++ b/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.ts @@ -49,8 +49,7 @@ import { DbRelationsRow, DbSearchRow, } from '../database/tables'; - -import { Stitcher } from '../stitching/Stitcher'; +import { Stitcher } from '../stitching/types'; import { isQueryEntitiesCursorRequest, @@ -606,7 +605,9 @@ export class DefaultEntitiesCatalog implements EntitiesCatalog { .where('entity_id', uid) .delete(); - await this.stitcher.stitch(new Set(relationPeers.map(p => p.ref))); + await this.stitcher.stitch({ + entityRefs: new Set(relationPeers.map(p => p.ref)), + }); } async entityAncestry(rootRef: string): Promise<EntityAncestryResponse> { diff --git a/plugins/catalog-backend/src/service/DefaultRefreshService.test.ts b/plugins/catalog-backend/src/service/DefaultRefreshService.test.ts index 76284ebbfd..5b29bb34d5 100644 --- a/plugins/catalog-backend/src/service/DefaultRefreshService.test.ts +++ b/plugins/catalog-backend/src/service/DefaultRefreshService.test.ts @@ -31,9 +31,9 @@ import { import { ProcessingDatabase } from '../database/types'; import { DefaultCatalogProcessingEngine } from '../processing/DefaultCatalogProcessingEngine'; import { EntityProcessingRequest } from '../processing/types'; -import { Stitcher } from '../stitching/Stitcher'; import { DefaultRefreshService } from './DefaultRefreshService'; import { ConfigReader } from '@backstage/config'; +import { DefaultStitcher } from '../stitching/DefaultStitcher'; jest.setTimeout(60_000); @@ -109,10 +109,16 @@ describe('DefaultRefreshService', () => { } } + const stitcher = DefaultStitcher.fromConfig(new ConfigReader({}), { + knex, + logger: defaultLogger, + }); const engine = new DefaultCatalogProcessingEngine({ config: new ConfigReader({}), logger: defaultLogger, processingDatabase: db, + knex: knex, + stitcher: stitcher, orchestrator: { async process(request: EntityProcessingRequest) { const entityRef = stringifyEntityRef(request.entity); @@ -151,7 +157,6 @@ describe('DefaultRefreshService', () => { }; }, }, - stitcher: new Stitcher(knex, defaultLogger), createHash: () => createHash('sha1'), pollingIntervalMs: 50, }); diff --git a/plugins/catalog-backend/src/service/request/parseQueryEntitiesParams.ts b/plugins/catalog-backend/src/service/request/parseQueryEntitiesParams.ts index b1d5e8dd1f..33033c66f3 100644 --- a/plugins/catalog-backend/src/service/request/parseQueryEntitiesParams.ts +++ b/plugins/catalog-backend/src/service/request/parseQueryEntitiesParams.ts @@ -24,10 +24,10 @@ import { parseEntityFilterParams } from './parseEntityFilterParams'; import { parseEntityOrderFieldParams } from './parseEntityOrderFieldParams'; import { parseEntityTransformParams } from './parseEntityTransformParams'; import { spec } from '../../schema/openapi.generated'; -import { internal } from '@backstage/backend-openapi-utils'; +import { QueryParameters } from '@backstage/backend-openapi-utils'; export function parseQueryEntitiesParams( - params: internal.QuerySchema<typeof spec, '/entities/by-query', 'get'>, + params: QueryParameters<typeof spec, '/entities/by-query', 'get'>, ): Omit<QueryEntitiesRequest, 'authorizationToken' | 'limit'> { const fields = parseEntityTransformParams(params); diff --git a/plugins/catalog-backend/src/stitching/Stitcher.test.ts b/plugins/catalog-backend/src/stitching/DefaultStitcher.test.ts similarity index 95% rename from plugins/catalog-backend/src/stitching/Stitcher.test.ts rename to plugins/catalog-backend/src/stitching/DefaultStitcher.test.ts index 1efcb01a3c..5b33fc424c 100644 --- a/plugins/catalog-backend/src/stitching/Stitcher.test.ts +++ b/plugins/catalog-backend/src/stitching/DefaultStitcher.test.ts @@ -25,7 +25,7 @@ import { DbRelationsRow, DbSearchRow, } from '../database/tables'; -import { Stitcher } from './Stitcher'; +import { DefaultStitcher } from './DefaultStitcher'; jest.setTimeout(60_000); @@ -41,7 +41,11 @@ describe('Stitcher', () => { const db = await databases.init(databaseId); await applyDatabaseMigrations(db); - const stitcher = new Stitcher(db, logger); + const stitcher = new DefaultStitcher({ + knex: db, + logger, + strategy: { mode: 'immediate' }, + }); let entities: DbFinalEntitiesRow[]; let entity: Entity; @@ -85,7 +89,7 @@ describe('Stitcher', () => { }, ]); - await stitcher.stitch(new Set(['k:ns/n'])); + await stitcher.stitch({ entityRefs: ['k:ns/n'] }); entities = await db<DbFinalEntitiesRow>('final_entities'); @@ -165,7 +169,7 @@ describe('Stitcher', () => { ); // Re-stitch without any changes - await stitcher.stitch(new Set(['k:ns/n'])); + await stitcher.stitch({ entityRefs: ['k:ns/n'] }); entities = await db<DbFinalEntitiesRow>('final_entities'); expect(entities.length).toBe(1); @@ -183,7 +187,7 @@ describe('Stitcher', () => { }, ]); - await stitcher.stitch(new Set(['k:ns/n'])); + await stitcher.stitch({ entityRefs: ['k:ns/n'] }); entities = await db<DbFinalEntitiesRow>('final_entities'); diff --git a/plugins/catalog-backend/src/stitching/DefaultStitcher.ts b/plugins/catalog-backend/src/stitching/DefaultStitcher.ts new file mode 100644 index 0000000000..095d80ad83 --- /dev/null +++ b/plugins/catalog-backend/src/stitching/DefaultStitcher.ts @@ -0,0 +1,124 @@ +/* + * 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 { Knex } from 'knex'; +import splitToChunks from 'lodash/chunk'; +import { DateTime } from 'luxon'; +import { Logger } from 'winston'; +import { performStitching } from '../database/operations/stitcher/performStitching'; +import { DbRefreshStateRow } from '../database/tables'; +import { progressTracker } from './progressTracker'; +import { Stitcher, StitchingStrategy } from './types'; + +type StitchProgressTracker = ReturnType<typeof progressTracker>; + +/** + * Performs the act of stitching - to take all of the various outputs from the + * ingestion process, and stitching them together into the final entity JSON + * shape. + */ +export class DefaultStitcher implements Stitcher { + private readonly knex: Knex; + private readonly logger: Logger; + private readonly strategy: StitchingStrategy; + private readonly tracker: StitchProgressTracker; + + static fromConfig( + _config: Config, + options: { + knex: Knex; + logger: Logger; + }, + ): DefaultStitcher { + return new DefaultStitcher({ + knex: options.knex, + logger: options.logger, + strategy: { mode: 'immediate' }, + }); + } + + constructor(options: { + knex: Knex; + logger: Logger; + strategy: StitchingStrategy; + }) { + this.knex = options.knex; + this.logger = options.logger; + this.strategy = options.strategy; + this.tracker = progressTracker(options.knex, options.logger); + } + + async stitch(options: { + entityRefs?: Iterable<string>; + entityIds?: Iterable<string>; + }) { + const { entityRefs, entityIds } = options; + + if (entityRefs) { + for (const entityRef of entityRefs) { + await this.#stitchOne({ entityRef }); + } + } + + if (entityIds) { + const chunks = splitToChunks( + Array.isArray(entityIds) ? entityIds : [...entityIds], + 100, + ); + for (const chunk of chunks) { + const rows = await this.knex<DbRefreshStateRow>('refresh_state') + .select('entity_ref') + .whereIn('entity_id', chunk); + for (const row of rows) { + await this.#stitchOne({ entityRef: row.entity_ref }); + } + } + } + } + + async start() { + // Only called immediately for now + } + + async stop() { + // Only called immediately for now + } + + async #stitchOne(options: { + entityRef: string; + stitchTicket?: string; + stitchRequestedAt?: DateTime; + }) { + const track = this.tracker.stitchStart({ + entityRef: options.entityRef, + stitchRequestedAt: options.stitchRequestedAt, + }); + + try { + const result = await performStitching({ + knex: this.knex, + logger: this.logger, + strategy: this.strategy, + entityRef: options.entityRef, + stitchTicket: options.stitchTicket, + }); + track.markComplete(result); + } catch (error) { + track.markFailed(error); + } + } +} diff --git a/plugins/catalog-backend/src/stitching/Stitcher.ts b/plugins/catalog-backend/src/stitching/Stitcher.ts deleted file mode 100644 index 38d0fd263f..0000000000 --- a/plugins/catalog-backend/src/stitching/Stitcher.ts +++ /dev/null @@ -1,250 +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 { ENTITY_STATUS_CATALOG_PROCESSING_TYPE } from '@backstage/catalog-client'; -import { AlphaEntity, EntityStatusItem } from '@backstage/catalog-model/alpha'; -import { - ANNOTATION_EDIT_URL, - ANNOTATION_VIEW_URL, - EntityRelation, -} from '@backstage/catalog-model'; -import { SerializedError, stringifyError } from '@backstage/errors'; -import { Knex } from 'knex'; -import { v4 as uuid } from 'uuid'; -import { Logger } from 'winston'; -import { - DbFinalEntitiesRow, - DbRefreshStateRow, - DbSearchRow, -} from '../database/tables'; -import { buildEntitySearch } from './buildEntitySearch'; -import { BATCH_SIZE, generateStableHash } from './util'; - -// See https://github.com/facebook/react/blob/f0cf832e1d0c8544c36aa8b310960885a11a847c/packages/react-dom-bindings/src/shared/sanitizeURL.js -const scriptProtocolPattern = - // eslint-disable-next-line no-control-regex - /^[\u0000-\u001F ]*j[\r\n\t]*a[\r\n\t]*v[\r\n\t]*a[\r\n\t]*s[\r\n\t]*c[\r\n\t]*r[\r\n\t]*i[\r\n\t]*p[\r\n\t]*t[\r\n\t]*\:/i; - -/** - * Performs the act of stitching - to take all of the various outputs from the - * ingestion process, and stitching them together into the final entity JSON - * shape. - */ -export class Stitcher { - constructor( - private readonly database: Knex, - private readonly logger: Logger, - ) {} - - async stitch(entityRefs: Set<string>) { - for (const entityRef of entityRefs) { - try { - await this.stitchOne(entityRef); - } catch (error) { - this.logger.error( - `Failed to stitch ${entityRef}, ${stringifyError(error)}`, - ); - } - } - } - - private async stitchOne(entityRef: string): Promise<void> { - const entityResult = await this.database<DbRefreshStateRow>('refresh_state') - .where({ entity_ref: entityRef }) - .limit(1) - .select('entity_id'); - if (!entityResult.length) { - // Entity does no exist in refresh state table, no stitching required. - return; - } - - // Insert stitching ticket that will be compared before inserting the final entity. - const ticket = uuid(); - await this.database<DbFinalEntitiesRow>('final_entities') - .insert({ - entity_id: entityResult[0].entity_id, - hash: '', - stitch_ticket: ticket, - }) - .onConflict('entity_id') - .merge(['stitch_ticket']); - - // Selecting from refresh_state and final_entities should yield exactly - // one row (except in abnormal cases where the stitch was invoked for - // something that didn't exist at all, in which case it's zero rows). - // The join with the temporary incoming_references still gives one row. - const [processedResult, relationsResult] = await Promise.all([ - this.database - .with('incoming_references', function incomingReferences(builder) { - return builder - .from('refresh_state_references') - .where({ target_entity_ref: entityRef }) - .count({ count: '*' }); - }) - .select({ - entityId: 'refresh_state.entity_id', - processedEntity: 'refresh_state.processed_entity', - errors: 'refresh_state.errors', - incomingReferenceCount: 'incoming_references.count', - previousHash: 'final_entities.hash', - }) - .from('refresh_state') - .where({ 'refresh_state.entity_ref': entityRef }) - .crossJoin(this.database.raw('incoming_references')) - .leftOuterJoin('final_entities', { - 'final_entities.entity_id': 'refresh_state.entity_id', - }), - this.database - .distinct({ - relationType: 'type', - relationTarget: 'target_entity_ref', - }) - .from('relations') - .where({ source_entity_ref: entityRef }) - .orderBy('relationType', 'asc') - .orderBy('relationTarget', 'asc'), - ]); - - // If there were no rows returned, it would mean that there was no - // matching row even in the refresh_state. This can happen for example - // if we emit a relation to something that hasn't been ingested yet. - // It's safe to ignore this stitch attempt in that case. - if (!processedResult.length) { - this.logger.error( - `Unable to stitch ${entityRef}, item does not exist in refresh state table`, - ); - return; - } - - const { - entityId, - processedEntity, - errors, - incomingReferenceCount, - previousHash, - } = processedResult[0]; - - // If there was no processed entity in place, the target hasn't been - // through the processing steps yet. It's safe to ignore this stitch - // attempt in that case, since another stitch will be triggered when - // that processing has finished. - if (!processedEntity) { - this.logger.debug( - `Unable to stitch ${entityRef}, the entity has not yet been processed`, - ); - return; - } - - // Grab the processed entity and stitch all of the relevant data into - // it - const entity = JSON.parse(processedEntity) as AlphaEntity; - const isOrphan = Number(incomingReferenceCount) === 0; - let statusItems: EntityStatusItem[] = []; - - if (isOrphan) { - this.logger.debug(`${entityRef} is an orphan`); - entity.metadata.annotations = { - ...entity.metadata.annotations, - ['backstage.io/orphan']: 'true', - }; - } - if (errors) { - const parsedErrors = JSON.parse(errors) as SerializedError[]; - if (Array.isArray(parsedErrors) && parsedErrors.length) { - statusItems = parsedErrors.map(e => ({ - type: ENTITY_STATUS_CATALOG_PROCESSING_TYPE, - level: 'error', - message: `${e.name}: ${e.message}`, - error: e, - })); - } - } - // We opt to do this check here as we otherwise can't guarantee that it will be run after all processors - for (const annotation of [ANNOTATION_VIEW_URL, ANNOTATION_EDIT_URL]) { - const value = entity.metadata.annotations?.[annotation]; - if (typeof value === 'string' && scriptProtocolPattern.test(value)) { - entity.metadata.annotations![annotation] = - 'https://backstage.io/annotation-rejected-for-security-reasons'; - } - } - - // TODO: entityRef is lower case and should be uppercase in the final - // result - entity.relations = relationsResult - .filter(row => row.relationType /* exclude null row, if relevant */) - .map<EntityRelation>(row => ({ - type: row.relationType!, - targetRef: row.relationTarget!, - })); - if (statusItems.length) { - entity.status = { - ...entity.status, - items: [...(entity.status?.items ?? []), ...statusItems], - }; - } - - // If the output entity was actually not changed, just abort - const hash = generateStableHash(entity); - if (hash === previousHash) { - this.logger.debug(`Skipped stitching of ${entityRef}, no changes`); - return; - } - - entity.metadata.uid = entityId; - if (!entity.metadata.etag) { - // If the original data source did not have its own etag handling, - // use the hash as a good-quality etag - entity.metadata.etag = hash; - } - - // This may throw if the entity is invalid, so we call it before - // the final_entities write, even though we may end up not needing - // to write the search index. - const searchEntries = buildEntitySearch(entityId, entity); - - const amountOfRowsChanged = await this.database<DbFinalEntitiesRow>( - 'final_entities', - ) - .update({ - final_entity: JSON.stringify(entity), - hash, - last_updated_at: this.database.fn.now(), - }) - .where('entity_id', entityId) - .where('stitch_ticket', ticket) - .onConflict('entity_id') - .merge(['final_entity', 'hash', 'last_updated_at']); - - if (amountOfRowsChanged === 0) { - this.logger.debug( - `Entity ${entityRef} is already processed, skipping write.`, - ); - return; - } - - // TODO(freben): Search will probably need a similar safeguard against - // race conditions like the final_entities ticket handling above. - // Otherwise, it can be the case that: - // A writes the entity -> - // B writes the entity -> - // B writes search -> - // A writes search - await this.database<DbSearchRow>('search') - .where({ entity_id: entityId }) - .delete(); - await this.database.batchInsert('search', searchEntries, BATCH_SIZE); - } -} diff --git a/plugins/catalog-backend/src/stitching/progressTracker.ts b/plugins/catalog-backend/src/stitching/progressTracker.ts new file mode 100644 index 0000000000..e8e08dbc54 --- /dev/null +++ b/plugins/catalog-backend/src/stitching/progressTracker.ts @@ -0,0 +1,84 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { stringifyError } from '@backstage/errors'; +import { metrics } from '@opentelemetry/api'; +import { Knex } from 'knex'; +import { DateTime } from 'luxon'; +import { Logger } from 'winston'; +import { createCounterMetric } from '../util/metrics'; + +// Helps wrap the timing and logging behaviors +export function progressTracker(_knex: Knex, logger: Logger) { + // prom-client metrics are deprecated in favour of OpenTelemetry metrics. + const promStitchedEntities = createCounterMetric({ + name: 'catalog_stitched_entities_count', + help: 'Amount of entities stitched. DEPRECATED, use OpenTelemetry metrics instead', + }); + + const meter = metrics.getMeter('default'); + + const stitchedEntities = meter.createCounter( + 'catalog.stitched.entities.count', + { + description: 'Amount of entities stitched', + }, + ); + + const stitchingDuration = meter.createHistogram( + 'catalog.stitching.duration', + { + description: 'Time spent executing the full stitching flow', + unit: 'seconds', + }, + ); + + function stitchStart(item: { + entityRef: string; + stitchRequestedAt?: DateTime; + }) { + logger.debug(`Stitching ${item.entityRef}`); + + const startTime = process.hrtime(); + + function endTime() { + const delta = process.hrtime(startTime); + return delta[0] + delta[1] / 1e9; + } + + function markComplete(result: string) { + promStitchedEntities.inc(1); + stitchedEntities.add(1, { result }); + stitchingDuration.record(endTime(), { result }); + } + + function markFailed(error: Error) { + promStitchedEntities.inc(1); + stitchedEntities.add(1, { result: 'error' }); + stitchingDuration.record(endTime(), { result: 'error' }); + logger.error( + `Failed to stitch ${item.entityRef}, ${stringifyError(error)}`, + ); + } + + return { + markComplete, + markFailed, + }; + } + + return { stitchStart }; +} diff --git a/plugins/catalog-backend/src/stitching/types.ts b/plugins/catalog-backend/src/stitching/types.ts new file mode 100644 index 0000000000..5f32a85b1f --- /dev/null +++ b/plugins/catalog-backend/src/stitching/types.ts @@ -0,0 +1,40 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Performs the act of stitching - to take all of the various outputs from the + * ingestion process, and stitching them together into the final entity JSON + * shape. + */ +export interface Stitcher { + stitch(options: { + entityRefs?: Iterable<string>; + entityIds?: Iterable<string>; + }): Promise<void>; +} + +/** + * The strategies supported by the stitching process, in terms of when to + * perform stitching. + * + * @remarks + * + * In immediate mode, stitching happens "in-band" (blocking) immediately when + * each processing task finishes. + */ +export type StitchingStrategy = { + mode: 'immediate'; +}; diff --git a/plugins/catalog-backend/src/tests/integration.test.ts b/plugins/catalog-backend/src/tests/integration.test.ts index e7f983f51f..8aeb95f49b 100644 --- a/plugins/catalog-backend/src/tests/integration.test.ts +++ b/plugins/catalog-backend/src/tests/integration.test.ts @@ -53,7 +53,7 @@ import { CatalogProcessingEngine } from '../processing/types'; import { DefaultEntitiesCatalog } from '../service/DefaultEntitiesCatalog'; import { DefaultRefreshService } from '../service/DefaultRefreshService'; import { RefreshOptions, RefreshService } from '../service/types'; -import { Stitcher } from '../stitching/Stitcher'; +import { DefaultStitcher } from '../stitching/DefaultStitcher'; const voidLogger = getVoidLogger(); @@ -268,7 +268,7 @@ class TestHarness { policy: EntityPolicies.allOf([]), legacySingleProcessorValidation: false, }); - const stitcher = new Stitcher(db, logger); + const stitcher = DefaultStitcher.fromConfig(config, { knex: db, logger }); const catalog = new DefaultEntitiesCatalog({ database: db, logger, @@ -282,6 +282,7 @@ class TestHarness { config: new ConfigReader({}), logger, processingDatabase, + knex: db, orchestrator, stitcher, createHash: () => createHash('sha1'), @@ -300,7 +301,16 @@ class TestHarness { return new TestHarness( catalog, - engine, + { + async start() { + await engine.start(); + await stitcher.start(); + }, + async stop() { + await engine.stop(); + await stitcher.stop(); + }, + }, refresh, provider, proxyProgressTracker, diff --git a/plugins/catalog-backend/src/tests/performance/stitchingPerformance.test.ts b/plugins/catalog-backend/src/tests/performance/stitchingPerformance.test.ts index e60c0a33d6..c1a869f9ad 100644 --- a/plugins/catalog-backend/src/tests/performance/stitchingPerformance.test.ts +++ b/plugins/catalog-backend/src/tests/performance/stitchingPerformance.test.ts @@ -181,6 +181,7 @@ describePerformanceTest('stitchingPerformance', () => { const backend = await startTestBackend({ features: [ import('@backstage/plugin-catalog-backend/alpha'), + staticDatabase(knex), createBackendModule({ moduleId: 'syntheticLoadEntities', pluginId: 'catalog', @@ -200,7 +201,6 @@ describePerformanceTest('stitchingPerformance', () => { }); }, }), - staticDatabase(knex), ], }); diff --git a/plugins/catalog-customized/CHANGELOG.md b/plugins/catalog-customized/CHANGELOG.md deleted file mode 100644 index ac858f652d..0000000000 --- a/plugins/catalog-customized/CHANGELOG.md +++ /dev/null @@ -1,457 +0,0 @@ -# @internal/plugin-catalog-customized - -## 0.0.14 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog@1.13.0 - - @backstage/plugin-catalog-react@1.8.4 - -## 0.0.14-next.3 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog@1.13.0-next.3 - - @backstage/plugin-catalog-react@1.8.4-next.3 - -## 0.0.14-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog@1.13.0-next.2 - - @backstage/plugin-catalog-react@1.8.4-next.2 - -## 0.0.14-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-react@1.8.4-next.1 - - @backstage/plugin-catalog@1.12.5-next.1 - -## 0.0.14-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog@1.12.4-next.0 - - @backstage/plugin-catalog-react@1.8.3-next.0 - -## 0.0.13 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog@1.12.1 - - @backstage/plugin-catalog-react@1.8.1 - -## 0.0.13-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-react@1.8.1-next.1 - - @backstage/plugin-catalog@1.12.1-next.2 - -## 0.0.13-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog@1.12.1-next.1 - - @backstage/plugin-catalog-react@1.8.1-next.0 - -## 0.0.13-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog@1.12.1-next.0 - - @backstage/plugin-catalog-react@1.8.1-next.0 - -## 0.0.12 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-react@1.8.0 - - @backstage/plugin-catalog@1.12.0 - -## 0.0.12-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-react@1.8.0-next.2 - - @backstage/plugin-catalog@1.12.0-next.2 - -## 0.0.12-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog@1.11.3-next.1 - - @backstage/plugin-catalog-react@1.7.1-next.1 - -## 0.0.12-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog@1.11.3-next.0 - - @backstage/plugin-catalog-react@1.7.1-next.0 - -## 0.0.11 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog@1.11.2 - - @backstage/plugin-catalog-react@1.7.0 - -## 0.0.11-next.3 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog@1.11.2-next.3 - - @backstage/plugin-catalog-react@1.7.0-next.3 - -## 0.0.11-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-react@1.7.0-next.2 - - @backstage/plugin-catalog@1.11.1-next.2 - -## 0.0.11-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog@1.11.1-next.1 - - @backstage/plugin-catalog-react@1.7.0-next.1 - -## 0.0.11-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-react@1.7.0-next.0 - - @backstage/plugin-catalog@1.11.1-next.0 - -## 0.0.10 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-react@1.6.0 - - @backstage/plugin-catalog@1.11.0 - -## 0.0.10-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog@1.11.0-next.2 - - @backstage/plugin-catalog-react@1.6.0-next.2 - -## 0.0.10-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog@1.11.0-next.1 - - @backstage/plugin-catalog-react@1.6.0-next.1 - -## 0.0.10-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-react@1.6.0-next.0 - - @backstage/plugin-catalog@1.11.0-next.0 - -## 0.0.9 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-react@1.5.0 - - @backstage/plugin-catalog@1.10.0 - -## 0.0.9-next.3 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-react@1.5.0-next.3 - - @backstage/plugin-catalog@1.10.0-next.3 - -## 0.0.9-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-react@1.4.1-next.2 - - @backstage/plugin-catalog@1.10.0-next.2 - -## 0.0.9-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-react@1.4.1-next.1 - - @backstage/plugin-catalog@1.10.0-next.1 - -## 0.0.9-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog@1.10.0-next.0 - - @backstage/plugin-catalog-react@1.4.1-next.0 - -## 0.0.8 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog@1.9.0 - - @backstage/plugin-catalog-react@1.4.0 - -## 0.0.8-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-react@1.4.0-next.2 - - @backstage/plugin-catalog@1.9.0-next.2 - -## 0.0.8-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog@1.9.0-next.1 - - @backstage/plugin-catalog-react@1.4.0-next.1 - -## 0.0.8-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-react@1.4.0-next.0 - - @backstage/plugin-catalog@1.9.0-next.0 - -## 0.0.7 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog@1.8.0 - - @backstage/plugin-catalog-react@1.3.0 - -## 0.0.7-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog@1.8.0-next.2 - - @backstage/plugin-catalog-react@1.3.0-next.2 - -## 0.0.7-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog@1.8.0-next.1 - - @backstage/plugin-catalog-react@1.3.0-next.1 - -## 0.0.7-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-react@1.3.0-next.0 - - @backstage/plugin-catalog@1.7.3-next.0 - -## 0.0.6 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-react@1.2.4 - - @backstage/plugin-catalog@1.7.2 - -## 0.0.6-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-react@1.2.4-next.2 - - @backstage/plugin-catalog@1.7.2-next.2 - -## 0.0.6-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog@1.7.2-next.1 - - @backstage/plugin-catalog-react@1.2.4-next.1 - -## 0.0.6-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-react@1.2.4-next.0 - - @backstage/plugin-catalog@1.7.2-next.0 - -## 0.0.6 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog@1.7.1 - - @backstage/plugin-catalog-react@1.2.3 - -## 0.0.5 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog@1.7.0 - - @backstage/plugin-catalog-react@1.2.2 - -## 0.0.5-next.4 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog@1.7.0-next.4 - - @backstage/plugin-catalog-react@1.2.2-next.4 - -## 0.0.5-next.3 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog@1.7.0-next.3 - - @backstage/plugin-catalog-react@1.2.2-next.3 - -## 0.0.5-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog@1.7.0-next.2 - - @backstage/plugin-catalog-react@1.2.2-next.2 - -## 0.0.5-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog@1.6.2-next.1 - - @backstage/plugin-catalog-react@1.2.2-next.1 - -## 0.0.5-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-react@1.2.2-next.0 - - @backstage/plugin-catalog@1.6.2-next.0 - -## 0.0.4 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-react@1.2.1 - - @backstage/plugin-catalog@1.6.1 - -## 0.0.4-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog@1.6.1-next.1 - - @backstage/plugin-catalog-react@1.2.1-next.1 - -## 0.0.4-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-react@1.2.1-next.0 - - @backstage/plugin-catalog@1.6.1-next.0 - -## 0.0.3 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-react@1.2.0 - - @backstage/plugin-catalog@1.6.0 - -## 0.0.3-next.2 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog@1.6.0-next.2 - - @backstage/plugin-catalog-react@1.2.0-next.2 - -## 0.0.3-next.1 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-react@1.2.0-next.1 - - @backstage/plugin-catalog@1.6.0-next.1 - -## 0.0.3-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog@1.5.2-next.0 - - @backstage/plugin-catalog-react@1.1.5-next.0 - -## 0.0.2 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-react@1.1.4 - - @backstage/plugin-catalog@1.5.1 - -## 0.0.2-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog-react@1.1.4-next.0 - - @backstage/plugin-catalog@1.5.1-next.0 - -## 0.0.1 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog@1.5.0 - - @backstage/plugin-catalog-react@1.1.3 - -## 0.0.1-next.0 - -### Patch Changes - -- Updated dependencies - - @backstage/plugin-catalog@1.5.0-next.0 - - @backstage/plugin-catalog-react@1.1.3-next.0 diff --git a/plugins/catalog-customized/README.md b/plugins/catalog-customized/README.md deleted file mode 100644 index b7323d7430..0000000000 --- a/plugins/catalog-customized/README.md +++ /dev/null @@ -1,57 +0,0 @@ -# Backstage Catalog Frontend - -This is the React frontend to customize Backstage [software -catalog](http://backstage.io/docs/features/software-catalog/). -This package supplies the example how it can be achieved. - -## Installation - -This `@internal/plugin-catalog-customized` package comes installed by default in example application of -Backstage application. - -To check if you already have the package, look under -`packages/app/package.json`, in the `dependencies` block, for -`@internal/plugin-catalog-customized`. The instructions below walk through restoring the -plugin, if you previously removed it. - -### Install the package - -```bash -# From your Backstage root directory -yarn add --cwd packages/app @internal/plugin-catalog-customized -``` - -### Add the plugin to your `packages/app` - -Add the import to a file where is your plugin catalog is defined: - -```diff -// packages/app/src/App.tsx - -import from '@internal/plugin-catalog-customized'; - -... - -import { - CatalogIndexPage, - CatalogEntityPage, -} from '@backstage/plugin-catalog'; - -... -``` - -## Development - -This frontend plugin can be started in a standalone mode from directly in this -package with `yarn start`. However, it will have limited functionality and that -process is most convenient when developing the catalog frontend plugin itself. - -To evaluate the catalog and have a greater amount of functionality available, -run the entire Backstage example application from the root folder: - -```bash -yarn dev -``` - -This will launch both frontend and backend in the same window, populated with -some example entities. diff --git a/plugins/catalog-customized/api-report.md b/plugins/catalog-customized/api-report.md deleted file mode 100644 index 5cf6eefde1..0000000000 --- a/plugins/catalog-customized/api-report.md +++ /dev/null @@ -1,9 +0,0 @@ -## API Report File for "@internal/plugin-catalog-customized" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts -export * from '@backstage/plugin-catalog'; - -// (No @packageDocumentation comment for this package) -``` diff --git a/plugins/catalog-customized/catalog-info.yaml b/plugins/catalog-customized/catalog-info.yaml deleted file mode 100644 index 1a6d0e0a00..0000000000 --- a/plugins/catalog-customized/catalog-info.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: backstage.io/v1alpha1 -kind: Component -metadata: - name: internal-plugin-catalog-customized - title: '@internal/plugin-catalog-customized' - description: >- - The internal Backstage Customizable plugin for browsing the Backstage - catalog -spec: - lifecycle: experimental - type: backstage-frontend-plugin - owner: catalog-maintainers diff --git a/plugins/catalog-customized/package.json b/plugins/catalog-customized/package.json deleted file mode 100644 index 4c33911549..0000000000 --- a/plugins/catalog-customized/package.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "name": "@internal/plugin-catalog-customized", - "description": "The internal Backstage Customizable plugin for browsing the Backstage catalog", - "version": "0.0.14", - "main": "src/index.ts", - "types": "src/index.ts", - "license": "Apache-2.0", - "private": true, - "publishConfig": { - "access": "public", - "main": "dist/index.esm.js", - "types": "dist/index.d.ts" - }, - "backstage": { - "role": "frontend-plugin" - }, - "homepage": "https://backstage.io", - "repository": { - "type": "git", - "url": "https://github.com/backstage/backstage", - "directory": "plugins/catalog-customized" - }, - "keywords": [ - "backstage" - ], - "sideEffects": false, - "scripts": { - "build": "backstage-cli package build", - "start": "backstage-cli package start", - "lint": "backstage-cli package lint", - "test": "backstage-cli package test", - "prepack": "backstage-cli package prepack", - "postpack": "backstage-cli package postpack", - "clean": "backstage-cli package clean" - }, - "dependencies": { - "@backstage/plugin-catalog": "workspace:^", - "@backstage/plugin-catalog-react": "workspace:^" - }, - "devDependencies": { - "@types/react": "^16.13.1 || ^17.0.0" - }, - "peerDependencies": { - "react": "^16.13.1 || ^17.0.0", - "react-dom": "^16.13.1 || ^17.0.0", - "react-router-dom": "6.0.0-beta.0 || ^6.3.0" - }, - "files": [ - "dist" - ] -} diff --git a/plugins/catalog-graph/CHANGELOG.md b/plugins/catalog-graph/CHANGELOG.md index c5032a1cf4..a9fc8ea29d 100644 --- a/plugins/catalog-graph/CHANGELOG.md +++ b/plugins/catalog-graph/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/plugin-catalog-graph +## 0.2.37-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + +## 0.2.37-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + ## 0.2.36 ### Patch Changes diff --git a/plugins/catalog-graph/api-report.md b/plugins/catalog-graph/api-report.md index ce56245c49..98a68d8aa2 100644 --- a/plugins/catalog-graph/api-report.md +++ b/plugins/catalog-graph/api-report.md @@ -53,8 +53,7 @@ export const catalogGraphPlugin: BackstagePlugin< }, true >; - }, - {} + } >; // @public diff --git a/plugins/catalog-graph/package.json b/plugins/catalog-graph/package.json index 236103471f..77cdee4476 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.36", + "version": "0.2.37-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-graph/src/components/CatalogGraphPage/CatalogGraphPage.test.tsx b/plugins/catalog-graph/src/components/CatalogGraphPage/CatalogGraphPage.test.tsx index 17bec9a475..2e215e75f9 100644 --- a/plugins/catalog-graph/src/components/CatalogGraphPage/CatalogGraphPage.test.tsx +++ b/plugins/catalog-graph/src/components/CatalogGraphPage/CatalogGraphPage.test.tsx @@ -111,14 +111,14 @@ describe('<CatalogGraphPage/>', () => { await renderInTestApp(wrapper, { mountedRoutes: { - '/entity/{kind}/{namespace}/{name}': entityRouteRef, + '/entity/:kind/:namespace/:name': entityRouteRef, }, }); expect(screen.getByText('Catalog Graph')).toBeInTheDocument(); - expect(await screen.findByText('b:d/c')).toBeInTheDocument(); - expect(await screen.findByText('b:d/e')).toBeInTheDocument(); - expect(await screen.findAllByTestId('node')).toHaveLength(2); + await expect(screen.findByText('b:d/c')).resolves.toBeInTheDocument(); + await expect(screen.findByText('b:d/e')).resolves.toBeInTheDocument(); + await expect(screen.findAllByTestId('node')).resolves.toHaveLength(2); expect(catalog.getEntityByRef).toHaveBeenCalledTimes(2); }); @@ -129,7 +129,7 @@ describe('<CatalogGraphPage/>', () => { await renderInTestApp(wrapper, { mountedRoutes: { - '/entity/{kind}/{namespace}/{name}': entityRouteRef, + '/entity/:kind/:namespace/:name': entityRouteRef, }, }); @@ -147,15 +147,15 @@ describe('<CatalogGraphPage/>', () => { await renderInTestApp(wrapper, { mountedRoutes: { - '/entity/{kind}/{namespace}/{name}': entityRouteRef, + '/entity/:kind/:namespace/:name': entityRouteRef, }, }); - expect(await screen.findAllByTestId('node')).toHaveLength(2); + await expect(screen.findAllByTestId('node')).resolves.toHaveLength(2); await userEvent.click(screen.getByText('b:d/e')); - expect(await screen.findByText('hasPart')).toBeInTheDocument(); + await expect(screen.findByText('hasPart')).resolves.toBeInTheDocument(); }); test('should navigate to entity', async () => { @@ -165,16 +165,16 @@ describe('<CatalogGraphPage/>', () => { await renderInTestApp(wrapper, { mountedRoutes: { - '/entity/{kind}/{namespace}/{name}': entityRouteRef, + '/entity/:kind/:namespace/:name': entityRouteRef, }, }); - expect(await screen.findAllByTestId('node')).toHaveLength(2); + await expect(screen.findAllByTestId('node')).resolves.toHaveLength(2); const user = userEvent.setup(); await user.keyboard('{Shift>}'); await user.click(screen.getByText('b:d/e')); - expect(navigate).toHaveBeenCalledWith('/entity/{kind}/{namespace}/{name}'); + expect(navigate).toHaveBeenCalledWith('/entity/b/d/e'); }); test('should capture analytics event when selecting other entity', async () => { @@ -189,15 +189,12 @@ describe('<CatalogGraphPage/>', () => { </TestApiProvider>, { mountedRoutes: { - '/entity/{kind}/{namespace}/{name}': entityRouteRef, + '/entity/:kind/:namespace/:name': entityRouteRef, }, }, ); - expect(await screen.findAllByTestId('node')).toHaveLength(2); - - // We wait a bit here to reliably reproduce an issue where that requires the `baseVal` and `view` mocks - await new Promise(r => setTimeout(r, 100)); + await expect(screen.findAllByTestId('node')).resolves.toHaveLength(2); await userEvent.click(screen.getByText('b:d/e')); @@ -219,12 +216,12 @@ describe('<CatalogGraphPage/>', () => { </TestApiProvider>, { mountedRoutes: { - '/entity/{kind}/{namespace}/{name}': entityRouteRef, + '/entity/:kind/:namespace/:name': entityRouteRef, }, }, ); - expect(await screen.findAllByTestId('node')).toHaveLength(2); + await expect(screen.findAllByTestId('node')).resolves.toHaveLength(2); const user = userEvent.setup(); await user.keyboard('{Shift>}'); @@ -234,7 +231,7 @@ describe('<CatalogGraphPage/>', () => { action: 'click', subject: 'b:d/e', attributes: { - to: '/entity/{kind}/{namespace}/{name}', + to: '/entity/b/d/e', }, }); }); diff --git a/plugins/catalog-import/CHANGELOG.md b/plugins/catalog-import/CHANGELOG.md index 84efe07b7f..97a6070230 100644 --- a/plugins/catalog-import/CHANGELOG.md +++ b/plugins/catalog-import/CHANGELOG.md @@ -1,5 +1,37 @@ # @backstage/plugin-catalog-import +## 0.10.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/integration-react@1.1.20-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/plugin-catalog-common@1.0.16 + +## 0.10.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/integration-react@1.1.20-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/plugin-catalog-common@1.0.16 + ## 0.10.0 ### Minor Changes diff --git a/plugins/catalog-import/api-report.md b/plugins/catalog-import/api-report.md index 7397bfad1d..a513cfe87a 100644 --- a/plugins/catalog-import/api-report.md +++ b/plugins/catalog-import/api-report.md @@ -134,7 +134,6 @@ const catalogImportPlugin: BackstagePlugin< { importPage: RouteRef<undefined>; }, - {}, {} >; export { catalogImportPlugin }; diff --git a/plugins/catalog-import/package.json b/plugins/catalog-import/package.json index 5d68888beb..a982b13373 100644 --- a/plugins/catalog-import/package.json +++ b/plugins/catalog-import/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-import", "description": "A Backstage plugin the helps you import entities into your catalog", - "version": "0.10.0", + "version": "0.10.1-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-node/CHANGELOG.md b/plugins/catalog-node/CHANGELOG.md index 1d3b4d54da..0126011e83 100644 --- a/plugins/catalog-node/CHANGELOG.md +++ b/plugins/catalog-node/CHANGELOG.md @@ -1,5 +1,30 @@ # @backstage/plugin-catalog-node +## 1.4.6-next.1 + +### Patch Changes + +- 7a2e2924c7: Added docs to `processingResult` +- Updated dependencies + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.16 + +## 1.4.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.16 + ## 1.4.4 ### Patch Changes diff --git a/plugins/catalog-node/package.json b/plugins/catalog-node/package.json index ca2de8542d..61e9823ea6 100644 --- a/plugins/catalog-node/package.json +++ b/plugins/catalog-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-node", "description": "The plugin-catalog-node module for @backstage/plugin-catalog-backend", - "version": "1.4.4", + "version": "1.4.6-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-node/src/api/processingResult.ts b/plugins/catalog-node/src/api/processingResult.ts index d8b6f3ae02..0d4341fcb7 100644 --- a/plugins/catalog-node/src/api/processingResult.ts +++ b/plugins/catalog-node/src/api/processingResult.ts @@ -26,6 +26,9 @@ import { LocationSpec } from '@backstage/plugin-catalog-common'; * @public */ export const processingResult = Object.freeze({ + /** + * Associates a NotFoundError with the processing state of the current entity. + */ notFoundError( atLocation: LocationSpec, message: string, @@ -37,6 +40,9 @@ export const processingResult = Object.freeze({ }; }, + /** + * Associates an InputError with the processing state of the current entity. + */ inputError( atLocation: LocationSpec, message: string, @@ -48,6 +54,9 @@ export const processingResult = Object.freeze({ }; }, + /** + * Associates a general Error with the processing state of the current entity. + */ generalError( atLocation: LocationSpec, message: string, @@ -55,18 +64,36 @@ export const processingResult = Object.freeze({ return { type: 'error', location: atLocation, error: new Error(message) }; }, + /** + * Emits a location. In effect, this is analogous to emitting a Location kind + * child entity. This is commonly used in discovery processors. Do not use + * this while processing Location entities. + */ location(newLocation: LocationSpec): CatalogProcessorResult { return { type: 'location', location: newLocation }; }, + /** + * Emits a child of the current entity, associated with a certain location. + */ entity(atLocation: LocationSpec, newEntity: Entity): CatalogProcessorResult { return { type: 'entity', location: atLocation, entity: newEntity }; }, + /** + * Emits a relation owned by the current entity. The relation does not have to + * start or end at the current entity. The relation only lives for as long as + * the current entity lives. + */ relation(spec: EntityRelationSpec): CatalogProcessorResult { return { type: 'relation', relation: spec }; }, + /** + * Associates the given refresh key with the current entity. The effect of + * this is that the entity will be marked for refresh when such requests are + * made. + */ refresh(key: string): CatalogProcessorResult { return { type: 'refresh', key }; }, diff --git a/plugins/catalog-react/CHANGELOG.md b/plugins/catalog-react/CHANGELOG.md index f8ddbe2a0a..467f134119 100644 --- a/plugins/catalog-react/CHANGELOG.md +++ b/plugins/catalog-react/CHANGELOG.md @@ -1,5 +1,42 @@ # @backstage/plugin-catalog-react +## 1.8.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/plugin-permission-react@0.4.16-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.5 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-permission-common@0.7.8 + +## 1.8.5-next.0 + +### Patch Changes + +- a402e1dfb9: Fixed an issue causing `EntityPage` to show an error for entities containing special characters +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/plugin-permission-react@0.4.16-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.5 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-permission-common@0.7.8 + ## 1.8.4 ### Patch Changes diff --git a/plugins/catalog-react/package.json b/plugins/catalog-react/package.json index 277a37e1a2..637f83fcee 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.8.4", + "version": "1.8.5-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-unprocessed-entities/CHANGELOG.md b/plugins/catalog-unprocessed-entities/CHANGELOG.md index f797b6b5e1..612c02a9a1 100644 --- a/plugins/catalog-unprocessed-entities/CHANGELOG.md +++ b/plugins/catalog-unprocessed-entities/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-catalog-unprocessed-entities +## 0.1.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## 0.1.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + ## 0.1.3 ### Patch Changes diff --git a/plugins/catalog-unprocessed-entities/api-report.md b/plugins/catalog-unprocessed-entities/api-report.md index 3ded42785a..cc4d6bba88 100644 --- a/plugins/catalog-unprocessed-entities/api-report.md +++ b/plugins/catalog-unprocessed-entities/api-report.md @@ -34,7 +34,6 @@ export const catalogUnprocessedEntitiesPlugin: BackstagePlugin< { root: RouteRef<undefined>; }, - {}, {} >; diff --git a/plugins/catalog-unprocessed-entities/package.json b/plugins/catalog-unprocessed-entities/package.json index ce24df8001..735cb05f8d 100644 --- a/plugins/catalog-unprocessed-entities/package.json +++ b/plugins/catalog-unprocessed-entities/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-unprocessed-entities", - "version": "0.1.3", + "version": "0.1.4-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog/CHANGELOG.md b/plugins/catalog/CHANGELOG.md index a26c19cfd6..648fa4d7a4 100644 --- a/plugins/catalog/CHANGELOG.md +++ b/plugins/catalog/CHANGELOG.md @@ -1,5 +1,67 @@ # @backstage/plugin-catalog +## 1.14.0-next.1 + +### Patch Changes + +- 7c4a8e4d5f: Create an experimental `CatalogSearchResultItemExtension` for declarative integration with Backstage; it can be accessed via the `/alpha` import. +- e5a2956dd2: Migrate catalog api to declarative integration system, it is exported from `/alpha` subpath. +- Updated dependencies + - @backstage/frontend-plugin-api@0.1.1-next.1 + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-search-react@1.7.1-next.1 + - @backstage/integration-react@1.1.20-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-scaffolder-common@1.4.1 + - @backstage/plugin-search-common@1.2.6 + +## 1.14.0-next.0 + +### Minor Changes + +- 28f1ab2e1a: The catalog plugin no longer implements the experimental reconfiguration API. The create button title can now instead be configured using the new experimental internationalization API, via the `catalogTranslationRef` exported at `/alpha`. For example: + + ```ts + import { catalogTranslationRef } from '@backstage/plugin-catalog/alpha'; + + const app = createApp({ + __experimentalTranslations: { + resources: [ + createTranslationMessages({ + ref: catalogTranslationRef, + catalog_page_create_button_title: 'Create Software', + }), + ], + }, + }); + ``` + +- f3561a2935: include owner chip in catalog search result item + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/integration-react@1.1.20-next.0 + - @backstage/plugin-search-react@1.7.1-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-scaffolder-common@1.4.1 + - @backstage/plugin-search-common@1.2.6 + ## 1.13.0 ### Minor Changes diff --git a/plugins/catalog/alpha-api-report.md b/plugins/catalog/alpha-api-report.md new file mode 100644 index 0000000000..e89807ac34 --- /dev/null +++ b/plugins/catalog/alpha-api-report.md @@ -0,0 +1,25 @@ +## API Report File for "@backstage/plugin-catalog" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { BackstagePlugin } from '@backstage/frontend-plugin-api'; +import { Extension } from '@backstage/frontend-plugin-api'; + +// @alpha (undocumented) +export const CatalogApi: Extension<{}>; + +// @alpha (undocumented) +export const CatalogSearchResultListItemExtension: Extension<{ + noTrack?: boolean | undefined; +}>; + +// @alpha (undocumented) +const _default: BackstagePlugin; +export default _default; + +// @alpha (undocumented) +export const StarredEntitiesApi: Extension<{}>; + +// (No @packageDocumentation comment for this package) +``` diff --git a/plugins/catalog/api-report.md b/plugins/catalog/api-report.md index c8956dcbe8..8173c395ba 100644 --- a/plugins/catalog/api-report.md +++ b/plugins/catalog/api-report.md @@ -117,8 +117,7 @@ export const catalogPlugin: BackstagePlugin< }, true >; - }, - CatalogInputPluginOptions + } >; // @public (undocumented) diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json index 10a9eaf35e..f779220669 100644 --- a/plugins/catalog/package.json +++ b/plugins/catalog/package.json @@ -1,14 +1,27 @@ { "name": "@backstage/plugin-catalog", "description": "The Backstage plugin for browsing the Backstage catalog", - "version": "1.13.0", + "version": "1.14.0-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", "publishConfig": { - "access": "public", - "main": "dist/index.esm.js", - "types": "dist/index.d.ts" + "access": "public" + }, + "exports": { + ".": "./src/index.ts", + "./alpha": "./src/alpha.tsx", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "alpha": [ + "src/alpha.tsx" + ], + "package.json": [ + "package.json" + ] + } }, "backstage": { "role": "frontend-plugin" @@ -38,6 +51,7 @@ "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/errors": "workspace:^", + "@backstage/frontend-plugin-api": "workspace:^", "@backstage/integration-react": "workspace:^", "@backstage/plugin-catalog-common": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", diff --git a/plugins/catalog/src/alpha.tsx b/plugins/catalog/src/alpha.tsx new file mode 100644 index 0000000000..5e78a52f9b --- /dev/null +++ b/plugins/catalog/src/alpha.tsx @@ -0,0 +1,76 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + createApiFactory, + discoveryApiRef, + fetchApiRef, + storageApiRef, +} from '@backstage/core-plugin-api'; +import { CatalogClient } from '@backstage/catalog-client'; +import { + createApiExtension, + createPlugin, +} from '@backstage/frontend-plugin-api'; +import { + catalogApiRef, + starredEntitiesApiRef, +} from '@backstage/plugin-catalog-react'; +import { createSearchResultListItemExtension } from '@backstage/plugin-search-react/alpha'; +import { DefaultStarredEntitiesApi } from './apis'; + +/** @alpha */ +export const CatalogApi = createApiExtension({ + factory: createApiFactory({ + api: catalogApiRef, + deps: { + discoveryApi: discoveryApiRef, + fetchApi: fetchApiRef, + }, + factory: ({ discoveryApi, fetchApi }) => + new CatalogClient({ discoveryApi, fetchApi }), + }), +}); + +/** @alpha */ +export const StarredEntitiesApi = createApiExtension({ + factory: createApiFactory({ + api: starredEntitiesApiRef, + deps: { storageApi: storageApiRef }, + factory: ({ storageApi }) => new DefaultStarredEntitiesApi({ storageApi }), + }), +}); + +/** @alpha */ +export const CatalogSearchResultListItemExtension = + createSearchResultListItemExtension({ + id: 'catalog', + predicate: result => result.type === 'software-catalog', + component: () => + import('./components/CatalogSearchResultListItem').then( + m => m.CatalogSearchResultListItem, + ), + }); + +/** @alpha */ +export default createPlugin({ + id: 'catalog', + extensions: [ + CatalogApi, + StarredEntitiesApi, + CatalogSearchResultListItemExtension, + ], +}); diff --git a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.test.tsx b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.test.tsx index f31d3baf39..b7d3ca3ed8 100644 --- a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.test.tsx +++ b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.test.tsx @@ -29,7 +29,6 @@ import { MockStarredEntitiesApi, starredEntitiesApiRef, } from '@backstage/plugin-catalog-react'; -import { MockPluginProvider } from '@backstage/test-utils/alpha'; import { mockBreakpoint, MockStorageApi, @@ -133,7 +132,7 @@ describe('DefaultCatalogPage', () => { [starredEntitiesApiRef, new MockStarredEntitiesApi()], ]} > - <MockPluginProvider>{children}</MockPluginProvider> + {children} </TestApiProvider>, { mountedRoutes: { diff --git a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx index 04f39ee66c..fb9b282d57 100644 --- a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx +++ b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx @@ -41,7 +41,8 @@ import { import React, { ReactNode } from 'react'; import { createComponentRouteRef } from '../../routes'; import { CatalogTable, CatalogTableRow } from '../CatalogTable'; -import { useCatalogPluginOptions } from '../../options'; +import { catalogTranslationRef } from '../../translation'; +import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; /** * Props for root catalog pages. @@ -71,15 +72,14 @@ export function DefaultCatalogPage(props: DefaultCatalogPageProps) { const orgName = useApi(configApiRef).getOptionalString('organization.name') ?? 'Backstage'; const createComponentLink = useRouteRef(createComponentRouteRef); - - const { createButtonTitle } = useCatalogPluginOptions(); + const { t } = useTranslationRef(catalogTranslationRef); return ( - <PageWithHeader title={`${orgName} Catalog`} themeId="home"> + <PageWithHeader title={t('catalog_page_title', { orgName })} themeId="home"> <Content> <ContentHeader title=""> <CreateButton - title={createButtonTitle} + title={t('catalog_page_create_button_title')} to={createComponentLink && createComponentLink()} /> <SupportButton>All your software catalog entities</SupportButton> diff --git a/plugins/catalog/src/components/CatalogSearchResultListItem/CatalogSearchResultListItem.tsx b/plugins/catalog/src/components/CatalogSearchResultListItem/CatalogSearchResultListItem.tsx index 50caf4ff8a..06906aecc1 100644 --- a/plugins/catalog/src/components/CatalogSearchResultListItem/CatalogSearchResultListItem.tsx +++ b/plugins/catalog/src/components/CatalogSearchResultListItem/CatalogSearchResultListItem.tsx @@ -110,6 +110,9 @@ export function CatalogSearchResultListItem( {result.lifecycle && ( <Chip label={`Lifecycle: ${result.lifecycle}`} size="small" /> )} + {result.owner && ( + <Chip label={`Owner: ${result.owner}`} size="small" /> + )} </Box> </div> </div> diff --git a/plugins/catalog/src/plugin.ts b/plugins/catalog/src/plugin.ts index 711f52767a..3410984ec3 100644 --- a/plugins/catalog/src/plugin.ts +++ b/plugins/catalog/src/plugin.ts @@ -52,7 +52,6 @@ import { HasSystemsCardProps } from './components/HasSystemsCard'; import { RelatedEntitiesCardProps } from './components/RelatedEntitiesCard'; import { CatalogSearchResultListItemProps } from './components/CatalogSearchResultListItem'; import { rootRouteRef } from './routes'; -import { CatalogInputPluginOptions, CatalogPluginOptions } from './options'; /** @public */ export const catalogPlugin = createPlugin({ @@ -83,14 +82,6 @@ export const catalogPlugin = createPlugin({ viewTechDoc: viewTechDocRouteRef, createFromTemplate: createFromTemplateRouteRef, }, - __experimentalConfigure( - options?: CatalogInputPluginOptions, - ): CatalogPluginOptions { - const defaultOptions = { - createButtonTitle: 'Create', - }; - return { ...defaultOptions, ...options }; - }, }); /** @public */ diff --git a/plugins/catalog/src/translation.ts b/plugins/catalog/src/translation.ts new file mode 100644 index 0000000000..2d1e3f2c8a --- /dev/null +++ b/plugins/catalog/src/translation.ts @@ -0,0 +1,26 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createTranslationRef } from '@backstage/core-plugin-api/alpha'; + +/** @alpha */ +export const catalogTranslationRef = createTranslationRef({ + id: 'catalog', + messages: { + catalog_page_title: `{{orgName}} Catalog`, + catalog_page_create_button_title: 'Create', + }, +}); diff --git a/plugins/cicd-statistics-module-gitlab/CHANGELOG.md b/plugins/cicd-statistics-module-gitlab/CHANGELOG.md index 539caaef1e..a1952616bb 100644 --- a/plugins/cicd-statistics-module-gitlab/CHANGELOG.md +++ b/plugins/cicd-statistics-module-gitlab/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-cicd-statistics-module-gitlab +## 0.1.21-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/plugin-cicd-statistics@0.1.27-next.1 + +## 0.1.21-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/plugin-cicd-statistics@0.1.27-next.0 + - @backstage/catalog-model@1.4.2 + ## 0.1.20 ### Patch Changes diff --git a/plugins/cicd-statistics-module-gitlab/package.json b/plugins/cicd-statistics-module-gitlab/package.json index 7573ebd63e..afdd1cd758 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.20", + "version": "0.1.21-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/cicd-statistics/CHANGELOG.md b/plugins/cicd-statistics/CHANGELOG.md index 6a70334cb1..4abb69de10 100644 --- a/plugins/cicd-statistics/CHANGELOG.md +++ b/plugins/cicd-statistics/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-cicd-statistics +## 0.1.27-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + +## 0.1.27-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + ## 0.1.26 ### Patch Changes diff --git a/plugins/cicd-statistics/api-report.md b/plugins/cicd-statistics/api-report.md index b0966aa281..70895d6a63 100644 --- a/plugins/cicd-statistics/api-report.md +++ b/plugins/cicd-statistics/api-report.md @@ -85,7 +85,6 @@ export const cicdStatisticsPlugin: BackstagePlugin< { entityContent: RouteRef<undefined>; }, - {}, {} >; diff --git a/plugins/cicd-statistics/package.json b/plugins/cicd-statistics/package.json index 9936874270..60668da35a 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.26", + "version": "0.1.27-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/circleci/CHANGELOG.md b/plugins/circleci/CHANGELOG.md index 71673c46eb..38e797dc35 100644 --- a/plugins/circleci/CHANGELOG.md +++ b/plugins/circleci/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-circleci +## 0.3.25-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## 0.3.25-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + ## 0.3.24 ### Patch Changes diff --git a/plugins/circleci/api-report.md b/plugins/circleci/api-report.md index d706115610..3bb8d4b6f9 100644 --- a/plugins/circleci/api-report.md +++ b/plugins/circleci/api-report.md @@ -63,7 +63,7 @@ export const circleCIApiRef: ApiRef<CircleCIApi>; export const circleCIBuildRouteRef: SubRouteRef<PathParams<'/:buildId'>>; // @public (undocumented) -const circleCIPlugin: BackstagePlugin<{}, {}, {}>; +const circleCIPlugin: BackstagePlugin<{}, {}>; export { circleCIPlugin }; export { circleCIPlugin as plugin }; diff --git a/plugins/circleci/package.json b/plugins/circleci/package.json index 8d897fda4f..c1c4c07004 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.24", + "version": "0.3.25-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/cloudbuild/CHANGELOG.md b/plugins/cloudbuild/CHANGELOG.md index 0905269073..3affd61ba7 100644 --- a/plugins/cloudbuild/CHANGELOG.md +++ b/plugins/cloudbuild/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-cloudbuild +## 0.3.25-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## 0.3.25-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + ## 0.3.24 ### Patch Changes diff --git a/plugins/cloudbuild/api-report.md b/plugins/cloudbuild/api-report.md index dc2aacbc18..3fbb15000d 100644 --- a/plugins/cloudbuild/api-report.md +++ b/plugins/cloudbuild/api-report.md @@ -104,7 +104,6 @@ const cloudbuildPlugin: BackstagePlugin< { entityContent: RouteRef<undefined>; }, - {}, {} >; export { cloudbuildPlugin }; diff --git a/plugins/cloudbuild/package.json b/plugins/cloudbuild/package.json index 74338240c6..d09f2372ab 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.24", + "version": "0.3.25-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/code-climate/CHANGELOG.md b/plugins/code-climate/CHANGELOG.md index 749de6cd76..9e32befc60 100644 --- a/plugins/code-climate/CHANGELOG.md +++ b/plugins/code-climate/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-code-climate +## 0.1.25-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## 0.1.25-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + ## 0.1.24 ### Patch Changes diff --git a/plugins/code-climate/api-report.md b/plugins/code-climate/api-report.md index 32359f663f..8243cada75 100644 --- a/plugins/code-climate/api-report.md +++ b/plugins/code-climate/api-report.md @@ -42,7 +42,6 @@ export const codeClimatePlugin: BackstagePlugin< { root: RouteRef<undefined>; }, - {}, {} >; diff --git a/plugins/code-climate/package.json b/plugins/code-climate/package.json index 30e29490eb..800c97652f 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.24", + "version": "0.1.25-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/code-coverage-backend/CHANGELOG.md b/plugins/code-coverage-backend/CHANGELOG.md index 2c4d9685e5..817fe0d57d 100644 --- a/plugins/code-coverage-backend/CHANGELOG.md +++ b/plugins/code-coverage-backend/CHANGELOG.md @@ -1,5 +1,32 @@ # @backstage/plugin-code-coverage-backend +## 0.2.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + +## 0.2.19-next.0 + +### Patch Changes + +- 4aa27aa200: Added option to set body size limit +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + ## 0.2.17 ### Patch Changes diff --git a/plugins/code-coverage-backend/README.md b/plugins/code-coverage-backend/README.md index a60b95ff25..54cf201015 100644 --- a/plugins/code-coverage-backend/README.md +++ b/plugins/code-coverage-backend/README.md @@ -235,3 +235,12 @@ Example ] } ``` + +### Configuration + +Configure the plugin in your `app-config.yaml`: + +```yaml +codeCoverage: + bodySizeLimit: 100kb # Defaults to 100kb, see https://www.npmjs.com/package/body-parser#limit +``` diff --git a/plugins/code-coverage-backend/package.json b/plugins/code-coverage-backend/package.json index f875f4d03d..761fccda23 100644 --- a/plugins/code-coverage-backend/package.json +++ b/plugins/code-coverage-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-code-coverage-backend", "description": "A Backstage backend plugin that helps you keep track of your code coverage", - "version": "0.2.17", + "version": "0.2.19-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/code-coverage-backend/src/service/router.test.ts b/plugins/code-coverage-backend/src/service/router.test.ts index 4f1a9ee2e5..2032a5470d 100644 --- a/plugins/code-coverage-backend/src/service/router.test.ts +++ b/plugins/code-coverage-backend/src/service/router.test.ts @@ -41,6 +41,7 @@ CodeCoverageDatabase.create = jest.fn( }, }), getHistory: async () => ({}), + insertCodeCoverage: async () => undefined, } as any), ); @@ -50,7 +51,13 @@ jest.mock('@backstage/catalog-client', () => ({ CatalogClient: jest.fn().mockImplementation(() => ({ getEntityByRef: async (_: string, options: CatalogRequestOptions) => { catalogRequestOptions = options; - return {}; + return { + metadata: { + annotations: { + 'backstage.io/code-coverage': 'enabled', + }, + }, + }; }, })), })); @@ -129,4 +136,41 @@ describe('createRouter', () => { }); }); }); + + describe('POST /report', () => { + it('returns created when body does not exceed limit', async () => { + const response = await request(app) + .post('/report?entity=component:default/mycomponent&coverageType=lcov') + .set('Content-Type', 'text/plain') + .send( + 'TN:\nSF:/src/index.js\nFNF:0\nFNH:0\nLF:1\nLH:1\nBRF:0\nBRH:0\nend_of_record', + ); + + expect(response.status).toBe(201); + }); + + it('returns content too large when body exceeds limit', async () => { + const router = await createRouter({ + config: new ConfigReader({ + codeCoverage: { + bodySizeLimit: '1b', + }, + }), + database: createDatabase(), + discovery: testDiscovery, + urlReader: mockUrlReader, + logger: getVoidLogger(), + }); + app = express().use(router); + + const response = await request(app) + .post('/report?entity=component:default/mycomponent&coverageType=lcov') + .set('Content-Type', 'text/plain') + .send( + 'TN:\nSF:/src/index.js\nFNF:0\nFNH:0\nLF:1\nLH:1\nBRF:0\nBRH:0\nend_of_record', + ); + + expect(response.status).toBe(413); + }); + }); }); diff --git a/plugins/code-coverage-backend/src/service/router.ts b/plugins/code-coverage-backend/src/service/router.ts index 3b97f2d233..47bc285d62 100644 --- a/plugins/code-coverage-backend/src/service/router.ts +++ b/plugins/code-coverage-backend/src/service/router.ts @@ -64,10 +64,21 @@ export const makeRouter = async ( options.catalogApi ?? new CatalogClient({ discoveryApi: discovery }); const scm = ScmIntegrations.fromConfig(config); + const bodySizeLimit = + config.getOptionalString('codeCoverage.bodySizeLimit') ?? '100kb'; + bodyParserXml(BodyParser); const router = Router(); - router.use(BodyParser.xml()); - router.use(BodyParser.text()); + router.use( + BodyParser.xml({ + limit: bodySizeLimit, + }), + ); + router.use( + BodyParser.text({ + limit: bodySizeLimit, + }), + ); router.use(express.json()); const utils = new CoverageUtils(scm, urlReader); diff --git a/plugins/code-coverage/CHANGELOG.md b/plugins/code-coverage/CHANGELOG.md index b8bf77b484..3801f63f61 100644 --- a/plugins/code-coverage/CHANGELOG.md +++ b/plugins/code-coverage/CHANGELOG.md @@ -1,5 +1,33 @@ # @backstage/plugin-code-coverage +## 0.2.18-next.1 + +### Patch Changes + +- 88b0b32547: Fixed the coverage history statistics to compare newest with oldest record +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## 0.2.18-next.0 + +### Patch Changes + +- a468544fa9: Updated layout to improve contrasts and consistency with other plugins +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + ## 0.2.17 ### Patch Changes diff --git a/plugins/code-coverage/api-report.md b/plugins/code-coverage/api-report.md index 5dcb5fcfd1..152cc93103 100644 --- a/plugins/code-coverage/api-report.md +++ b/plugins/code-coverage/api-report.md @@ -14,7 +14,6 @@ export const codeCoveragePlugin: BackstagePlugin< { root: RouteRef<undefined>; }, - {}, {} >; diff --git a/plugins/code-coverage/dev/__fixtures__/coverage-for-entity.json b/plugins/code-coverage/dev/__fixtures__/coverage-for-entity.json new file mode 100644 index 0000000000..c2f4725818 --- /dev/null +++ b/plugins/code-coverage/dev/__fixtures__/coverage-for-entity.json @@ -0,0 +1,174 @@ +{ + "metadata": { + "vcs": { + "type": "github", + "location": "https://github.com/backstage/backstage/tree/main/" + }, + "generationTime": 1694413579498 + }, + "entity": { + "name": "backstage", + "namespace": "default", + "kind": "Component" + }, + "files": [ + { + "filename": "src/index.js", + "lineHits": { + "1": 1, + "2": 1, + "3": 1, + "4": 13, + "5": 13, + "6": 3, + "7": 13, + "8": 3, + "9": 13, + "10": 3, + "11": 13, + "12": 3, + "13": 13, + "14": 1, + "15": 13, + "16": 13 + }, + "branchHits": { + "3": { + "covered": 1, + "available": 1, + "missed": 0 + }, + "5": { + "covered": 1, + "available": 1, + "missed": 0 + }, + "7": { + "covered": 1, + "available": 1, + "missed": 0 + }, + "9": { + "covered": 1, + "available": 1, + "missed": 0 + }, + "11": { + "covered": 1, + "available": 1, + "missed": 0 + }, + "13": { + "covered": 1, + "available": 1, + "missed": 0 + } + } + }, + { + "filename": "src/math.js", + "lineHits": { + "1": 1, + "2": 3, + "3": 2, + "4": 2, + "5": 1, + "6": 1, + "7": 1, + "8": 1, + "9": 3, + "10": 2, + "11": 2, + "12": 1, + "13": 1, + "14": 1, + "15": 1, + "16": 3, + "17": 2, + "18": 2, + "19": 1, + "20": 1, + "21": 1, + "22": 1, + "23": 3, + "24": 2, + "25": 3, + "26": 0, + "27": 0, + "28": 1, + "29": 1 + }, + "branchHits": { + "2": { + "covered": 3, + "available": 3, + "missed": 0 + }, + "5": { + "covered": 1, + "available": 1, + "missed": 0 + }, + "8": { + "covered": 1, + "available": 1, + "missed": 0 + }, + "9": { + "covered": 2, + "available": 2, + "missed": 0 + }, + "12": { + "covered": 1, + "available": 1, + "missed": 0 + }, + "15": { + "covered": 1, + "available": 1, + "missed": 0 + }, + "16": { + "covered": 2, + "available": 2, + "missed": 0 + }, + "19": { + "covered": 1, + "available": 1, + "missed": 0 + }, + "22": { + "covered": 1, + "available": 1, + "missed": 0 + }, + "23": { + "covered": 2, + "available": 2, + "missed": 0 + }, + "25": { + "covered": 1, + "available": 2, + "missed": 1 + } + } + } + ], + "aggregate": { + "line": { + "available": 45, + "covered": 43, + "missed": 2, + "percentage": 95.56 + }, + "branch": { + "available": 23, + "covered": 22, + "missed": 1, + "percentage": 95.65 + } + } +} diff --git a/plugins/code-coverage/dev/__fixtures__/coverage-history-for-entity.json b/plugins/code-coverage/dev/__fixtures__/coverage-history-for-entity.json new file mode 100644 index 0000000000..26b96875e5 --- /dev/null +++ b/plugins/code-coverage/dev/__fixtures__/coverage-history-for-entity.json @@ -0,0 +1,84 @@ +{ + "entity": { + "name": "backstage", + "kind": "component", + "namespace": "default" + }, + "history": [ + { + "timestamp": 1694413579498, + "branch": { + "available": 23, + "covered": 22, + "missed": 1, + "percentage": 95.65 + }, + "line": { + "available": 45, + "covered": 43, + "missed": 2, + "percentage": 95.56 + } + }, + { + "timestamp": 1694178927072, + "branch": { + "available": 23, + "covered": 22, + "missed": 1, + "percentage": 95.65 + }, + "line": { + "available": 45, + "covered": 43, + "missed": 2, + "percentage": 95.56 + } + }, + { + "timestamp": 1694178830777, + "branch": { + "available": 19, + "covered": 18, + "missed": 1, + "percentage": 94.74 + }, + "line": { + "available": 45, + "covered": 43, + "missed": 2, + "percentage": 95.56 + } + }, + { + "timestamp": 1694178708402, + "branch": { + "available": 15, + "covered": 10, + "missed": 5, + "percentage": 66.67 + }, + "line": { + "available": 45, + "covered": 36, + "missed": 9, + "percentage": 80 + } + }, + { + "timestamp": 1694178270486, + "branch": { + "available": 10, + "covered": 5, + "missed": 5, + "percentage": 50 + }, + "line": { + "available": 45, + "covered": 26, + "missed": 19, + "percentage": 57.78 + } + } + ] +} diff --git a/plugins/code-coverage/dev/__fixtures__/file-content-index-js.txt b/plugins/code-coverage/dev/__fixtures__/file-content-index-js.txt new file mode 100644 index 0000000000..34df5226d5 --- /dev/null +++ b/plugins/code-coverage/dev/__fixtures__/file-content-index-js.txt @@ -0,0 +1,16 @@ +import { add, multiply, subtract, divide } from "./math"; + +export default (a, b, operator) => { + switch(operator) { + case '+': + return add(a, b); + case '-': + return subtract(a, b); + case '*': + return multiply(a, b); + case '/': + return divide(a, b); + default: + throw new Error('Invalid operator'); + } +}; diff --git a/plugins/code-coverage/dev/__fixtures__/file-content-math-js.txt b/plugins/code-coverage/dev/__fixtures__/file-content-math-js.txt new file mode 100644 index 0000000000..05f43438f5 --- /dev/null +++ b/plugins/code-coverage/dev/__fixtures__/file-content-math-js.txt @@ -0,0 +1,29 @@ +export function add(a, b) { + if (isNaN(a) || isNaN(b)) { + throw new Error('Invalid input'); + } + return a + b; +} + +export function subtract(a, b) { + if (isNaN(a) || isNaN(b)) { + throw new Error('Invalid input'); + } + return a - b; +} + +export function multiply(a, b) { + if (isNaN(a) || isNaN(b)) { + throw new Error('Invalid input'); + } + return a * b; +} + +export function divide(a, b) { + if (isNaN(a) || isNaN(b)) { + throw new Error('Invalid input'); + } else if (b === 0) { + throw new Error('Division by zero'); + } + return a / b; +} diff --git a/plugins/code-coverage/dev/__fixtures__/get-file-content-from-entity.ts b/plugins/code-coverage/dev/__fixtures__/get-file-content-from-entity.ts new file mode 100644 index 0000000000..9fea0997f7 --- /dev/null +++ b/plugins/code-coverage/dev/__fixtures__/get-file-content-from-entity.ts @@ -0,0 +1,64 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export default { + 'src/index.js': `import { add, multiply, subtract, divide } from \"./math\"; + +export default (a, b, operator) => { + switch(operator) { + case '+': + return add(a, b); + case '-': + return subtract(a, b); + case '*': + return multiply(a, b); + case '/': + return divide(a, b); + default: + throw new Error('Invalid operator'); + } +}; + `, + 'src/math.js': `export function add(a, b) { + if (isNaN(a) || isNaN(b)) { + throw new Error('Invalid input'); + } + return a + b; +} + +export function subtract(a, b) { + if (isNaN(a) || isNaN(b)) { + throw new Error('Invalid input'); + } + return a - b; +} + +export function multiply(a, b) { + if (isNaN(a) || isNaN(b)) { + throw new Error('Invalid input'); + } + return a * b; +} + +export function divide(a, b) { + if (isNaN(a) || isNaN(b)) { + throw new Error('Invalid input'); + } else if (b === 0) { + throw new Error('Division by zero'); + } + return a / b; +} + `, +}; diff --git a/plugins/code-coverage/dev/index.tsx b/plugins/code-coverage/dev/index.tsx index f364c2a0d1..e0c1ef7616 100644 --- a/plugins/code-coverage/dev/index.tsx +++ b/plugins/code-coverage/dev/index.tsx @@ -16,11 +16,65 @@ import React from 'react'; import { createDevApp } from '@backstage/dev-utils'; import { codeCoveragePlugin, EntityCodeCoverageContent } from '../src/plugin'; +import { CompoundEntityRef, Entity } from '@backstage/catalog-model'; +import { EntityProvider } from '@backstage/plugin-catalog-react'; +import { codeCoverageApiRef, CodeCoverageApi } from '../src/api'; +import coverageForEntity from './__fixtures__/coverage-for-entity.json'; +import coverageHistoryForEntity from './__fixtures__/coverage-history-for-entity.json'; +import fileContentFromEntity from './__fixtures__/get-file-content-from-entity'; + +const mockEntity: Entity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'backstage', + description: 'backstage.io', + annotations: { + 'backstage.io/code-coverage': 'enabled', + }, + }, + spec: { + lifecycle: 'production', + type: 'website', + owner: 'user:guest', + }, +}; + +const mockCodeCoverageApi: CodeCoverageApi = { + async getCoverageForEntity(_entity: CompoundEntityRef) { + return coverageForEntity as any; + }, + async getFileContentFromEntity(_entity: CompoundEntityRef, filePath: string) { + switch (filePath) { + case 'src/index.js': + return fileContentFromEntity['src/index.js']; + case 'src/math.js': + return fileContentFromEntity['src/math.js']; + default: + return ''; + } + }, + async getCoverageHistoryForEntity( + _entity: CompoundEntityRef, + _limit?: number, + ) { + return coverageHistoryForEntity; + }, +}; createDevApp() + .registerApi({ + api: codeCoverageApiRef, + deps: {}, + factory: () => mockCodeCoverageApi, + }) .registerPlugin(codeCoveragePlugin) .addPage({ - element: <EntityCodeCoverageContent />, + element: ( + <EntityProvider entity={mockEntity}> + <EntityCodeCoverageContent /> + </EntityProvider> + ), title: 'Root Page', }) .render(); diff --git a/plugins/code-coverage/package.json b/plugins/code-coverage/package.json index ede73b9506..f47a44221a 100644 --- a/plugins/code-coverage/package.json +++ b/plugins/code-coverage/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-code-coverage", "description": "A Backstage plugin that helps you keep track of your code coverage", - "version": "0.2.17", + "version": "0.2.18-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/code-coverage/src/components/CoverageHistoryChart/CoverageHistoryChart.tsx b/plugins/code-coverage/src/components/CoverageHistoryChart/CoverageHistoryChart.tsx index 1e5341eb50..09f499fafd 100644 --- a/plugins/code-coverage/src/components/CoverageHistoryChart/CoverageHistoryChart.tsx +++ b/plugins/code-coverage/src/components/CoverageHistoryChart/CoverageHistoryChart.tsx @@ -113,8 +113,8 @@ export const CoverageHistoryChart = () => { ); } - const oldestCoverage = valueHistory.history[0]; - const [latestCoverage] = valueHistory.history.slice(-1); + const [oldestCoverage] = valueHistory.history.slice(-1); + const latestCoverage = valueHistory.history[0]; const getTrendForCoverage = (type: Coverage) => { if (!oldestCoverage[type].percentage) { diff --git a/plugins/code-coverage/src/components/FileExplorer/CodeRow.tsx b/plugins/code-coverage/src/components/FileExplorer/CodeRow.tsx index c7dee55f2b..20f0548f16 100644 --- a/plugins/code-coverage/src/components/FileExplorer/CodeRow.tsx +++ b/plugins/code-coverage/src/components/FileExplorer/CodeRow.tsx @@ -41,9 +41,11 @@ const useStyles = makeStyles(theme => ({ }, hitCountRoundedRectangle: { backgroundColor: `${theme.palette.success.main}`, + color: `${theme.palette.success.contrastText}`, }, notHitCountRoundedRectangle: { backgroundColor: `${theme.palette.error.main}`, + color: `${theme.palette.error.contrastText}`, }, codeLine: { paddingLeft: `${theme.spacing(1)}`, @@ -52,9 +54,11 @@ const useStyles = makeStyles(theme => ({ }, hitCodeLine: { backgroundColor: `${theme.palette.success.main}`, + color: `${theme.palette.success.contrastText}`, }, notHitCodeLine: { backgroundColor: `${theme.palette.error.main}`, + color: `${theme.palette.error.contrastText}`, }, })); diff --git a/plugins/code-coverage/src/components/FileExplorer/FileExplorer.tsx b/plugins/code-coverage/src/components/FileExplorer/FileExplorer.tsx index 3d41a1ff64..4017ba8264 100644 --- a/plugins/code-coverage/src/components/FileExplorer/FileExplorer.tsx +++ b/plugins/code-coverage/src/components/FileExplorer/FileExplorer.tsx @@ -15,15 +15,9 @@ */ import { useEntity } from '@backstage/plugin-catalog-react'; -import { - Box, - Card, - CardContent, - CardHeader, - Modal, - Tooltip, -} from '@material-ui/core'; -import DescriptionIcon from '@material-ui/icons/Description'; +import { Box, Modal, makeStyles } from '@material-ui/core'; +import FolderIcon from '@material-ui/icons/Folder'; +import FileOutlinedIcon from '@material-ui/icons/InsertDriveFileOutlined'; import { Alert } from '@material-ui/lab'; import React, { Fragment, useEffect, useState } from 'react'; import useAsync from 'react-use/lib/useAsync'; @@ -38,6 +32,19 @@ import { } from '@backstage/core-components'; import { useApi } from '@backstage/core-plugin-api'; +const useStyles = makeStyles(theme => ({ + container: { + marginTop: theme.spacing(2), + }, + icon: { + marginRight: theme.spacing(1), + }, + link: { + color: theme.palette.primary.main, + cursor: 'pointer', + }, +})); + type FileStructureObject = Record<string, any>; type CoverageTableRow = { @@ -143,6 +150,7 @@ export const getObjectsAtPath = ( }; export const FileExplorer = () => { + const styles = useStyles(); const { entity } = useEntity(); const [curData, setCurData] = useState<CoverageTableRow | undefined>(); const [tableData, setTableData] = useState<CoverageTableRow[] | undefined>(); @@ -188,6 +196,7 @@ export const FileExplorer = () => { const moveUpIntoPath = (idx: number) => { const path = curPath.split('/').slice(0, idx + 1); + setCurFile(''); setCurPath(path.join('/')); setTableData(getObjectsAtPath(curData, path.slice(1))); }; @@ -197,43 +206,32 @@ export const FileExplorer = () => { title: 'Path', type: 'string', field: 'path', - render: (row: CoverageTableRow) => { - if (row.files?.length) { - return ( - <div - role="button" - tabIndex={row.tableData!.id} - style={{ color: 'lightblue', cursor: 'pointer' }} - onKeyDown={() => { - setCurPath(`${curPath}/${row.path}`); - moveDownIntoPath(row.path); - }} - onClick={() => { - setCurPath(`${curPath}/${row.path}`); - moveDownIntoPath(row.path); - }} - > - {row.path} - </div> - ); - } - - return ( - <Box display="flex" alignItems="center"> - {row.path} - <Tooltip title="View file content"> - <DescriptionIcon - fontSize="small" - style={{ color: 'lightblue', cursor: 'pointer' }} - onClick={() => { - setCurFile(`${curPath.slice(1)}/${row.path}`); - setModalOpen(true); - }} - /> - </Tooltip> - </Box> - ); - }, + render: (row: CoverageTableRow) => ( + <Box + display="flex" + alignItems="center" + role="button" + tabIndex={row.tableData!.id} + className={styles.link} + onClick={() => { + if (row.files?.length) { + setCurPath(`${curPath}/${row.path}`); + moveDownIntoPath(row.path); + } else { + setCurFile(`${curPath.slice(1)}/${row.path}`); + setModalOpen(true); + } + }} + > + {row.files?.length > 0 && ( + <FolderIcon fontSize="small" className={styles.icon} /> + )} + {row.files?.length === 0 && ( + <FileOutlinedIcon fontSize="small" className={styles.icon} /> + )} + {row.path} + </Box> + ), }, { title: 'Coverage', @@ -264,42 +262,50 @@ export const FileExplorer = () => { } return ( - <Card> - <CardHeader title="Explore Files" /> - <CardContent> - <Box mb={2} display="flex"> - {pathArray.map((pathElement, idx) => ( - <Fragment key={pathElement || 'root'}> - <div - role="button" - tabIndex={idx} - style={{ - color: `${idx !== lastPathElementIndex && 'lightblue'}`, - cursor: `${idx !== lastPathElementIndex && 'pointer'}`, - }} - onKeyDown={() => moveUpIntoPath(idx)} - onClick={() => moveUpIntoPath(idx)} - > - {pathElement || 'root'} - </div> - <div>{'\u00A0/\u00A0'}</div> - </Fragment> - ))} - </Box> - <Table - emptyContent={<>No files found</>} - data={tableData || []} - columns={columns} - /> - <Modal - open={modalOpen} - onClick={event => event.stopPropagation()} - onClose={() => setModalOpen(false)} - style={{ overflow: 'scroll' }} - > - <FileContent filename={curFile} coverage={fileCoverage} /> - </Modal> - </CardContent> - </Card> + <Box className={styles.container}> + <Table + emptyContent={<>No files found</>} + data={tableData || []} + columns={columns} + title={ + <> + <Box>Explore Files</Box> + <Box + mt={1} + style={{ + fontSize: '0.875rem', + fontWeight: 'normal', + display: 'flex', + }} + > + {pathArray.map((pathElement, idx) => ( + <Fragment key={pathElement || 'root'}> + <div + role="button" + tabIndex={idx} + className={ + idx !== lastPathElementIndex ? styles.link : undefined + } + onKeyDown={() => moveUpIntoPath(idx)} + onClick={() => moveUpIntoPath(idx)} + > + {pathElement || 'root'} + </div> + {idx !== lastPathElementIndex && <div>{'\u00A0/\u00A0'}</div>} + </Fragment> + ))} + </Box> + </> + } + /> + <Modal + open={modalOpen} + onClick={event => event.stopPropagation()} + onClose={() => setModalOpen(false)} + style={{ overflow: 'scroll' }} + > + <FileContent filename={curFile} coverage={fileCoverage} /> + </Modal> + </Box> ); }; diff --git a/plugins/code-coverage/src/components/FileExplorer/Highlighter.ts b/plugins/code-coverage/src/components/FileExplorer/Highlighter.ts index d97d147da3..465e43f6e4 100644 --- a/plugins/code-coverage/src/components/FileExplorer/Highlighter.ts +++ b/plugins/code-coverage/src/components/FileExplorer/Highlighter.ts @@ -14,8 +14,8 @@ * limitations under the License. */ -import 'highlight.js/styles/atom-one-dark.css'; -import highlight from 'highlight.js'; +import 'highlight.js/styles/mono-blue.css'; +import { highlight } from 'highlight.js'; /* * Given a file extension, repo name, and array of code lines, return a Promise resolving @@ -30,7 +30,6 @@ import highlight from 'highlight.js'; */ export const highlightLines = (fileExtension: string, lines: Array<string>) => { const formattedLines: Array<string> = []; - let state: CompiledMode | Language | undefined; let fileformat = fileExtension; if (fileExtension === 'm') { fileformat = 'objectivec'; @@ -46,8 +45,10 @@ export const highlightLines = (fileExtension: string, lines: Array<string>) => { } lines.forEach(line => { - const result = highlight.highlight(fileformat, line, true, state); - state = result.top; + const result = highlight(line, { + language: fileformat, + ignoreIllegals: true, + }); formattedLines.push(result.value); }); return formattedLines; diff --git a/plugins/codescene/CHANGELOG.md b/plugins/codescene/CHANGELOG.md index 57f5fe44a9..15f34acaf0 100644 --- a/plugins/codescene/CHANGELOG.md +++ b/plugins/codescene/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-codescene +## 0.1.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## 0.1.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + ## 0.1.17 ### Patch Changes diff --git a/plugins/codescene/api-report.md b/plugins/codescene/api-report.md index 662968d3c9..99eb2b6256 100644 --- a/plugins/codescene/api-report.md +++ b/plugins/codescene/api-report.md @@ -24,7 +24,6 @@ export const codescenePlugin: BackstagePlugin< projectId: string; }>; }, - {}, {} >; diff --git a/plugins/codescene/package.json b/plugins/codescene/package.json index a3a5564900..c57a9c53af 100644 --- a/plugins/codescene/package.json +++ b/plugins/codescene/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-codescene", - "version": "0.1.17", + "version": "0.1.18-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/config-schema/CHANGELOG.md b/plugins/config-schema/CHANGELOG.md index d6d03c1caf..2c2ac53154 100644 --- a/plugins/config-schema/CHANGELOG.md +++ b/plugins/config-schema/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-config-schema +## 0.1.46-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + +## 0.1.46-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + ## 0.1.45 ### Patch Changes diff --git a/plugins/config-schema/api-report.md b/plugins/config-schema/api-report.md index 95d352d1b7..16630ae8d0 100644 --- a/plugins/config-schema/api-report.md +++ b/plugins/config-schema/api-report.md @@ -29,7 +29,6 @@ export const configSchemaPlugin: BackstagePlugin< { root: RouteRef<undefined>; }, - {}, {} >; diff --git a/plugins/config-schema/package.json b/plugins/config-schema/package.json index ad642a4283..c623a59dfa 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.45", + "version": "0.1.46-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/cost-insights/CHANGELOG.md b/plugins/cost-insights/CHANGELOG.md index f74ae41fc0..a51c19f324 100644 --- a/plugins/cost-insights/CHANGELOG.md +++ b/plugins/cost-insights/CHANGELOG.md @@ -1,5 +1,33 @@ # @backstage/plugin-cost-insights +## 0.12.14-next.1 + +### Patch Changes + +- ba4820883c: Updated dependency `@types/pluralize` to `^0.0.31`. +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-cost-insights-common@0.1.2 + +## 0.12.14-next.0 + +### Patch Changes + +- 959aa2a09f: The experimental plugin configuration has been removed. The trend line can now instead be hidden by setting `costInsights.hideTrendLine` to `true` in the configuration. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-cost-insights-common@0.1.2 + ## 0.12.13 ### Patch Changes diff --git a/plugins/cost-insights/api-report.md b/plugins/cost-insights/api-report.md index b37804c93d..11cdbd8141 100644 --- a/plugins/cost-insights/api-report.md +++ b/plugins/cost-insights/api-report.md @@ -242,6 +242,7 @@ export type ConfigContextProps = { icons: Icon[]; engineerCost: number; engineerThreshold: number; + hideTrendLine: boolean; currencies: Currency[]; }; @@ -326,8 +327,7 @@ const costInsightsPlugin: BackstagePlugin< growthAlerts: RouteRef<undefined>; unlabeledDataflowAlerts: RouteRef<undefined>; }, - {}, - CostInsightsInputPluginOptions + {} >; export { costInsightsPlugin }; export { costInsightsPlugin as plugin }; diff --git a/plugins/cost-insights/config.d.ts b/plugins/cost-insights/config.d.ts index 61a54f76e2..786d6f5a59 100644 --- a/plugins/cost-insights/config.d.ts +++ b/plugins/cost-insights/config.d.ts @@ -26,6 +26,11 @@ export interface Config { */ engineerThreshold?: number; + /** + * @visibility frontend + */ + hideTrendLine?: boolean; + /** * @visibility frontend */ diff --git a/plugins/cost-insights/package.json b/plugins/cost-insights/package.json index 28f6ece59e..c204616fe4 100644 --- a/plugins/cost-insights/package.json +++ b/plugins/cost-insights/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-cost-insights", "description": "A Backstage plugin that helps you keep track of your cloud spend", - "version": "0.12.13", + "version": "0.12.14-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -70,7 +70,7 @@ "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", - "@types/pluralize": "^0.0.30", + "@types/pluralize": "^0.0.31", "@types/recharts": "^1.8.14", "@types/regression": "^2.0.0", "@types/yup": "^0.29.13", diff --git a/plugins/cost-insights/src/components/CostOverviewCard/CostOverviewCard.test.tsx b/plugins/cost-insights/src/components/CostOverviewCard/CostOverviewCard.test.tsx index d4fdc66bdb..2250392355 100644 --- a/plugins/cost-insights/src/components/CostOverviewCard/CostOverviewCard.test.tsx +++ b/plugins/cost-insights/src/components/CostOverviewCard/CostOverviewCard.test.tsx @@ -15,7 +15,6 @@ */ import React from 'react'; import { fireEvent } from '@testing-library/react'; -import { MockPluginProvider } from '@backstage/test-utils/alpha'; import { renderInTestApp } from '@backstage/test-utils'; import { CostOverviewCard } from './CostOverviewCard'; import { Cost } from '@backstage/plugin-cost-insights-common'; @@ -45,9 +44,7 @@ function renderInContext(children: JSX.Element) { <MockConfigProvider> <MockFilterProvider> <MockBillingDateProvider> - <MockScrollProvider> - <MockPluginProvider>{children}</MockPluginProvider> - </MockScrollProvider> + <MockScrollProvider>{children}</MockScrollProvider> </MockBillingDateProvider> </MockFilterProvider> </MockConfigProvider> diff --git a/plugins/cost-insights/src/components/CostOverviewCard/CostOverviewChart.tsx b/plugins/cost-insights/src/components/CostOverviewCard/CostOverviewChart.tsx index ce0623cc7e..2201dcc650 100644 --- a/plugins/cost-insights/src/components/CostOverviewCard/CostOverviewChart.tsx +++ b/plugins/cost-insights/src/components/CostOverviewCard/CostOverviewChart.tsx @@ -47,7 +47,6 @@ import { groupByDate, trendFrom } from '../../utils/charts'; import { aggregationSort } from '../../utils/sort'; import { CostOverviewLegend } from './CostOverviewLegend'; import { TooltipRenderer } from '../../types'; -import { useCostInsightsOptions } from '../../options'; import { useConfig } from '../../hooks'; type CostOverviewChartProps = { @@ -65,7 +64,7 @@ export const CostOverviewChart = ({ }: CostOverviewChartProps) => { const theme = useTheme<CostInsightsTheme>(); const styles = useStyles(theme); - const { baseCurrency } = useConfig(); + const { baseCurrency, hideTrendLine } = useConfig(); const data = { dailyCost: { @@ -134,7 +133,6 @@ export const CostOverviewChart = ({ ); }; - const { hideTrendLine } = useCostInsightsOptions(); const localizedTickFormatter = formatGraphValue(baseCurrency); return ( diff --git a/plugins/cost-insights/src/components/EntityCosts/EntityCost.test.tsx b/plugins/cost-insights/src/components/EntityCosts/EntityCost.test.tsx index 6eb3369b40..6ad7285ab9 100644 --- a/plugins/cost-insights/src/components/EntityCosts/EntityCost.test.tsx +++ b/plugins/cost-insights/src/components/EntityCosts/EntityCost.test.tsx @@ -14,7 +14,6 @@ * limitations under the License. */ import React from 'react'; -import { MockPluginProvider } from '@backstage/test-utils/alpha'; import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; import { changeOf, @@ -65,9 +64,7 @@ function renderInContext(children: JSX.Element) { <MockFilterProvider> <MockBillingDateProvider> <MockScrollProvider> - <MockScrollProvider> - <MockPluginProvider>{children}</MockPluginProvider> - </MockScrollProvider> + <MockScrollProvider>{children}</MockScrollProvider> </MockScrollProvider> </MockBillingDateProvider> </MockFilterProvider> diff --git a/plugins/cost-insights/src/hooks/useConfig.tsx b/plugins/cost-insights/src/hooks/useConfig.tsx index f42cea38c3..82c0ce26f5 100644 --- a/plugins/cost-insights/src/hooks/useConfig.tsx +++ b/plugins/cost-insights/src/hooks/useConfig.tsx @@ -72,6 +72,7 @@ export type ConfigContextProps = { icons: Icon[]; engineerCost: number; engineerThreshold: number; + hideTrendLine: boolean; currencies: Currency[]; }; @@ -86,6 +87,7 @@ const defaultState: ConfigContextProps = { icons: [], engineerCost: 0, engineerThreshold: EngineerThreshold, + hideTrendLine: false, currencies: defaultCurrencies, }; @@ -193,12 +195,20 @@ export const ConfigProvider = ({ children }: PropsWithChildren<{}>) => { ); } + function getHideTrendLine(): boolean { + return ( + c.getOptionalBoolean('costInsights.hideTrendLine') ?? + defaultState.hideTrendLine + ); + } + function getConfig() { const baseCurrency = getBaseCurrency(); const products = getProducts(); const metrics = getMetrics(); const engineerCost = getEngineerCost(); const engineerThreshold = getEngineerThreshold(); + const hideTrendLine = getHideTrendLine(); const icons = getIcons(); const currencies = getCurrencies(); @@ -212,6 +222,7 @@ export const ConfigProvider = ({ children }: PropsWithChildren<{}>) => { products, engineerCost, engineerThreshold, + hideTrendLine, icons, currencies, })); diff --git a/plugins/cost-insights/src/plugin.ts b/plugins/cost-insights/src/plugin.ts index c863c9e03a..04d58d1877 100644 --- a/plugins/cost-insights/src/plugin.ts +++ b/plugins/cost-insights/src/plugin.ts @@ -19,10 +19,6 @@ import { createRouteRef, createRoutableExtension, } from '@backstage/core-plugin-api'; -import { - CostInsightsInputPluginOptions, - CostInsightsPluginOptions, -} from './options'; export const rootRouteRef = createRouteRef({ id: 'cost-insights', @@ -45,14 +41,6 @@ export const costInsightsPlugin = createPlugin({ growthAlerts: projectGrowthAlertRef, unlabeledDataflowAlerts: unlabeledDataflowAlertRef, }, - __experimentalConfigure( - options?: CostInsightsInputPluginOptions, - ): CostInsightsPluginOptions { - const defaultOptions = { - hideTrendLine: false, - }; - return { ...defaultOptions, ...options }; - }, }); /** @public */ diff --git a/plugins/cost-insights/src/testUtils/providers.tsx b/plugins/cost-insights/src/testUtils/providers.tsx index 9522dfb702..5df1b2512f 100644 --- a/plugins/cost-insights/src/testUtils/providers.tsx +++ b/plugins/cost-insights/src/testUtils/providers.tsx @@ -96,6 +96,7 @@ export const MockConfigProvider = (props: MockConfigProviderProps) => { icons: [], engineerCost: 0, engineerThreshold: EngineerThreshold, + hideTrendLine: false, currencies: [], }; diff --git a/plugins/devtools-backend/CHANGELOG.md b/plugins/devtools-backend/CHANGELOG.md index 7d679b0aa6..7fc9c01be5 100644 --- a/plugins/devtools-backend/CHANGELOG.md +++ b/plugins/devtools-backend/CHANGELOG.md @@ -1,5 +1,39 @@ # @backstage/plugin-devtools-backend +## 0.2.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/plugin-permission-node@0.7.16-next.1 + - @backstage/config@1.1.0 + - @backstage/cli-common@0.1.13-next.0 + - @backstage/config-loader@1.5.1-next.0 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.4 + - @backstage/plugin-permission-common@0.7.8 + +## 0.2.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/config-loader@1.5.1-next.0 + - @backstage/cli-common@0.1.13-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.4 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-permission-node@0.7.16-next.0 + ## 0.2.0 ### Minor Changes diff --git a/plugins/devtools-backend/package.json b/plugins/devtools-backend/package.json index e8a3d5b151..f5311f9cf3 100644 --- a/plugins/devtools-backend/package.json +++ b/plugins/devtools-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-devtools-backend", - "version": "0.2.0", + "version": "0.2.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/devtools/CHANGELOG.md b/plugins/devtools/CHANGELOG.md index 2585103b45..b858ff2c61 100644 --- a/plugins/devtools/CHANGELOG.md +++ b/plugins/devtools/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/plugin-devtools +## 0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/plugin-permission-react@0.4.16-next.0 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.4 + +## 0.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/plugin-permission-react@0.4.16-next.0 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.4 + ## 0.1.4 ### Patch Changes diff --git a/plugins/devtools/api-report.md b/plugins/devtools/api-report.md index f0a9280162..21754d7c1e 100644 --- a/plugins/devtools/api-report.md +++ b/plugins/devtools/api-report.md @@ -36,7 +36,6 @@ export const devToolsPlugin: BackstagePlugin< { root: RouteRef<undefined>; }, - {}, {} >; diff --git a/plugins/devtools/package.json b/plugins/devtools/package.json index 44010775a8..62ba643765 100644 --- a/plugins/devtools/package.json +++ b/plugins/devtools/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-devtools", - "version": "0.1.4", + "version": "0.1.5-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/dynatrace/CHANGELOG.md b/plugins/dynatrace/CHANGELOG.md index 33ddc90338..dc1c8cd54d 100644 --- a/plugins/dynatrace/CHANGELOG.md +++ b/plugins/dynatrace/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-dynatrace +## 7.0.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## 7.0.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + ## 7.0.4 ### Patch Changes diff --git a/plugins/dynatrace/api-report.md b/plugins/dynatrace/api-report.md index 0f25fc3108..f78b4060fd 100644 --- a/plugins/dynatrace/api-report.md +++ b/plugins/dynatrace/api-report.md @@ -10,7 +10,7 @@ import { Entity } from '@backstage/catalog-model'; import { JSX as JSX_2 } from 'react'; // @public -export const dynatracePlugin: BackstagePlugin<{}, {}, {}>; +export const dynatracePlugin: BackstagePlugin<{}, {}>; // @public export const DynatraceTab: () => JSX_2.Element; diff --git a/plugins/dynatrace/package.json b/plugins/dynatrace/package.json index 663744a454..83395cabb8 100644 --- a/plugins/dynatrace/package.json +++ b/plugins/dynatrace/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-dynatrace", - "version": "7.0.4", + "version": "7.0.5-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/entity-feedback-backend/CHANGELOG.md b/plugins/entity-feedback-backend/CHANGELOG.md index ac9527c416..8c0b27d2aa 100644 --- a/plugins/entity-feedback-backend/CHANGELOG.md +++ b/plugins/entity-feedback-backend/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/plugin-entity-feedback-backend +## 0.2.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## 0.2.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/plugin-entity-feedback-common@0.1.3 + ## 0.2.0 ### Minor Changes diff --git a/plugins/entity-feedback-backend/package.json b/plugins/entity-feedback-backend/package.json index 41d33eb896..320748501f 100644 --- a/plugins/entity-feedback-backend/package.json +++ b/plugins/entity-feedback-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-entity-feedback-backend", - "version": "0.2.0", + "version": "0.2.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/entity-feedback/CHANGELOG.md b/plugins/entity-feedback/CHANGELOG.md index c470784b86..c5ead7f611 100644 --- a/plugins/entity-feedback/CHANGELOG.md +++ b/plugins/entity-feedback/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/plugin-entity-feedback +## 0.2.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## 0.2.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-entity-feedback-common@0.1.3 + ## 0.2.7 ### Patch Changes diff --git a/plugins/entity-feedback/api-report.md b/plugins/entity-feedback/api-report.md index d61394ab9a..27e56e5282 100644 --- a/plugins/entity-feedback/api-report.md +++ b/plugins/entity-feedback/api-report.md @@ -70,7 +70,6 @@ export const entityFeedbackPlugin: BackstagePlugin< { root: RouteRef<undefined>; }, - {}, {} >; diff --git a/plugins/entity-feedback/package.json b/plugins/entity-feedback/package.json index b8f2333ad4..b04e438e34 100644 --- a/plugins/entity-feedback/package.json +++ b/plugins/entity-feedback/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-entity-feedback", - "version": "0.2.7", + "version": "0.2.8-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/entity-validation/CHANGELOG.md b/plugins/entity-validation/CHANGELOG.md index a975bdba54..0cb48bd911 100644 --- a/plugins/entity-validation/CHANGELOG.md +++ b/plugins/entity-validation/CHANGELOG.md @@ -1,5 +1,33 @@ # @backstage/plugin-entity-validation +## 0.1.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-catalog-common@1.0.16 + +## 0.1.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-catalog-common@1.0.16 + ## 0.1.9 ### Patch Changes diff --git a/plugins/entity-validation/api-report.md b/plugins/entity-validation/api-report.md index 48b309cfaa..9d69458ed0 100644 --- a/plugins/entity-validation/api-report.md +++ b/plugins/entity-validation/api-report.md @@ -20,7 +20,6 @@ export const entityValidationPlugin: BackstagePlugin< { root: RouteRef<undefined>; }, - {}, {} >; diff --git a/plugins/entity-validation/package.json b/plugins/entity-validation/package.json index 1a17875970..5f8368aeb0 100644 --- a/plugins/entity-validation/package.json +++ b/plugins/entity-validation/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-entity-validation", - "version": "0.1.9", + "version": "0.1.10-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/events-backend-module-aws-sqs/CHANGELOG.md b/plugins/events-backend-module-aws-sqs/CHANGELOG.md index e79d836d49..c45de40839 100644 --- a/plugins/events-backend-module-aws-sqs/CHANGELOG.md +++ b/plugins/events-backend-module-aws-sqs/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-events-backend-module-aws-sqs +## 0.2.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.2.14-next.1 + +## 0.2.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.2.14-next.0 + ## 0.2.6 ### Patch Changes diff --git a/plugins/events-backend-module-aws-sqs/package.json b/plugins/events-backend-module-aws-sqs/package.json index b3f0d379c2..c9825edbff 100644 --- a/plugins/events-backend-module-aws-sqs/package.json +++ b/plugins/events-backend-module-aws-sqs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-aws-sqs", - "version": "0.2.6", + "version": "0.2.8-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/events-backend-module-azure/CHANGELOG.md b/plugins/events-backend-module-azure/CHANGELOG.md index 5289fdb465..4883d87b10 100644 --- a/plugins/events-backend-module-azure/CHANGELOG.md +++ b/plugins/events-backend-module-azure/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-events-backend-module-azure +## 0.1.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-events-node@0.2.14-next.1 + +## 0.1.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/plugin-events-node@0.2.14-next.0 + ## 0.1.13 ### Patch Changes diff --git a/plugins/events-backend-module-azure/package.json b/plugins/events-backend-module-azure/package.json index 9cb0ff81c1..18d712e5c4 100644 --- a/plugins/events-backend-module-azure/package.json +++ b/plugins/events-backend-module-azure/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-azure", - "version": "0.1.13", + "version": "0.1.15-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md b/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md index c21e46c15b..21b4e7e6ca 100644 --- a/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md +++ b/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-events-backend-module-bitbucket-cloud +## 0.1.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-events-node@0.2.14-next.1 + +## 0.1.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/plugin-events-node@0.2.14-next.0 + ## 0.1.13 ### Patch Changes diff --git a/plugins/events-backend-module-bitbucket-cloud/package.json b/plugins/events-backend-module-bitbucket-cloud/package.json index d5918731d1..5d6563e8b6 100644 --- a/plugins/events-backend-module-bitbucket-cloud/package.json +++ b/plugins/events-backend-module-bitbucket-cloud/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-bitbucket-cloud", - "version": "0.1.13", + "version": "0.1.15-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/events-backend-module-gerrit/CHANGELOG.md b/plugins/events-backend-module-gerrit/CHANGELOG.md index d09472671a..aa368e48e4 100644 --- a/plugins/events-backend-module-gerrit/CHANGELOG.md +++ b/plugins/events-backend-module-gerrit/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-events-backend-module-gerrit +## 0.1.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-events-node@0.2.14-next.1 + +## 0.1.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/plugin-events-node@0.2.14-next.0 + ## 0.1.13 ### Patch Changes diff --git a/plugins/events-backend-module-gerrit/package.json b/plugins/events-backend-module-gerrit/package.json index 9cc5f77e20..9b05753c42 100644 --- a/plugins/events-backend-module-gerrit/package.json +++ b/plugins/events-backend-module-gerrit/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-gerrit", - "version": "0.1.13", + "version": "0.1.15-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/events-backend-module-github/CHANGELOG.md b/plugins/events-backend-module-github/CHANGELOG.md index 0fa5c1e73a..16979ed40b 100644 --- a/plugins/events-backend-module-github/CHANGELOG.md +++ b/plugins/events-backend-module-github/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-events-backend-module-github +## 0.1.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/plugin-events-node@0.2.14-next.1 + +## 0.1.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/plugin-events-node@0.2.14-next.0 + ## 0.1.13 ### Patch Changes diff --git a/plugins/events-backend-module-github/package.json b/plugins/events-backend-module-github/package.json index ac94f83f41..c6cce93bda 100644 --- a/plugins/events-backend-module-github/package.json +++ b/plugins/events-backend-module-github/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-github", - "version": "0.1.13", + "version": "0.1.15-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/events-backend-module-gitlab/CHANGELOG.md b/plugins/events-backend-module-gitlab/CHANGELOG.md index 137f700504..24f8a1c574 100644 --- a/plugins/events-backend-module-gitlab/CHANGELOG.md +++ b/plugins/events-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-events-backend-module-gitlab +## 0.1.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/plugin-events-node@0.2.14-next.1 + +## 0.1.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/plugin-events-node@0.2.14-next.0 + ## 0.1.13 ### Patch Changes diff --git a/plugins/events-backend-module-gitlab/package.json b/plugins/events-backend-module-gitlab/package.json index 367ff8caf2..7e7ca5eb31 100644 --- a/plugins/events-backend-module-gitlab/package.json +++ b/plugins/events-backend-module-gitlab/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-gitlab", - "version": "0.1.13", + "version": "0.1.15-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/events-backend-test-utils/CHANGELOG.md b/plugins/events-backend-test-utils/CHANGELOG.md index de26b9b864..6df0dc6a05 100644 --- a/plugins/events-backend-test-utils/CHANGELOG.md +++ b/plugins/events-backend-test-utils/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-events-backend-test-utils +## 0.1.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.2.14-next.1 + +## 0.1.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.2.14-next.0 + ## 0.1.13 ### Patch Changes diff --git a/plugins/events-backend-test-utils/package.json b/plugins/events-backend-test-utils/package.json index e749eecc28..9d09d999f4 100644 --- a/plugins/events-backend-test-utils/package.json +++ b/plugins/events-backend-test-utils/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-events-backend-test-utils", "description": "The plugin-events-backend-test-utils for @backstage/plugin-events-node", - "version": "0.1.13", + "version": "0.1.15-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/events-backend/CHANGELOG.md b/plugins/events-backend/CHANGELOG.md index 64fb6da65a..9810584a6b 100644 --- a/plugins/events-backend/CHANGELOG.md +++ b/plugins/events-backend/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-events-backend +## 0.2.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/plugin-events-node@0.2.14-next.1 + +## 0.2.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/plugin-events-node@0.2.14-next.0 + ## 0.2.12 ### Patch Changes diff --git a/plugins/events-backend/package.json b/plugins/events-backend/package.json index 135971b91f..03028ae833 100644 --- a/plugins/events-backend/package.json +++ b/plugins/events-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend", - "version": "0.2.12", + "version": "0.2.14-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/events-node/CHANGELOG.md b/plugins/events-node/CHANGELOG.md index e458e3e1e8..607651ad73 100644 --- a/plugins/events-node/CHANGELOG.md +++ b/plugins/events-node/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-events-node +## 0.2.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.5-next.1 + +## 0.2.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.5-next.0 + ## 0.2.12 ### Patch Changes diff --git a/plugins/events-node/package.json b/plugins/events-node/package.json index 2a27e1c200..762b5237b0 100644 --- a/plugins/events-node/package.json +++ b/plugins/events-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-events-node", "description": "The plugin-events-node module for @backstage/plugin-events-backend", - "version": "0.2.12", + "version": "0.2.14-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/example-todo-list-backend/CHANGELOG.md b/plugins/example-todo-list-backend/CHANGELOG.md index 9518234111..8c1c37256d 100644 --- a/plugins/example-todo-list-backend/CHANGELOG.md +++ b/plugins/example-todo-list-backend/CHANGELOG.md @@ -1,5 +1,27 @@ # @internal/plugin-todo-list-backend +## 1.0.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + +## 1.0.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/errors@1.2.2 + ## 1.0.17 ### Patch Changes diff --git a/plugins/example-todo-list-backend/package.json b/plugins/example-todo-list-backend/package.json index 27a8536c7d..3a3a38a5c4 100644 --- a/plugins/example-todo-list-backend/package.json +++ b/plugins/example-todo-list-backend/package.json @@ -1,6 +1,6 @@ { "name": "@internal/plugin-todo-list-backend", - "version": "1.0.17", + "version": "1.0.18-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/example-todo-list/CHANGELOG.md b/plugins/example-todo-list/CHANGELOG.md index 5ec4c4ea8e..04243ee26a 100644 --- a/plugins/example-todo-list/CHANGELOG.md +++ b/plugins/example-todo-list/CHANGELOG.md @@ -1,5 +1,23 @@ # @internal/plugin-todo-list +## 1.0.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/theme@0.4.2 + +## 1.0.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/theme@0.4.2 + ## 1.0.17 ### Patch Changes diff --git a/plugins/example-todo-list/api-report.md b/plugins/example-todo-list/api-report.md index 1b7aa49a19..2feeeb903d 100644 --- a/plugins/example-todo-list/api-report.md +++ b/plugins/example-todo-list/api-report.md @@ -17,7 +17,6 @@ export const todoListPlugin: BackstagePlugin< { root: RouteRef<undefined>; }, - {}, {} >; diff --git a/plugins/example-todo-list/package.json b/plugins/example-todo-list/package.json index e61aaace42..589689a59c 100644 --- a/plugins/example-todo-list/package.json +++ b/plugins/example-todo-list/package.json @@ -1,6 +1,6 @@ { "name": "@internal/plugin-todo-list", - "version": "1.0.17", + "version": "1.0.18-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/explore-backend/CHANGELOG.md b/plugins/explore-backend/CHANGELOG.md index 3baae5db72..4e27d8f124 100644 --- a/plugins/explore-backend/CHANGELOG.md +++ b/plugins/explore-backend/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-explore-backend +## 0.0.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/plugin-search-backend-module-explore@0.1.9-next.1 + - @backstage/config@1.1.0 + - @backstage/types@1.1.1 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-common@1.2.6 + +## 0.0.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/types@1.1.1 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-backend-module-explore@0.1.9-next.0 + - @backstage/plugin-search-common@1.2.6 + ## 0.0.13 ### Patch Changes diff --git a/plugins/explore-backend/package.json b/plugins/explore-backend/package.json index 50e179a4b9..1e8a4a456b 100644 --- a/plugins/explore-backend/package.json +++ b/plugins/explore-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-explore-backend", - "version": "0.0.13", + "version": "0.0.15-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/explore-react/CHANGELOG.md b/plugins/explore-react/CHANGELOG.md index 708876c580..6d45e9a689 100644 --- a/plugins/explore-react/CHANGELOG.md +++ b/plugins/explore-react/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-explore-react +## 0.0.32-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/plugin-explore-common@0.0.2 + ## 0.0.31 ### Patch Changes diff --git a/plugins/explore-react/package.json b/plugins/explore-react/package.json index 09edad02d9..9282573a38 100644 --- a/plugins/explore-react/package.json +++ b/plugins/explore-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-explore-react", "description": "A frontend library for Backstage plugins that want to interact with the explore plugin", - "version": "0.0.31", + "version": "0.0.32-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/explore/CHANGELOG.md b/plugins/explore/CHANGELOG.md index 5ddd9c74ad..480d85437d 100644 --- a/plugins/explore/CHANGELOG.md +++ b/plugins/explore/CHANGELOG.md @@ -1,5 +1,39 @@ # @backstage/plugin-explore +## 0.4.11-next.1 + +### Patch Changes + +- 0f10c53a05: Create an experimental `ExploreSearchResultItemExtension` for declarative integration with Backstage; it can be accessed via the `/alpha` import. +- Updated dependencies + - @backstage/frontend-plugin-api@0.1.1-next.1 + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-search-react@1.7.1-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/plugin-explore-react@0.0.32-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-common@1.2.6 + +## 0.4.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/plugin-explore-react@0.0.32-next.0 + - @backstage/plugin-search-react@1.7.1-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-common@1.2.6 + ## 0.4.10 ### Patch Changes diff --git a/plugins/explore/alpha-api-report.md b/plugins/explore/alpha-api-report.md new file mode 100644 index 0000000000..3d6e527629 --- /dev/null +++ b/plugins/explore/alpha-api-report.md @@ -0,0 +1,19 @@ +## API Report File for "@backstage/plugin-explore" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { BackstagePlugin } from '@backstage/frontend-plugin-api'; +import { Extension } from '@backstage/frontend-plugin-api'; + +// @alpha (undocumented) +const _default: BackstagePlugin; +export default _default; + +// @alpha (undocumented) +export const ExploreSearchResultListItemExtension: Extension<{ + noTrack?: boolean | undefined; +}>; + +// (No @packageDocumentation comment for this package) +``` diff --git a/plugins/explore/api-report.md b/plugins/explore/api-report.md index 193efb044d..d32a133685 100644 --- a/plugins/explore/api-report.md +++ b/plugins/explore/api-report.md @@ -99,8 +99,7 @@ const explorePlugin: BackstagePlugin< }, true >; - }, - {} + } >; export { explorePlugin }; export { explorePlugin as plugin }; diff --git a/plugins/explore/package.json b/plugins/explore/package.json index 1ac3ab6393..0462d60884 100644 --- a/plugins/explore/package.json +++ b/plugins/explore/package.json @@ -1,14 +1,27 @@ { "name": "@backstage/plugin-explore", "description": "A Backstage plugin for building an exploration page of your software ecosystem", - "version": "0.4.10", + "version": "0.4.11-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", "publishConfig": { - "access": "public", - "main": "dist/index.esm.js", - "types": "dist/index.d.ts" + "access": "public" + }, + "exports": { + ".": "./src/index.ts", + "./alpha": "./src/alpha.tsx", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "alpha": [ + "src/alpha.tsx" + ], + "package.json": [ + "package.json" + ] + } }, "backstage": { "role": "frontend-plugin" @@ -37,6 +50,7 @@ "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/errors": "workspace:^", + "@backstage/frontend-plugin-api": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", "@backstage/plugin-explore-common": "workspace:^", "@backstage/plugin-explore-react": "workspace:^", diff --git a/plugins/explore/src/alpha.tsx b/plugins/explore/src/alpha.tsx new file mode 100644 index 0000000000..1825af5ddb --- /dev/null +++ b/plugins/explore/src/alpha.tsx @@ -0,0 +1,35 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createPlugin } from '@backstage/frontend-plugin-api'; +import { createSearchResultListItemExtension } from '@backstage/plugin-search-react/alpha'; + +/** @alpha */ +export const ExploreSearchResultListItemExtension = + createSearchResultListItemExtension({ + id: 'explore', + predicate: result => result.type === 'tools', + component: () => + import('./components/ToolSearchResultListItem').then( + m => m.ToolSearchResultListItem, + ), + }); + +/** @alpha */ +export default createPlugin({ + id: 'explore', + extensions: [ExploreSearchResultListItemExtension], +}); diff --git a/plugins/firehydrant/CHANGELOG.md b/plugins/firehydrant/CHANGELOG.md index 2e5fd2ac0f..b1694c6717 100644 --- a/plugins/firehydrant/CHANGELOG.md +++ b/plugins/firehydrant/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-firehydrant +## 0.2.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## 0.2.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + ## 0.2.8 ### Patch Changes diff --git a/plugins/firehydrant/api-report.md b/plugins/firehydrant/api-report.md index 76ccd8f019..9eeac41576 100644 --- a/plugins/firehydrant/api-report.md +++ b/plugins/firehydrant/api-report.md @@ -18,7 +18,6 @@ export const firehydrantPlugin: BackstagePlugin< { root: RouteRef<undefined>; }, - {}, {} >; diff --git a/plugins/firehydrant/package.json b/plugins/firehydrant/package.json index f94732dd23..31848ee464 100644 --- a/plugins/firehydrant/package.json +++ b/plugins/firehydrant/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-firehydrant", "description": "A Backstage plugin that integrates towards FireHydrant", - "version": "0.2.8", + "version": "0.2.9-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/fossa/CHANGELOG.md b/plugins/fossa/CHANGELOG.md index 70330dd55a..68a526db00 100644 --- a/plugins/fossa/CHANGELOG.md +++ b/plugins/fossa/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-fossa +## 0.2.57-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## 0.2.57-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + ## 0.2.56 ### Patch Changes diff --git a/plugins/fossa/api-report.md b/plugins/fossa/api-report.md index ac76ff6af6..6be878d434 100644 --- a/plugins/fossa/api-report.md +++ b/plugins/fossa/api-report.md @@ -31,7 +31,6 @@ export const fossaPlugin: BackstagePlugin< { fossaOverview: RouteRef<undefined>; }, - {}, {} >; ``` diff --git a/plugins/fossa/package.json b/plugins/fossa/package.json index b2eba4ece9..7fbe7e5570 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.56", + "version": "0.2.57-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/gcalendar/CHANGELOG.md b/plugins/gcalendar/CHANGELOG.md index 7eaeed8bf6..3e479c9bc4 100644 --- a/plugins/gcalendar/CHANGELOG.md +++ b/plugins/gcalendar/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-gcalendar +## 0.3.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## 0.3.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + ## 0.3.18 ### Patch Changes diff --git a/plugins/gcalendar/api-report.md b/plugins/gcalendar/api-report.md index 3f1d42d239..f1f505fc9a 100644 --- a/plugins/gcalendar/api-report.md +++ b/plugins/gcalendar/api-report.md @@ -51,7 +51,6 @@ export const gcalendarPlugin: BackstagePlugin< { root: RouteRef<undefined>; }, - {}, {} >; diff --git a/plugins/gcalendar/package.json b/plugins/gcalendar/package.json index c94f635e30..be9b02d4cc 100644 --- a/plugins/gcalendar/package.json +++ b/plugins/gcalendar/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-gcalendar", - "version": "0.3.18", + "version": "0.3.19-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/gcp-projects/CHANGELOG.md b/plugins/gcp-projects/CHANGELOG.md index d79cc5cbef..69584e9c89 100644 --- a/plugins/gcp-projects/CHANGELOG.md +++ b/plugins/gcp-projects/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-gcp-projects +## 0.3.42-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/theme@0.4.2 + +## 0.3.42-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/theme@0.4.2 + ## 0.3.41 ### Patch Changes diff --git a/plugins/gcp-projects/api-report.md b/plugins/gcp-projects/api-report.md index fd156687c0..e6938485fc 100644 --- a/plugins/gcp-projects/api-report.md +++ b/plugins/gcp-projects/api-report.md @@ -48,7 +48,6 @@ const gcpProjectsPlugin: BackstagePlugin< { root: RouteRef<undefined>; }, - {}, {} >; export { gcpProjectsPlugin }; diff --git a/plugins/gcp-projects/package.json b/plugins/gcp-projects/package.json index 3f26a0eeab..888f2c7a16 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.41", + "version": "0.3.42-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/git-release-manager/CHANGELOG.md b/plugins/git-release-manager/CHANGELOG.md index 0d2ce7cd6b..10c0d6770a 100644 --- a/plugins/git-release-manager/CHANGELOG.md +++ b/plugins/git-release-manager/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-git-release-manager +## 0.3.38-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/integration@1.7.1-next.0 + - @backstage/theme@0.4.2 + +## 0.3.38-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/theme@0.4.2 + ## 0.3.37 ### Patch Changes diff --git a/plugins/git-release-manager/api-report.md b/plugins/git-release-manager/api-report.md index a3215041f0..3e4c0847a7 100644 --- a/plugins/git-release-manager/api-report.md +++ b/plugins/git-release-manager/api-report.md @@ -263,7 +263,6 @@ export const gitReleaseManagerPlugin: BackstagePlugin< { root: RouteRef<undefined>; }, - {}, {} >; diff --git a/plugins/git-release-manager/package.json b/plugins/git-release-manager/package.json index 1085649e35..869d39633d 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.37", + "version": "0.3.38-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/github-actions/CHANGELOG.md b/plugins/github-actions/CHANGELOG.md index e1ba36001e..e4bea23a68 100644 --- a/plugins/github-actions/CHANGELOG.md +++ b/plugins/github-actions/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/plugin-github-actions +## 0.6.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/integration-react@1.1.20-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/theme@0.4.2 + +## 0.6.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/integration-react@1.1.20-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + ## 0.6.5 ### Patch Changes diff --git a/plugins/github-actions/api-report.md b/plugins/github-actions/api-report.md index e7c6114c93..887556f431 100644 --- a/plugins/github-actions/api-report.md +++ b/plugins/github-actions/api-report.md @@ -177,7 +177,6 @@ const githubActionsPlugin: BackstagePlugin< { entityContent: RouteRef<undefined>; }, - {}, {} >; export { githubActionsPlugin }; diff --git a/plugins/github-actions/package.json b/plugins/github-actions/package.json index 26e6f45211..fa273363c9 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.6.5", + "version": "0.6.6-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/github-deployments/CHANGELOG.md b/plugins/github-deployments/CHANGELOG.md index 949f6c6f7c..637bb2ca7f 100644 --- a/plugins/github-deployments/CHANGELOG.md +++ b/plugins/github-deployments/CHANGELOG.md @@ -1,5 +1,33 @@ # @backstage/plugin-github-deployments +## 0.1.56-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/integration-react@1.1.20-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/theme@0.4.2 + +## 0.1.56-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/integration-react@1.1.20-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + ## 0.1.55 ### Patch Changes diff --git a/plugins/github-deployments/api-report.md b/plugins/github-deployments/api-report.md index 669bcd74ba..26bb108d86 100644 --- a/plugins/github-deployments/api-report.md +++ b/plugins/github-deployments/api-report.md @@ -43,7 +43,7 @@ export type GithubDeployment = { }; // @public (undocumented) -export const githubDeploymentsPlugin: BackstagePlugin<{}, {}, {}>; +export const githubDeploymentsPlugin: BackstagePlugin<{}, {}>; // @public (undocumented) export const GithubDeploymentsTable: { diff --git a/plugins/github-deployments/package.json b/plugins/github-deployments/package.json index 564b20a948..edd3b6ff0e 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.55", + "version": "0.1.56-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/github-issues/CHANGELOG.md b/plugins/github-issues/CHANGELOG.md index f38c9ba630..e6a848c39d 100644 --- a/plugins/github-issues/CHANGELOG.md +++ b/plugins/github-issues/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/plugin-github-issues +## 0.2.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/theme@0.4.2 + +## 0.2.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + ## 0.2.13 ### Patch Changes diff --git a/plugins/github-issues/api-report.md b/plugins/github-issues/api-report.md index 3c7b616f82..0efa863a01 100644 --- a/plugins/github-issues/api-report.md +++ b/plugins/github-issues/api-report.md @@ -52,7 +52,6 @@ export const githubIssuesPlugin: BackstagePlugin< { root: RouteRef<undefined>; }, - {}, {} >; diff --git a/plugins/github-issues/package.json b/plugins/github-issues/package.json index 8cdded424c..0a18bb22b9 100644 --- a/plugins/github-issues/package.json +++ b/plugins/github-issues/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-github-issues", - "version": "0.2.13", + "version": "0.2.14-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/github-pull-requests-board/CHANGELOG.md b/plugins/github-pull-requests-board/CHANGELOG.md index 239baaaa0b..cf06af7c0c 100644 --- a/plugins/github-pull-requests-board/CHANGELOG.md +++ b/plugins/github-pull-requests-board/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-github-pull-requests-board +## 0.1.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/theme@0.4.2 + +## 0.1.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + ## 0.1.18 ### Patch Changes diff --git a/plugins/github-pull-requests-board/package.json b/plugins/github-pull-requests-board/package.json index 96cea6bd3a..b7d320931b 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.18", + "version": "0.1.19-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/gitops-profiles/CHANGELOG.md b/plugins/gitops-profiles/CHANGELOG.md index acd81f3af2..7783bf960b 100644 --- a/plugins/gitops-profiles/CHANGELOG.md +++ b/plugins/gitops-profiles/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-gitops-profiles +## 0.3.41-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/theme@0.4.2 + +## 0.3.41-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/config@1.1.0 + - @backstage/theme@0.4.2 + ## 0.3.40 ### Patch Changes diff --git a/plugins/gitops-profiles/api-report.md b/plugins/gitops-profiles/api-report.md index 3dc3c9add2..97f3a9864b 100644 --- a/plugins/gitops-profiles/api-report.md +++ b/plugins/gitops-profiles/api-report.md @@ -124,7 +124,6 @@ const gitopsProfilesPlugin: BackstagePlugin< }>; createPage: RouteRef<undefined>; }, - {}, {} >; export { gitopsProfilesPlugin }; diff --git a/plugins/gitops-profiles/package.json b/plugins/gitops-profiles/package.json index db187a7964..d254a70390 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.40", + "version": "0.3.41-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/gocd/CHANGELOG.md b/plugins/gocd/CHANGELOG.md index c25eca242d..33c2d9bd14 100644 --- a/plugins/gocd/CHANGELOG.md +++ b/plugins/gocd/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-gocd +## 0.1.31-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## 0.1.31-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + ## 0.1.30 ### Patch Changes diff --git a/plugins/gocd/api-report.md b/plugins/gocd/api-report.md index df93b5f2eb..de2c76e06b 100644 --- a/plugins/gocd/api-report.md +++ b/plugins/gocd/api-report.md @@ -15,7 +15,7 @@ export const EntityGoCdContent: () => JSX.Element; export const GOCD_PIPELINES_ANNOTATION = 'gocd.org/pipelines'; // @public -export const gocdPlugin: BackstagePlugin<{}, {}, {}>; +export const gocdPlugin: BackstagePlugin<{}, {}>; // @public export const isGoCdAvailable: (entity: Entity) => boolean; diff --git a/plugins/gocd/package.json b/plugins/gocd/package.json index 4d195ffa31..9da32e57b1 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.30", + "version": "0.1.31-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/gocd/src/components/Select/Select.test.tsx b/plugins/gocd/src/components/Select/Select.test.tsx index 9d73194ed8..c93b5dd148 100644 --- a/plugins/gocd/src/components/Select/Select.test.tsx +++ b/plugins/gocd/src/components/Select/Select.test.tsx @@ -66,7 +66,7 @@ describe('Select', () => { />, ); user.tab(); - userEvent.keyboard('{enter}'); + await userEvent.keyboard('{enter}'); expect(rendered.getAllByText(testItems[0].label)).toHaveLength(2); expect(rendered.getByText(testItems[1].label)).toBeInTheDocument(); diff --git a/plugins/graphiql/CHANGELOG.md b/plugins/graphiql/CHANGELOG.md index c03f2e3c8f..0663cb0755 100644 --- a/plugins/graphiql/CHANGELOG.md +++ b/plugins/graphiql/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-graphiql +## 0.2.55-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.1.1-next.1 + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/theme@0.4.2 + +## 0.2.55-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/frontend-plugin-api@0.1.1-next.0 + - @backstage/theme@0.4.2 + ## 0.2.54 ### Patch Changes diff --git a/plugins/graphiql/api-report.md b/plugins/graphiql/api-report.md index cbecc37006..984b90ae88 100644 --- a/plugins/graphiql/api-report.md +++ b/plugins/graphiql/api-report.md @@ -44,7 +44,7 @@ export const GraphiQLIcon: IconComponent; export const GraphiQLPage: () => JSX_2.Element; // @public (undocumented) -const graphiqlPlugin: BackstagePlugin<{}, {}, {}>; +const graphiqlPlugin: BackstagePlugin<{}, {}>; export { graphiqlPlugin }; export { graphiqlPlugin as plugin }; diff --git a/plugins/graphiql/package.json b/plugins/graphiql/package.json index 100e14e7d0..d0ce3982a6 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.54", + "version": "0.2.55-next.1", "publishConfig": { "access": "public" }, diff --git a/plugins/graphql-backend/CHANGELOG.md b/plugins/graphql-backend/CHANGELOG.md index 36d30d831f..c3991bd3a2 100644 --- a/plugins/graphql-backend/CHANGELOG.md +++ b/plugins/graphql-backend/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-graphql-backend +## 0.1.43-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/config@1.1.0 + - @backstage/plugin-catalog-graphql@0.3.23 + +## 0.1.43-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/plugin-catalog-graphql@0.3.23 + ## 0.1.41 ### Patch Changes diff --git a/plugins/graphql-backend/package.json b/plugins/graphql-backend/package.json index d6316d3599..7ba1b47881 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.41", + "version": "0.1.43-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/graphql-voyager/CHANGELOG.md b/plugins/graphql-voyager/CHANGELOG.md index d521429402..5331c0a7fc 100644 --- a/plugins/graphql-voyager/CHANGELOG.md +++ b/plugins/graphql-voyager/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-graphql-voyager +## 0.1.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/theme@0.4.2 + +## 0.1.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/theme@0.4.2 + ## 0.1.7 ### Patch Changes diff --git a/plugins/graphql-voyager/api-report.md b/plugins/graphql-voyager/api-report.md index 257a8ca7b7..e926bbd193 100644 --- a/plugins/graphql-voyager/api-report.md +++ b/plugins/graphql-voyager/api-report.md @@ -59,7 +59,6 @@ export const graphqlVoyagerPlugin: BackstagePlugin< { root: RouteRef<undefined>; }, - {}, {} >; diff --git a/plugins/graphql-voyager/package.json b/plugins/graphql-voyager/package.json index 62d4e7be23..bc62c158ac 100644 --- a/plugins/graphql-voyager/package.json +++ b/plugins/graphql-voyager/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-graphql-voyager", "description": "Backstage plugin for GraphQL Voyager", - "version": "0.1.7", + "version": "0.1.8-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/home-react/CHANGELOG.md b/plugins/home-react/CHANGELOG.md index c3dd8aefe6..2c2fce8504 100644 --- a/plugins/home-react/CHANGELOG.md +++ b/plugins/home-react/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-home-react +## 0.1.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + +## 0.1.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + ## 0.1.3 ### Patch Changes diff --git a/plugins/home-react/package.json b/plugins/home-react/package.json index 9c7e3bf1db..f6e9655849 100644 --- a/plugins/home-react/package.json +++ b/plugins/home-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-home-react", "description": "A Backstage plugin that contains react components helps you build a home page", - "version": "0.1.3", + "version": "0.1.4-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/home/CHANGELOG.md b/plugins/home/CHANGELOG.md index 841e9ea121..2d826ed5d0 100644 --- a/plugins/home/CHANGELOG.md +++ b/plugins/home/CHANGELOG.md @@ -1,5 +1,34 @@ # @backstage/plugin-home +## 0.5.9-next.1 + +### Patch Changes + +- f997f771da: Adds Top/Recently Visited components to homepage +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-app-api@1.10.1-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/plugin-home-react@0.1.4-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + +## 0.5.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/config@1.1.0 + - @backstage/plugin-home-react@0.1.4-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + ## 0.5.8 ### Patch Changes diff --git a/plugins/home/README.md b/plugins/home/README.md index e147cdfbdf..d41ae57162 100644 --- a/plugins/home/README.md +++ b/plugins/home/README.md @@ -242,6 +242,89 @@ const defaultConfig = [ <CustomHomepageGrid config={defaultConfig}> ``` +## Page visit homepage component (HomePageTopVisited / HomePageRecentlyVisited) + +This component shows the homepage user a view for "Recently visited" or "Top visited". +Being provided by the `<HomePageTopVisited/>` and `<HomePageRecentlyVisited/>` component, see it in use on a homepage example below: + +```tsx +// packages/app/src/components/home/HomePage.tsx +import React from 'react'; +import Grid from '@material-ui/core/Grid'; +import { + HomePageTopVisited, + HomePageRecentlyVisited, +} from '@backstage/plugin-home'; + +export const homePage = ( + <Grid container spacing={3}> + <Grid item xs={12} md={4}> + <HomePageTopVisited /> + </Grid> + <Grid item xs={12} md={4}> + <HomePageRecentlyVisited /> + </Grid> + </Grid> +); +``` + +There are some requirements to provide its functionality, so please ensure the following: + +These components need an API to handle visit data, please refer to the [utility-apis](../../docs/api/utility-apis.md) +documentation for more information. Bellow you can see an example for two options: + +```ts +// packages/app/src/apis.ts +// ... +import { + VisitsStorageApi, + VisitsWebStorageApi, + visitsApiRef, +} from '@backstage/plugin-home'; +// ... +export const apis: AnyApiFactory[] = [ + // Implementation that relies on a provided storageApi + createApiFactory({ + api: visitsApiRef, + deps: { + storageApi: storageApiRef, + identityApi: identityApiRef, + }, + factory: ({ storageApi, identityApi }) => + VisitsStorageApi.create({ storageApi, identityApi }), + }), + + // Or a localStorage data implementation, relies on WebStorage implementation of storageApi + createApiFactory({ + api: visitsApiRef, + deps: { + identityApi: identityApiRef, + errorApi: errorApiRef + }, + factory: ({ identityApi, errorApi }) => VisitsWebStorageApi.create({ identityApi, errorApi }), + }), + // ... +``` + +To monitor page visit activity and save it on behalf of the user a component is provided, please add it to your app. +See the example usage: + +```ts +// packages/app/src/App.tsx +import { VisitListener } from '@backstage/plugin-home'; +// ... +export default app.createRoot( + <> + <AlertDisplay /> + <OAuthRequestDialog /> + <AppRouter> + <VisitListener /> + <Root>{routes}</Root> + </AppRouter> + </>, +); +``` + ## Contributing ### Homepage Components diff --git a/plugins/home/api-report.md b/plugins/home/api-report.md index 450bc054fa..14f685cfc1 100644 --- a/plugins/home/api-report.md +++ b/plugins/home/api-report.md @@ -5,6 +5,7 @@ ```ts /// <reference types="react" /> +import { ApiRef } from '@backstage/core-plugin-api'; import { BackstagePlugin } from '@backstage/core-plugin-api'; import { CardConfig as CardConfig_2 } from '@backstage/plugin-home-react'; import { CardExtensionProps as CardExtensionProps_2 } from '@backstage/plugin-home-react'; @@ -13,12 +14,15 @@ import { CardSettings as CardSettings_2 } from '@backstage/plugin-home-react'; import { ComponentParts as ComponentParts_2 } from '@backstage/plugin-home-react'; import { ComponentRenderer as ComponentRenderer_2 } from '@backstage/plugin-home-react'; import { createCardExtension as createCardExtension_2 } from '@backstage/plugin-home-react'; +import { ErrorApi } from '@backstage/core-plugin-api'; +import { IdentityApi } from '@backstage/core-plugin-api'; import { JSX as JSX_2 } from 'react'; import { default as React_2 } from 'react'; import { ReactElement } from 'react'; import { ReactNode } from 'react'; import { RendererProps as RendererProps_2 } from '@backstage/plugin-home-react'; import { RouteRef } from '@backstage/core-plugin-api'; +import { StorageApi } from '@backstage/core-plugin-api'; // @public export type Breakpoint = 'xxs' | 'xs' | 'sm' | 'md' | 'lg' | 'xl'; @@ -122,6 +126,11 @@ export const HomePageRandomJoke: ( }>, ) => JSX_2.Element; +// @public +export const HomePageRecentlyVisited: ( + props: CardExtensionProps_2<Partial<VisitedByTypeProps>>, +) => JSX_2.Element; + // @public export const HomePageStarredEntities: ( props: CardExtensionProps_2<unknown>, @@ -132,12 +141,16 @@ export const HomePageToolkit: ( props: CardExtensionProps_2<ToolkitContentProps>, ) => JSX_2.Element; +// @public +export const HomePageTopVisited: ( + props: CardExtensionProps_2<Partial<VisitedByTypeProps>>, +) => JSX_2.Element; + // @public (undocumented) export const homePlugin: BackstagePlugin< { root: RouteRef<undefined>; }, - {}, {} >; @@ -187,6 +200,97 @@ export type ToolkitContentProps = { tools: Tool[]; }; +// @public +export type Visit = { + id: string; + name: string; + pathname: string; + hits: number; + timestamp: number; + entityRef?: string; +}; + +// @public (undocumented) +export type VisitedByTypeKind = 'recent' | 'top'; + +// @public (undocumented) +export type VisitedByTypeProps = { + visits?: Array<Visit>; + numVisitsOpen?: number; + numVisitsTotal?: number; + loading?: boolean; + kind: VisitedByTypeKind; +}; + +// @public +export const VisitListener: ({ + children, + toEntityRef, + visitName, +}: { + children?: React_2.ReactNode; + toEntityRef?: + | (({ pathname }: { pathname: string }) => string | undefined) + | undefined; + visitName?: (({ pathname }: { pathname: string }) => string) | undefined; +}) => JSX.Element; + +// @public +export interface VisitsApi { + list(queryParams?: VisitsApiQueryParams): Promise<Visit[]>; + save(saveParams: VisitsApiSaveParams): Promise<Visit>; +} + +// @public +export type VisitsApiQueryParams = { + limit?: number; + orderBy?: Array<{ + field: keyof Visit; + direction: 'asc' | 'desc'; + }>; + filterBy?: Array<{ + field: keyof Visit; + operator: '<' | '<=' | '==' | '!=' | '>' | '>=' | 'contains'; + value: string | number; + }>; +}; + +// @public (undocumented) +export const visitsApiRef: ApiRef<VisitsApi>; + +// @public +export type VisitsApiSaveParams = { + visit: Omit<Visit, 'id' | 'hits' | 'timestamp'>; +}; + +// @public +export class VisitsStorageApi implements VisitsApi { + // (undocumented) + static create(options: VisitsStorageApiOptions): VisitsStorageApi; + list(queryParams?: VisitsApiQueryParams): Promise<Visit[]>; + save(saveParams: VisitsApiSaveParams): Promise<Visit>; +} + +// @public (undocumented) +export type VisitsStorageApiOptions = { + limit?: number; + storageApi: StorageApi; + identityApi: IdentityApi; +}; + +// @public +export class VisitsWebStorageApi { + // (undocumented) + static create(options: VisitsWebStorageApiOptions): VisitsStorageApi; +} + +// @public (undocumented) +export type VisitsWebStorageApiOptions = { + limit?: number; + identityApi: IdentityApi; + errorApi: ErrorApi; +}; + // @public export const WelcomeTitle: ({ language, diff --git a/plugins/home/package.json b/plugins/home/package.json index 1f4fa90148..17c17cffe3 100644 --- a/plugins/home/package.json +++ b/plugins/home/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-home", "description": "A Backstage plugin that helps you build a home page", - "version": "0.5.8", + "version": "0.5.9-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -36,11 +36,13 @@ "dependencies": { "@backstage/catalog-model": "workspace:^", "@backstage/config": "workspace:^", + "@backstage/core-app-api": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", "@backstage/plugin-home-react": "workspace:^", "@backstage/theme": "workspace:^", + "@backstage/types": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", @@ -50,6 +52,7 @@ "@rjsf/validator-ajv8": "5.13.0", "@types/react": "^16.13.1 || ^17.0.0", "lodash": "^4.17.21", + "luxon": "^3.4.3", "react-grid-layout": "^1.3.4", "react-resizable": "^3.0.4", "react-use": "^17.2.4", @@ -62,12 +65,12 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", - "@backstage/core-app-api": "workspace:^", "@backstage/dev-utils": "workspace:^", "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^8.0.0", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", + "@testing-library/react-hooks": "^8.0.1", "@testing-library/user-event": "^14.0.0", "@types/react-grid-layout": "^1.3.2", "msw": "^1.0.0" diff --git a/plugins/home/src/api/VisitsApi.ts b/plugins/home/src/api/VisitsApi.ts new file mode 100644 index 0000000000..ad750d81f2 --- /dev/null +++ b/plugins/home/src/api/VisitsApi.ts @@ -0,0 +1,120 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createApiRef } from '@backstage/core-plugin-api'; + +/** + * @public + * Model for a visit entity. + */ +export type Visit = { + /** + * The auto-generated visit identification. + */ + id: string; + /** + * The visited entity, usually an entity id. + */ + name: string; + /** + * The visited url pathname, usually the entity route. + */ + pathname: string; + /** + * An individual view count. + */ + hits: number; + /** + * Last date and time of visit. Format: unix epoch in ms. + */ + timestamp: number; + /** + * Optional entity reference. See stringifyEntityRef from catalog-model. + */ + entityRef?: string; +}; + +/** + * @public + * This data structure represents the parameters associated with search queries for visits. + */ +export type VisitsApiQueryParams = { + /** + * Limits the number of results returned. The default is 8. + */ + limit?: number; + /** + * Allows ordering visits on entity properties. + * @example + * Sort ascending by the timestamp field. + * ``` + * { orderBy: [{ field: 'timestamp', direction: 'asc' }] } + * ``` + */ + orderBy?: Array<{ + field: keyof Visit; + direction: 'asc' | 'desc'; + }>; + /** + * Allows filtering visits on entity properties. + * @example + * Most popular docs on the past 7 days + * ``` + * { + * orderBy: [{ field: 'hits', direction: 'desc' }], + * filterBy: [ + * { field: 'timestamp', operator: '>=', value: <date> }, + * { field: 'entityRef', operator: 'contains', value: 'docs' } + * ] + * } + * ``` + */ + filterBy?: Array<{ + field: keyof Visit; + operator: '<' | '<=' | '==' | '!=' | '>' | '>=' | 'contains'; + value: string | number; + }>; +}; + +/** + * @public + * This data structure represents the parameters associated with saving visits. + */ +export type VisitsApiSaveParams = { + visit: Omit<Visit, 'id' | 'hits' | 'timestamp'>; +}; + +/** + * @public + * Visits API public contract. + */ +export interface VisitsApi { + /** + * Persist a new visit. + * @param pageVisit - a new visit data + */ + save(saveParams: VisitsApiSaveParams): Promise<Visit>; + /** + * Get user visits. + * @param queryParams - optional search query params. + */ + list(queryParams?: VisitsApiQueryParams): Promise<Visit[]>; +} + +/** @public */ +export const visitsApiRef = createApiRef<VisitsApi>({ + id: 'homepage.visits', +}); diff --git a/plugins/home/src/api/VisitsStorageApi.test.ts b/plugins/home/src/api/VisitsStorageApi.test.ts new file mode 100644 index 0000000000..6faeb62350 --- /dev/null +++ b/plugins/home/src/api/VisitsStorageApi.test.ts @@ -0,0 +1,339 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { BackstageUserIdentity, IdentityApi } from '@backstage/core-plugin-api'; +import { VisitsStorageApi } from './VisitsStorageApi'; +import { MockStorageApi } from '@backstage/test-utils'; +import { Visit, VisitsApi } from './VisitsApi'; + +describe('VisitsStorageApi.create', () => { + const mockRandomUUID = () => + '068f3129-7440-4e0e-8fd4-xxxxxxxxxxxx'.replace( + /x/g, + () => Math.floor(Math.random() * 16).toString(16), // 0x0 to 0xf + ) as `${string}-${string}-${string}-${string}-${string}`; + + const mockIdentityApi: IdentityApi = { + signOut: jest.fn(), + getProfileInfo: jest.fn(), + getBackstageIdentity: async () => + ({ userEntityRef: 'user:default/guest' } as BackstageUserIdentity), + getCredentials: jest.fn(), + }; + + beforeEach(() => { + window.crypto.randomUUID = mockRandomUUID; + jest.useFakeTimers(); + }); + + afterEach(() => { + jest.resetAllMocks(); + jest.useRealTimers(); + window.localStorage.clear(); + }); + + it('instantiates', () => { + const api = VisitsStorageApi.create({ + storageApi: MockStorageApi.create(), + identityApi: mockIdentityApi, + }); + expect(api).toBeTruthy(); + }); + + describe('.save()', () => { + it('saves a visit', async () => { + const api = VisitsStorageApi.create({ + storageApi: MockStorageApi.create(), + identityApi: mockIdentityApi, + }); + const visit = { + pathname: '/catalog/default/component/playback-order', + entityRef: 'component:default/playback-order', + name: 'Playback Order', + }; + const returnedVisit = await api.save({ visit }); + expect(returnedVisit).toEqual(expect.objectContaining(visit)); + expect(returnedVisit.id).toBeTruthy(); + expect(returnedVisit.timestamp).toBeTruthy(); + expect(returnedVisit.hits).toBeTruthy(); + }); + + it('can control the number of stored entities', async () => { + const api = VisitsStorageApi.create({ + storageApi: MockStorageApi.create(), + identityApi: mockIdentityApi, + limit: 2, + }); + const baseDate = Date.now(); + const visit1 = { + pathname: '/catalog/default/component/playback-order-1', + entityRef: 'component:default/playback-order', + name: 'Playback Order', + }; + jest.setSystemTime(baseDate); + await api.save({ visit: visit1 }); + const visit2 = { + pathname: '/catalog/default/component/playback-order-2', + entityRef: 'component:default/playback-order', + name: 'Playback Order', + }; + jest.setSystemTime(baseDate + 360_000); + await api.save({ visit: visit2 }); + const visit3 = { + pathname: '/catalog/default/component/playback-order-3', + entityRef: 'component:default/playback-order', + name: 'Playback Order', + }; + jest.setSystemTime(baseDate + 360_000 * 2); + await api.save({ visit: visit3 }); + const visits = await api.list(); + expect(visits).toHaveLength(2); + expect(visits).toContainEqual(expect.objectContaining(visit2)); + expect(visits).toContainEqual(expect.objectContaining(visit3)); + }); + + it('correctly bumps the hits from a previous visit', async () => { + const api = VisitsStorageApi.create({ + storageApi: MockStorageApi.create(), + identityApi: mockIdentityApi, + }); + const visit = { + pathname: '/catalog/default/component/playback-order', + entityRef: 'component:default/playback-order', + name: 'Playback Order', + }; + const visit1 = await api.save({ visit }); + const visit2 = await api.save({ visit }); + const visits = await api.list(); + expect(visits).toHaveLength(1); + expect(visits).toContainEqual(expect.objectContaining(visit)); + // keeps the original id created on the first visit + expect(visits).toContainEqual(expect.objectContaining({ id: visit1.id })); + // updates timestamp and hits + expect(visits).toContainEqual( + expect.objectContaining({ timestamp: visit2.timestamp, hits: 2 }), + ); + }); + }); + + describe('.list()', () => { + let api: VisitsApi; + let visitsToSave: Array<Omit<Visit, 'id' | 'hits' | 'timestamp'>>; + let baseDate: number; + + beforeEach(() => { + api = VisitsStorageApi.create({ + storageApi: MockStorageApi.create(), + identityApi: mockIdentityApi, + }); + visitsToSave = [ + { + pathname: '/catalog/default/component/playback-order-1', + entityRef: 'component:default/playback-order-1', + name: 'Playback Order Odd', + }, + { + pathname: '/catalog/default/component/playback-order-2', + entityRef: 'component:default/playback-order-2', + name: 'Playback Order Even', + }, + { + pathname: '/catalog/default/component/playback-order-3', + entityRef: 'component:default/playback-order-3', + name: 'Playback Order Odd', + }, + ]; + baseDate = Date.now(); + // Chaining items to ensure the right setSystemTime + return visitsToSave.reduce( + (acc, visit, index) => + acc.then(() => { + jest.setSystemTime(baseDate + 360_000 * index); + return api.save({ visit }); + }), + Promise.resolve({}), + ); + }); + + it('retrieves visits', async () => { + const visits = await api.list(); + expect(visits).toHaveLength(3); + expect(visits).toEqual([ + expect.objectContaining(visitsToSave[2]), + expect.objectContaining(visitsToSave[1]), + expect.objectContaining(visitsToSave[0]), + ]); + }); + + it('orders by timestamp asc', async () => { + const visits = await api.list({ + orderBy: [{ field: 'timestamp', direction: 'asc' }], + }); + expect(visits).toEqual([ + expect.objectContaining(visitsToSave[0]), + expect.objectContaining(visitsToSave[1]), + expect.objectContaining(visitsToSave[2]), + ]); + }); + + it('orders by timestamp desc', async () => { + const visits = await api.list({ + orderBy: [{ field: 'timestamp', direction: 'desc' }], + }); + expect(visits).toEqual([ + expect.objectContaining(visitsToSave[2]), + expect.objectContaining(visitsToSave[1]), + expect.objectContaining(visitsToSave[0]), + ]); + }); + + it('orders by entityRef asc', async () => { + const visits = await api.list({ + orderBy: [{ field: 'entityRef', direction: 'asc' }], + }); + expect(visits).toEqual([ + expect.objectContaining(visitsToSave[0]), + expect.objectContaining(visitsToSave[1]), + expect.objectContaining(visitsToSave[2]), + ]); + }); + + it('orders by entityRef desc', async () => { + const visits = await api.list({ + orderBy: [{ field: 'entityRef', direction: 'desc' }], + }); + expect(visits).toEqual([ + expect.objectContaining(visitsToSave[2]), + expect.objectContaining(visitsToSave[1]), + expect.objectContaining(visitsToSave[0]), + ]); + }); + + it('orders by name asc then by entityRef asc', async () => { + const visits = await api.list({ + orderBy: [ + { field: 'name', direction: 'asc' }, + { field: 'entityRef', direction: 'asc' }, + ], + }); + expect(visits).toEqual([ + expect.objectContaining(visitsToSave[1]), // Playback Order Even, playback-order-2 + expect.objectContaining(visitsToSave[0]), // Playback Order Odd, playback-order-1 + expect.objectContaining(visitsToSave[2]), // Playback Order Odd, playback-order-3 + ]); + }); + + it('orders by name desc then by entityRef asc', async () => { + const visits = await api.list({ + orderBy: [ + { field: 'name', direction: 'desc' }, + { field: 'entityRef', direction: 'asc' }, + ], + }); + expect(visits).toEqual([ + expect.objectContaining(visitsToSave[0]), // Playback Order Odd, playback-order-1 + expect.objectContaining(visitsToSave[2]), // Playback Order Odd, playback-order-3 + expect.objectContaining(visitsToSave[1]), // Playback Order Even, playback-order-2 + ]); + }); + + it('filters by timestamp with >', async () => { + const visits = await api.list({ + filterBy: [{ field: 'timestamp', operator: '>', value: baseDate }], + }); + expect(visits).toHaveLength(2); + expect(visits).toEqual([ + expect.objectContaining(visitsToSave[2]), + expect.objectContaining(visitsToSave[1]), + ]); + }); + + it('filters by timestamp with >=', async () => { + const visits = await api.list({ + filterBy: [ + { field: 'timestamp', operator: '>=', value: baseDate + 360_000 * 2 }, + ], + }); + expect(visits).toHaveLength(1); + expect(visits).toEqual([expect.objectContaining(visitsToSave[2])]); + }); + + it('filters by timestamp with <', async () => { + const visits = await api.list({ + filterBy: [{ field: 'timestamp', operator: '<', value: baseDate + 1 }], + }); + expect(visits).toHaveLength(1); + expect(visits).toEqual([expect.objectContaining(visitsToSave[0])]); + }); + + it('filters by timestamp with <=', async () => { + const visits = await api.list({ + filterBy: [ + { field: 'timestamp', operator: '<=', value: baseDate + 360_000 }, + ], + }); + expect(visits).toHaveLength(2); + expect(visits).toEqual([ + expect.objectContaining(visitsToSave[1]), + expect.objectContaining(visitsToSave[0]), + ]); + }); + + it('filters by timestamp with ==', async () => { + const visits = await api.list({ + filterBy: [ + { field: 'timestamp', operator: '==', value: baseDate + 360_000 }, + ], + }); + expect(visits).toHaveLength(1); + expect(visits).toEqual([expect.objectContaining(visitsToSave[1])]); + }); + + it('filters by timestamp with !=', async () => { + const visits = await api.list({ + filterBy: [ + { field: 'timestamp', operator: '!=', value: baseDate + 360_000 }, + ], + }); + expect(visits).toHaveLength(2); + expect(visits).toEqual([ + expect.objectContaining(visitsToSave[2]), + expect.objectContaining(visitsToSave[0]), + ]); + }); + + it('filters by entityRef with contains', async () => { + const visits = await api.list({ + filterBy: [ + { field: 'entityRef', operator: 'contains', value: 'order-2' }, + ], + }); + expect(visits).toHaveLength(1); + expect(visits).toEqual([expect.objectContaining(visitsToSave[1])]); + }); + + it('filters by timestamp with <= then by name with contains', async () => { + const visits = await api.list({ + filterBy: [ + { field: 'timestamp', operator: '<=', value: baseDate + 360_000 }, + { field: 'name', operator: 'contains', value: 'Odd' }, + ], + }); + expect(visits).toHaveLength(1); + expect(visits).toEqual([expect.objectContaining(visitsToSave[0])]); + }); + }); +}); diff --git a/plugins/home/src/api/VisitsStorageApi.ts b/plugins/home/src/api/VisitsStorageApi.ts new file mode 100644 index 0000000000..daf24d716b --- /dev/null +++ b/plugins/home/src/api/VisitsStorageApi.ts @@ -0,0 +1,150 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { IdentityApi, StorageApi } from '@backstage/core-plugin-api'; +import { + Visit, + VisitsApi, + VisitsApiQueryParams, + VisitsApiSaveParams, +} from './VisitsApi'; + +/** @public */ +export type VisitsStorageApiOptions = { + limit?: number; + storageApi: StorageApi; + identityApi: IdentityApi; +}; + +type ArrayElement<A> = A extends readonly (infer T)[] ? T : never; + +/** + * @public + * This is an implementation of VisitsApi that relies on a StorageApi. + * Beware that filtering and ordering are done in memory therefore it is + * prudent to keep limit to a reasonable size. + */ +export class VisitsStorageApi implements VisitsApi { + private readonly limit: number; + private readonly storageApi: StorageApi; + private readonly storageKeyPrefix = '@backstage/plugin-home:visits'; + private readonly identityApi: IdentityApi; + + static create(options: VisitsStorageApiOptions) { + return new VisitsStorageApi(options); + } + + private constructor(options: VisitsStorageApiOptions) { + this.limit = Math.abs(options.limit ?? 100); + this.storageApi = options.storageApi; + this.identityApi = options.identityApi; + } + + /** + * Returns a list of visits through the visitsApi + */ + async list(queryParams?: VisitsApiQueryParams): Promise<Visit[]> { + let visits = [...(await this.retrieveAll())]; + + // reversing order to guarantee orderBy priority + (queryParams?.orderBy ?? []).reverse().forEach(order => { + if (order.direction === 'asc') { + visits.sort((a, b) => this.compare(order, a, b)); + } else { + visits.sort((a, b) => this.compare(order, b, a)); + } + }); + + // reversing order to guarantee filterBy priority + (queryParams?.filterBy ?? []).reverse().forEach(filter => { + visits = visits.filter(visit => { + const field = visit[filter.field] as number | string; + if (filter.operator === '>') return field > filter.value; + if (filter.operator === '>=') return field >= filter.value; + if (filter.operator === '<') return field < filter.value; + if (filter.operator === '<=') return field <= filter.value; + if (filter.operator === '==') return field === filter.value; + if (filter.operator === '!=') return field !== filter.value; + if (filter.operator === 'contains') + return `${field}`.includes(`${filter.value}`); + return false; + }); + }); + + return visits; + } + + /** + * Saves a visit through the visitsApi + */ + async save(saveParams: VisitsApiSaveParams): Promise<Visit> { + const visits: Visit[] = [...(await this.retrieveAll())]; + + const visit: Visit = { + ...saveParams.visit, + id: window.crypto.randomUUID(), + hits: 1, + timestamp: Date.now(), + }; + + // Updates entry if pathname is already registered + const visitIndex = visits.findIndex(e => e.pathname === visit.pathname); + if (visitIndex >= 0) { + visit.id = visits[visitIndex].id; + visit.hits = visits[visitIndex].hits + 1; + visits[visitIndex] = visit; + } else { + visits.push(visit); + } + + // Sort by time, most recent first + visits.sort((a, b) => b.timestamp - a.timestamp); + // Keep the most recent items up to limit + await this.persistAll(visits.splice(0, this.limit)); + return visit; + } + + private async persistAll(visits: Array<Visit>) { + const { userEntityRef } = await this.identityApi.getBackstageIdentity(); + const storageKey = `${this.storageKeyPrefix}:${userEntityRef}`; + + return this.storageApi.set<Array<Visit>>(storageKey, visits); + } + + private async retrieveAll(): Promise<Array<Visit>> { + const { userEntityRef } = await this.identityApi.getBackstageIdentity(); + const storageKey = `${this.storageKeyPrefix}:${userEntityRef}`; + let visits: Array<Visit>; + + try { + visits = this.storageApi.snapshot<Array<Visit>>(storageKey).value ?? []; + } catch { + visits = []; + } + return visits; + } + + // This assumes Visit fields are either numbers or strings + private compare( + order: ArrayElement<VisitsApiQueryParams['orderBy']>, + a: Visit, + b: Visit, + ): number { + const isNumber = typeof a[order.field] === 'number'; + return isNumber + ? (a[order.field] as number) - (b[order.field] as number) + : `${a[order.field]}`.localeCompare(`${b[order.field]}`); + } +} diff --git a/plugins/home/src/api/VisitsWebStorageApi.test.ts b/plugins/home/src/api/VisitsWebStorageApi.test.ts new file mode 100644 index 0000000000..1cf1fa3129 --- /dev/null +++ b/plugins/home/src/api/VisitsWebStorageApi.test.ts @@ -0,0 +1,87 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { BackstageUserIdentity, IdentityApi } from '@backstage/core-plugin-api'; +import { VisitsWebStorageApi } from './VisitsWebStorageApi'; + +describe('VisitsWebStorageApi.create()', () => { + const mockRandomUUID = () => + '068f3129-7440-4e0e-8fd4-xxxxxxxxxxxx'.replace( + /x/g, + () => Math.floor(Math.random() * 16).toString(16), // 0x0 to 0xf + ) as `${string}-${string}-${string}-${string}-${string}`; + + const mockIdentityApi: IdentityApi = { + signOut: jest.fn(), + getProfileInfo: jest.fn(), + getBackstageIdentity: async () => + ({ userEntityRef: 'user:default/guest' } as BackstageUserIdentity), + getCredentials: jest.fn(), + }; + + const mockErrorApi = { post: jest.fn(), error$: jest.fn() }; + + beforeEach(() => { + window.crypto.randomUUID = mockRandomUUID; + }); + + afterEach(() => { + window.localStorage.clear(); + jest.resetAllMocks(); + }); + + it('instantiates with only identitiyApi', () => { + const api = VisitsWebStorageApi.create({ + identityApi: mockIdentityApi, + errorApi: mockErrorApi, + }); + expect(api).toBeTruthy(); + }); + + it('saves a visit', async () => { + const api = VisitsWebStorageApi.create({ + identityApi: mockIdentityApi, + errorApi: mockErrorApi, + }); + const visit = { + pathname: '/catalog/default/component/playback-order', + entityRef: 'component:default/playback-order', + name: 'Playback Order', + }; + const returnedVisit = await api.save({ visit }); + expect(returnedVisit).toEqual(expect.objectContaining(visit)); + expect(returnedVisit.id).toBeTruthy(); + expect(returnedVisit.timestamp).toBeTruthy(); + expect(returnedVisit.hits).toBeTruthy(); + }); + + it('retrieves visits', async () => { + const api = VisitsWebStorageApi.create({ + identityApi: mockIdentityApi, + errorApi: mockErrorApi, + }); + const visit = { + pathname: '/catalog/default/component/playback-order', + entityRef: 'component:default/playback-order', + name: 'Playback Order', + }; + const returnedVisit = await api.save({ visit }); + const visits = await api.list(); + expect(visits).toHaveLength(1); + expect(visits).toEqual([expect.objectContaining(visit)]); + expect(visits).toEqual([returnedVisit]); + }); +}); diff --git a/plugins/home/src/api/VisitsWebStorageApi.ts b/plugins/home/src/api/VisitsWebStorageApi.ts new file mode 100644 index 0000000000..56b3ae53c5 --- /dev/null +++ b/plugins/home/src/api/VisitsWebStorageApi.ts @@ -0,0 +1,39 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { ErrorApi, IdentityApi } from '@backstage/core-plugin-api'; +import { VisitsStorageApi } from './VisitsStorageApi'; +import { WebStorage } from '@backstage/core-app-api'; + +/** @public */ +export type VisitsWebStorageApiOptions = { + limit?: number; + identityApi: IdentityApi; + errorApi: ErrorApi; +}; + +/** + * @public + * This is a reference implementation of VisitsApi using WebStorage. + */ +export class VisitsWebStorageApi { + static create(options: VisitsWebStorageApiOptions) { + return VisitsStorageApi.create({ + limit: options.limit, + identityApi: options.identityApi, + storageApi: WebStorage.create({ errorApi: options.errorApi }), + }); + } +} diff --git a/plugins/home/src/api/index.ts b/plugins/home/src/api/index.ts new file mode 100644 index 0000000000..944fa65330 --- /dev/null +++ b/plugins/home/src/api/index.ts @@ -0,0 +1,19 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './VisitsStorageApi'; +export * from './VisitsWebStorageApi'; +export * from './VisitsApi'; diff --git a/plugins/home/src/components/VisitList/ItemCategory.tsx b/plugins/home/src/components/VisitList/ItemCategory.tsx new file mode 100644 index 0000000000..0f9636ce31 --- /dev/null +++ b/plugins/home/src/components/VisitList/ItemCategory.tsx @@ -0,0 +1,79 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { Chip, makeStyles } from '@material-ui/core'; +import { colorVariants } from '@backstage/theme'; +import { Visit } from '../../api/VisitsApi'; +import { CompoundEntityRef, parseEntityRef } from '@backstage/catalog-model'; + +const useStyles = makeStyles(theme => ({ + chip: { + color: theme.palette.common.white, + fontWeight: 'bold', + margin: 0, + }, +})); +const maybeEntity = (visit: Visit): CompoundEntityRef | undefined => { + try { + return parseEntityRef(visit?.entityRef ?? ''); + } catch (e) { + return undefined; + } +}; +const getColorByIndex = (index: number) => { + const variants = Object.keys(colorVariants); + const variantIndex = index % variants.length; + return colorVariants[variants[variantIndex]][0]; +}; +const getChipColor = (entity: CompoundEntityRef | undefined): string => { + const defaultColor = getColorByIndex(0); + if (!entity) return defaultColor; + + // IDEA: Use or replicate useAllKinds hook thus supporting all software catalog + // registered kinds. See: + // plugins/catalog-react/src/components/EntityKindPicker/kindFilterUtils.ts + // Provide extension point to register your own color code. + const entityKinds = [ + 'component', + 'template', + 'api', + 'group', + 'user', + 'resource', + 'system', + 'domain', + 'location', + ]; + const foundIndex = entityKinds.indexOf( + entity.kind.toLocaleLowerCase('en-US'), + ); + return foundIndex === -1 ? defaultColor : getColorByIndex(foundIndex + 1); +}; + +export const ItemCategory = ({ visit }: { visit: Visit }) => { + const classes = useStyles(); + const entity = maybeEntity(visit); + + return ( + <Chip + size="small" + className={classes.chip} + label={(entity?.kind ?? 'Other').toLocaleLowerCase('en-US')} + style={{ background: getChipColor(entity) }} + /> + ); +}; diff --git a/plugins/home/src/components/VisitList/ItemDetail.tsx b/plugins/home/src/components/VisitList/ItemDetail.tsx new file mode 100644 index 0000000000..3f55557f73 --- /dev/null +++ b/plugins/home/src/components/VisitList/ItemDetail.tsx @@ -0,0 +1,58 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { Typography } from '@material-ui/core'; +import { Visit } from '../../api/VisitsApi'; +import { DateTime } from 'luxon'; + +const ItemDetailHits = ({ visit }: { visit: Visit }) => ( + <Typography component="span" variant="caption" color="textSecondary"> + {visit.hits} time{visit.hits > 1 ? 's' : ''} + </Typography> +); + +const ItemDetailTimeAgo = ({ visit }: { visit: Visit }) => { + const visitDate = DateTime.fromMillis(visit.timestamp); + + return ( + <Typography + component="time" + variant="caption" + color="textSecondary" + dateTime={visitDate.toISO() ?? undefined} + > + {visitDate >= DateTime.now().startOf('day') + ? visitDate.toFormat('HH:mm') + : visitDate.toRelative()} + </Typography> + ); +}; + +export type ItemDetailType = 'time-ago' | 'hits'; + +export const ItemDetail = ({ + visit, + type, +}: { + visit: Visit; + type: ItemDetailType; +}) => + type === 'time-ago' ? ( + <ItemDetailTimeAgo visit={visit} /> + ) : ( + <ItemDetailHits visit={visit} /> + ); diff --git a/plugins/home/src/components/VisitList/ItemName.tsx b/plugins/home/src/components/VisitList/ItemName.tsx new file mode 100644 index 0000000000..965ad80d5e --- /dev/null +++ b/plugins/home/src/components/VisitList/ItemName.tsx @@ -0,0 +1,41 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { Typography, makeStyles } from '@material-ui/core'; +import { Visit } from '../../api/VisitsApi'; +import { Link } from '@backstage/core-components'; + +const useStyles = makeStyles(_theme => ({ + name: { + marginLeft: '0.8rem', + marginRight: '0.8rem', + }, +})); +export const ItemName = ({ visit }: { visit: Visit }) => { + const classes = useStyles(); + + return ( + <Typography + component={Link} + to={visit.pathname} + noWrap + className={classes.name} + > + {visit.name} + </Typography> + ); +}; diff --git a/plugins/home/src/components/VisitList/VisitList.test.tsx b/plugins/home/src/components/VisitList/VisitList.test.tsx new file mode 100644 index 0000000000..077c428706 --- /dev/null +++ b/plugins/home/src/components/VisitList/VisitList.test.tsx @@ -0,0 +1,160 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { VisitList } from './VisitList'; +import { render } from '@testing-library/react'; +import { BrowserRouter } from 'react-router-dom'; + +describe('<VisitList/>', () => { + it('renders with mandatory parameters', async () => { + const { getByText } = await render( + <VisitList title="My title" detailType="time-ago" />, + ); + expect(getByText('My title')).toBeInTheDocument(); + }); + + it('renders skeleton when loading is true', async () => { + const { container } = await render( + <VisitList title="My title" detailType="time-ago" loading />, + ); + expect(container.querySelectorAll('li')).toHaveLength(8); + expect(container.querySelectorAll('.MuiSkeleton-root')).toHaveLength(16); + }); + + it('renders specified amount of items', async () => { + const { container } = await render( + <VisitList + title="My title" + detailType="time-ago" + loading + numVisitsOpen={1} + numVisitsTotal={2} + />, + ); + expect(container.querySelectorAll('li')).toHaveLength(2); + }); + + it('renders some items hidden', async () => { + const { container } = await render( + <VisitList + title="My title" + detailType="time-ago" + loading + numVisitsOpen={1} + numVisitsTotal={2} + />, + ); + expect(container.querySelectorAll('li')[0]).toBeVisible(); + expect(container.querySelectorAll('li')[1]).not.toBeVisible(); + }); + + it('renders all items when not collapsed', async () => { + const { container } = await render( + <VisitList + title="My title" + detailType="time-ago" + loading + collapsed={false} + numVisitsOpen={1} + numVisitsTotal={2} + />, + ); + expect(container.querySelectorAll('li')[0]).toBeVisible(); + expect(container.querySelectorAll('li')[1]).toBeVisible(); + }); + + it('renders visit with time-ago', async () => { + const { container, getByText } = await render( + <BrowserRouter> + <VisitList + title="My title" + detailType="time-ago" + visits={[ + { + id: 'explore', + name: 'Explore Backstage', + pathname: '/explore', + hits: 35, + timestamp: Date.now() - 86400_000, + }, + ]} + /> + , + </BrowserRouter>, + ); + expect(container.querySelectorAll('li')).toHaveLength(1); + expect(getByText('Explore Backstage')).toBeInTheDocument(); + expect(getByText('1 day ago')).toBeInTheDocument(); + }); + + it('renders visit with hits', async () => { + const { container, getByText } = await render( + <BrowserRouter> + <VisitList + title="My title" + detailType="hits" + visits={[ + { + id: 'explore', + name: 'Explore Backstage', + pathname: '/explore', + hits: 35, + timestamp: Date.now() - 86400_000, + }, + ]} + /> + , + </BrowserRouter>, + ); + expect(container.querySelectorAll('li')).toHaveLength(1); + expect(getByText('Explore Backstage')).toBeInTheDocument(); + expect(getByText('35 times')).toBeInTheDocument(); + }); + + it('renders text warning about few items', async () => { + const { getByText } = await render( + <BrowserRouter> + <VisitList + title="My title" + detailType="hits" + visits={[ + { + id: 'explore', + name: 'Explore Backstage', + pathname: '/explore', + hits: 35, + timestamp: Date.now() - 86400_000, + }, + ]} + /> + , + </BrowserRouter>, + ); + expect( + getByText('The more pages you visit, the more pages will appear here.'), + ).toBeInTheDocument(); + }); + + it('renders text warning about no items', async () => { + const { getByText } = await render( + <BrowserRouter> + <VisitList title="My title" detailType="hits" visits={[]} />, + </BrowserRouter>, + ); + expect(getByText('There are no visits to show yet.')).toBeInTheDocument(); + }); +}); diff --git a/plugins/home/src/components/VisitList/VisitList.tsx b/plugins/home/src/components/VisitList/VisitList.tsx new file mode 100644 index 0000000000..f1dc855d9d --- /dev/null +++ b/plugins/home/src/components/VisitList/VisitList.tsx @@ -0,0 +1,102 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { Collapse, List, Typography, makeStyles } from '@material-ui/core'; +import { Visit } from '../../api/VisitsApi'; +import { VisitListItem } from './VisitListItem'; +import { ItemDetailType } from './ItemDetail'; +import { VisitListEmpty } from './VisitListEmpty'; +import { VisitListFew } from './VisitListFew'; +import { VisitListSkeleton } from './VisitListSkeleton'; + +const useStyles = makeStyles(_theme => ({ + title: { + marginBottom: '2rem', + }, +})); + +export const VisitList = ({ + title, + detailType, + visits = [], + numVisitsOpen = 3, + numVisitsTotal = 8, + collapsed = true, + loading = false, +}: { + title: string; + detailType: ItemDetailType; + visits?: Visit[]; + numVisitsOpen?: number; + numVisitsTotal?: number; + collapsed?: boolean; + loading?: boolean; +}) => { + const classes = useStyles(); + + let listBody: React.ReactElement = <></>; + if (loading) { + listBody = ( + <VisitListSkeleton + numVisitsOpen={numVisitsOpen} + numVisitsTotal={numVisitsTotal} + collapsed={collapsed} + /> + ); + } else if (visits.length === 0) { + listBody = <VisitListEmpty />; + } else if (visits.length < numVisitsOpen) { + listBody = ( + <> + {visits.map((visit, index) => ( + <VisitListItem visit={visit} key={index} detailType={detailType} /> + ))} + <VisitListFew /> + </> + ); + } else { + listBody = ( + <> + {visits.slice(0, numVisitsOpen).map((visit, index) => ( + <VisitListItem visit={visit} key={index} detailType={detailType} /> + ))} + {visits.length > numVisitsOpen && ( + <Collapse in={!collapsed}> + {visits.slice(numVisitsOpen, numVisitsTotal).map((visit, index) => ( + <VisitListItem + visit={visit} + key={index} + detailType={detailType} + /> + ))} + </Collapse> + )} + </> + ); + } + + return ( + <> + <Typography variant="h5" className={classes.title}> + {title} + </Typography> + <List dense disablePadding> + {listBody} + </List> + </> + ); +}; diff --git a/plugins/home/src/components/VisitList/VisitListEmpty.tsx b/plugins/home/src/components/VisitList/VisitListEmpty.tsx new file mode 100644 index 0000000000..3996f0f863 --- /dev/null +++ b/plugins/home/src/components/VisitList/VisitListEmpty.tsx @@ -0,0 +1,30 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { Typography } from '@material-ui/core'; + +export const VisitListEmpty = () => ( + <> + <Typography variant="body2" color="textSecondary"> + There are no visits to show yet. + </Typography> + <Typography variant="body2" color="textSecondary"> + Once you start using Backstage, your visits will appear here as a quick + link to carry on where you left off. + </Typography> + </> +); diff --git a/plugins/home/src/components/VisitList/VisitListFew.tsx b/plugins/home/src/components/VisitList/VisitListFew.tsx new file mode 100644 index 0000000000..c28f1af931 --- /dev/null +++ b/plugins/home/src/components/VisitList/VisitListFew.tsx @@ -0,0 +1,26 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { Typography } from '@material-ui/core'; + +export const VisitListFew = () => ( + <> + <Typography variant="body2" color="textSecondary"> + The more pages you visit, the more pages will appear here. + </Typography> + </> +); diff --git a/plugins/home/src/components/VisitList/VisitListItem.tsx b/plugins/home/src/components/VisitList/VisitListItem.tsx new file mode 100644 index 0000000000..20087c884a --- /dev/null +++ b/plugins/home/src/components/VisitList/VisitListItem.tsx @@ -0,0 +1,55 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { + ListItem, + ListItemAvatar, + ListItemText, + makeStyles, +} from '@material-ui/core'; +import { Visit } from '../../api/VisitsApi'; +import { ItemName } from './ItemName'; +import { ItemDetail, ItemDetailType } from './ItemDetail'; +import { ItemCategory } from './ItemCategory'; + +const useStyles = makeStyles(_theme => ({ + avatar: { + minWidth: 0, + }, +})); +export const VisitListItem = ({ + visit, + detailType, +}: { + visit: Visit; + detailType: ItemDetailType; +}) => { + const classes = useStyles(); + + return ( + <ListItem disableGutters> + <ListItemAvatar className={classes.avatar}> + <ItemCategory visit={visit} /> + </ListItemAvatar> + <ListItemText + primary={<ItemName visit={visit} />} + secondary={<ItemDetail visit={visit} type={detailType} />} + disableTypography + /> + </ListItem> + ); +}; diff --git a/plugins/home/src/components/VisitList/VisitListSkeleton.tsx b/plugins/home/src/components/VisitList/VisitListSkeleton.tsx new file mode 100644 index 0000000000..94ba840d9d --- /dev/null +++ b/plugins/home/src/components/VisitList/VisitListSkeleton.tsx @@ -0,0 +1,79 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { + Collapse, + ListItem, + ListItemAvatar, + ListItemText, + makeStyles, +} from '@material-ui/core'; +import { Skeleton } from '@material-ui/lab'; + +const useStyles = makeStyles(_theme => ({ + skeleton: { + borderRadius: 30, + }, +})); + +const VisitListItemSkeleton = () => { + const classes = useStyles(); + + return ( + <ListItem disableGutters> + <ListItemAvatar> + <Skeleton + className={classes.skeleton} + variant="rect" + width={50} + height={24} + /> + </ListItemAvatar> + <ListItemText + primary={<Skeleton variant="text" width="100%" height={28} />} + disableTypography + /> + </ListItem> + ); +}; + +export const VisitListSkeleton = ({ + numVisitsOpen, + numVisitsTotal, + collapsed, +}: { + numVisitsOpen: number; + numVisitsTotal: number; + collapsed: boolean; +}) => ( + <> + {Array(numVisitsOpen) + .fill(null) + .map((_e, index) => ( + <VisitListItemSkeleton key={index} /> + ))} + {numVisitsTotal > numVisitsOpen && ( + <Collapse in={!collapsed}> + {Array(numVisitsTotal - numVisitsOpen) + .fill(null) + .map((_e, index) => ( + <VisitListItemSkeleton key={index} /> + ))} + </Collapse> + )} + </> +); diff --git a/plugins/kubernetes/src/components/ResourceUtilization/index.ts b/plugins/home/src/components/VisitList/index.ts similarity index 90% rename from plugins/kubernetes/src/components/ResourceUtilization/index.ts rename to plugins/home/src/components/VisitList/index.ts index 33d232cbf4..2d9513893b 100644 --- a/plugins/kubernetes/src/components/ResourceUtilization/index.ts +++ b/plugins/home/src/components/VisitList/index.ts @@ -13,4 +13,5 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export { ResourceUtilization } from './ResourceUtilization'; + +export { VisitList } from './VisitList'; diff --git a/plugins/home/src/components/VisitListener.test.tsx b/plugins/home/src/components/VisitListener.test.tsx new file mode 100644 index 0000000000..72c530071a --- /dev/null +++ b/plugins/home/src/components/VisitListener.test.tsx @@ -0,0 +1,134 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; +import { TestApiProvider, renderInTestApp } from '@backstage/test-utils'; +import { Visit, visitsApiRef } from '../api'; +import { VisitListener } from './VisitListener'; +import { waitFor } from '@testing-library/react'; + +const visits: Array<Visit> = [ + { + id: 'tech-radar', + name: 'Tech Radar', + pathname: '/tech-radar', + hits: 40, + timestamp: Date.now() - 360_000, + }, + { + id: 'explore', + name: 'Explore Backstage', + pathname: '/explore', + hits: 35, + timestamp: Date.now() - 86400_000 * 1, + }, + { + id: 'user-1', + name: 'Guest', + pathname: '/catalog/default/user/guest', + hits: 30, + timestamp: Date.now() - 86400_000 * 2, + entityRef: 'User:default/guest', + }, +]; + +const mockVisitsApi = { + save: jest.fn(async () => visits[0]), + list: jest.fn(async () => visits), +}; + +describe('<VisitListener/>', () => { + afterEach(jest.resetAllMocks); + + it('registers a visit', async () => { + const pathname = '/catalog/default/component/playback-order'; + + await renderInTestApp( + <TestApiProvider apis={[[visitsApiRef, mockVisitsApi]]}> + <VisitListener /> + </TestApiProvider>, + { routeEntries: [pathname] }, + ); + + await waitFor(() => expect(mockVisitsApi.save).toHaveBeenCalledTimes(1)); + expect(mockVisitsApi.save).toHaveBeenCalledWith({ + visit: { + pathname, + entityRef: 'component:default/playback-order', + name: 'playback-order', + }, + }); + }); + + it('renders its children', async () => { + const { getByTestId } = await renderInTestApp( + <TestApiProvider apis={[[visitsApiRef, mockVisitsApi]]}> + <VisitListener> + <div data-testid="child">child</div> + </VisitListener> + </TestApiProvider>, + ); + + expect(getByTestId('child')).toBeTruthy(); + }); + + it('is able to override how visit names are defined', async () => { + const pathname = '/catalog/default/component/playback-order'; + + const visitNameOverride = ({ pathname: path }: { pathname: string }) => + path; + + await renderInTestApp( + <TestApiProvider apis={[[visitsApiRef, mockVisitsApi]]}> + <VisitListener visitName={visitNameOverride} /> + </TestApiProvider>, + { routeEntries: [pathname] }, + ); + + await waitFor(() => + expect(mockVisitsApi.save).toHaveBeenCalledWith({ + visit: { + pathname, + entityRef: 'component:default/playback-order', + name: pathname, + }, + }), + ); + }); + + it('is able to override how entityRefs are defined', async () => { + const pathname = '/catalog/default/component/playback-order'; + + const toEntityRefOverride = ({ pathname: path }: { pathname: string }) => + path; + + await renderInTestApp( + <TestApiProvider apis={[[visitsApiRef, mockVisitsApi]]}> + <VisitListener toEntityRef={toEntityRefOverride} /> + </TestApiProvider>, + { routeEntries: [pathname] }, + ); + + await waitFor(() => + expect(mockVisitsApi.save).toHaveBeenCalledWith({ + visit: { + pathname, + entityRef: pathname, + name: 'playback-order', + }, + }), + ); + }); +}); diff --git a/plugins/home/src/components/VisitListener.tsx b/plugins/home/src/components/VisitListener.tsx new file mode 100644 index 0000000000..866fd69885 --- /dev/null +++ b/plugins/home/src/components/VisitListener.tsx @@ -0,0 +1,111 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React, { useEffect } from 'react'; + +import { useLocation } from 'react-router-dom'; + +import { visitsApiRef } from '../api'; +import { useApi } from '@backstage/core-plugin-api'; +import { stringifyEntityRef } from '@backstage/catalog-model'; + +/** + * This function returns an implementation of toEntityRef which is responsible + * for receiving a pathname and maybe returning an entityRef compatible with the + * catalog-model. + * By default this function uses the url root "/catalog" and the + * stringifyEntityRef implementation from catalog-model. + * Example: + * const toEntityRef = getToEntityRef(); + * toEntityRef(\{ pathname: "/catalog/default/component/playback-order" \}) + * // returns "component:default/playback-order" + */ +const getToEntityRef = + ({ + rootPath = 'catalog', + stringifyEntityRefImpl = stringifyEntityRef, + } = {}) => + ({ pathname }: { pathname: string }): string | undefined => { + const regex = new RegExp( + `^\/${rootPath}\/(?<namespace>[^\/]+)\/(?<kind>[^\/]+)\/(?<name>[^\/]+)`, + ); + const result = regex.exec(pathname); + if (!result || !result?.groups) return undefined; + const entity = { + namespace: result.groups.namespace, + kind: result.groups.kind, + name: result.groups.name, + }; + return stringifyEntityRefImpl(entity); + }; + +/** + * @internal + * This function returns an implementation of visitName which is responsible + * for receiving a pathname and returning a string (name). + */ +const getVisitName = + ({ rootPath = 'catalog', document = global.document } = {}) => + ({ pathname }: { pathname: string }) => { + // If it is a catalog entity, get the name from the path + const regex = new RegExp( + `^\/${rootPath}\/(?<namespace>[^\/]+)\/(?<kind>[^\/]+)\/(?<name>[^\/]+)`, + ); + let result = regex.exec(pathname); + if (result && result?.groups) return result.groups.name; + + // If it is a root pathname, get the name from there + result = /^\/(?<name>[^\/]+)$/.exec(pathname); + if (result && result?.groups) return result.groups.name; + + // Fallback to document title + return document.title; + }; + +/** + * @public + * Component responsible for listening to location changes and calling + * the visitsApi to save visits. + */ +export const VisitListener = ({ + children, + toEntityRef, + visitName, +}: { + children?: React.ReactNode; + toEntityRef?: ({ pathname }: { pathname: string }) => string | undefined; + visitName?: ({ pathname }: { pathname: string }) => string; +}): JSX.Element => { + const visitsApi = useApi(visitsApiRef); + const { pathname } = useLocation(); + const toEntityRefImpl = toEntityRef ?? getToEntityRef(); + const visitNameImpl = visitName ?? getVisitName(); + useEffect(() => { + // Wait for the browser to finish with paint with the assumption react + // has finished with dom reconciliation. + const requestId = requestAnimationFrame(() => { + visitsApi.save({ + visit: { + name: visitNameImpl({ pathname }), + pathname, + entityRef: toEntityRefImpl({ pathname }), + }, + }); + }); + return () => cancelAnimationFrame(requestId); + }, [visitsApi, pathname, toEntityRefImpl, visitNameImpl]); + + return <>{children}</>; +}; diff --git a/plugins/home/src/components/index.ts b/plugins/home/src/components/index.ts index e528e0795d..a6a4148e36 100644 --- a/plugins/home/src/components/index.ts +++ b/plugins/home/src/components/index.ts @@ -16,3 +16,4 @@ export { HomepageCompositionRoot } from './HomepageCompositionRoot'; export * from './CustomHomepage'; +export * from './VisitListener'; diff --git a/plugins/home/src/homePageComponents/VisitedByType/Actions.tsx b/plugins/home/src/homePageComponents/VisitedByType/Actions.tsx new file mode 100644 index 0000000000..45e67802c9 --- /dev/null +++ b/plugins/home/src/homePageComponents/VisitedByType/Actions.tsx @@ -0,0 +1,37 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React, { useCallback } from 'react'; +import { Button } from '@material-ui/core'; +import { useContext } from './Context'; + +export const Actions = () => { + const { collapsed, setCollapsed, visits, numVisitsOpen, loading } = + useContext(); + const onClick = useCallback( + () => setCollapsed(prevCollapsed => !prevCollapsed), + [setCollapsed], + ); + const label = collapsed ? 'View More' : 'View Less'; + + if (!loading && visits.length <= numVisitsOpen) return <></>; + + return ( + <Button variant="text" onClick={onClick}> + {label} + </Button> + ); +}; diff --git a/plugins/home/src/homePageComponents/VisitedByType/Content.test.tsx b/plugins/home/src/homePageComponents/VisitedByType/Content.test.tsx new file mode 100644 index 0000000000..4442c319e6 --- /dev/null +++ b/plugins/home/src/homePageComponents/VisitedByType/Content.test.tsx @@ -0,0 +1,136 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { Content } from './Content'; +import { TestApiProvider, renderInTestApp } from '@backstage/test-utils'; +import { visitsApiRef } from '../../api'; +import { ContextProvider } from './Context'; +import { waitFor } from '@testing-library/react'; + +const visits = [ + { + id: 'explore', + name: 'Explore Backstage', + pathname: '/explore', + hits: 35, + timestamp: Date.now() - 86400_000, + }, +]; + +const mockVisitsApi = { + save: async () => visits[0], + list: async () => visits, +}; + +describe('<Content kind="recent"/>', () => { + it('renders', async () => { + const { getByText } = await renderInTestApp( + <TestApiProvider apis={[[visitsApiRef, mockVisitsApi]]}> + <ContextProvider> + <Content kind="recent" /> + </ContextProvider> + </TestApiProvider>, + ); + expect(getByText('Recently Visited')).toBeInTheDocument(); + await waitFor(() => + expect(getByText('Explore Backstage')).toBeInTheDocument(), + ); + }); + + it('allows visits to be overridden', async () => { + const { getByText } = await renderInTestApp( + <TestApiProvider apis={[[visitsApiRef, mockVisitsApi]]}> + <ContextProvider> + <Content + kind="recent" + visits={[ + { + id: 'tech-radar', + name: 'Tech Radar', + pathname: '/tech-radar', + hits: 40, + timestamp: Date.now() - 360_000, + }, + ]} + /> + </ContextProvider> + </TestApiProvider>, + ); + expect(getByText('Recently Visited')).toBeInTheDocument(); + await waitFor(() => expect(getByText('Tech Radar')).toBeInTheDocument()); + }); + + it('allows loading to be overridden', async () => { + const { container } = await renderInTestApp( + <TestApiProvider apis={[[visitsApiRef, mockVisitsApi]]}> + <ContextProvider> + <Content kind="recent" loading /> + </ContextProvider> + </TestApiProvider>, + ); + expect(container.querySelector('.MuiSkeleton-root')).toBeInTheDocument(); + }); + + it('allows number of items to be specified', async () => { + const { container } = await renderInTestApp( + <TestApiProvider apis={[[visitsApiRef, mockVisitsApi]]}> + <ContextProvider> + <Content + kind="recent" + visits={[ + { + id: 'explore', + name: 'Explore Backstage', + pathname: '/explore', + hits: 35, + timestamp: Date.now() - 86400_000, + }, + { + id: 'tech-radar', + name: 'Tech Radar', + pathname: '/tech-radar', + hits: 40, + timestamp: Date.now() - 360_000, + }, + ]} + numVisitsOpen={1} + numVisitsTotal={2} + /> + </ContextProvider> + </TestApiProvider>, + ); + expect(container.querySelectorAll('li')).toHaveLength(2); + expect(container.querySelectorAll('li')[0]).toBeVisible(); + expect(container.querySelectorAll('li')[1]).not.toBeVisible(); + }); +}); + +describe('<Content kind="top"/>', () => { + it('renders', async () => { + const { getByText } = await renderInTestApp( + <TestApiProvider apis={[[visitsApiRef, mockVisitsApi]]}> + <ContextProvider> + <Content kind="top" /> + </ContextProvider> + </TestApiProvider>, + ); + expect(getByText('Top Visited')).toBeInTheDocument(); + await waitFor(() => + expect(getByText('Explore Backstage')).toBeInTheDocument(), + ); + }); +}); diff --git a/plugins/home/src/homePageComponents/VisitedByType/Content.tsx b/plugins/home/src/homePageComponents/VisitedByType/Content.tsx new file mode 100644 index 0000000000..4e847b717f --- /dev/null +++ b/plugins/home/src/homePageComponents/VisitedByType/Content.tsx @@ -0,0 +1,91 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React, { useEffect } from 'react'; +import { VisitedByType } from './VisitedByType'; +import { Visit, visitsApiRef } from '../../api/VisitsApi'; +import { ContextValueOnly, useContext } from './Context'; +import { useApi } from '@backstage/core-plugin-api'; +import useAsync from 'react-use/lib/useAsync'; + +/** @public */ +export type VisitedByTypeKind = 'recent' | 'top'; + +/** @public */ +export type VisitedByTypeProps = { + visits?: Array<Visit>; + numVisitsOpen?: number; + numVisitsTotal?: number; + loading?: boolean; + kind: VisitedByTypeKind; +}; + +/** + * Display recently visited pages for the homepage + * @public + */ +export const Content = ({ + visits, + numVisitsOpen, + numVisitsTotal, + loading, + kind, +}: VisitedByTypeProps) => { + const { setContext, setVisits, setLoading } = useContext(); + // Allows behavior override from properties + useEffect(() => { + const context: Partial<ContextValueOnly> = {}; + context.kind = kind; + if (visits) { + context.visits = visits; + context.loading = false; + } else if (loading) { + context.loading = loading; + } + if (numVisitsOpen) context.numVisitsOpen = numVisitsOpen; + if (numVisitsTotal) context.numVisitsTotal = numVisitsTotal; + setContext(state => ({ ...state, ...context })); + }, [setContext, kind, visits, loading, numVisitsOpen, numVisitsTotal]); + + // Fetches data from visitsApi in case visits and loading are not provided + const visitsApi = useApi(visitsApiRef); + const { loading: reqLoading } = useAsync(async () => { + if (!visits && !loading && kind === 'recent') { + return await visitsApi + .list({ + limit: numVisitsTotal ?? 8, + orderBy: [{ field: 'timestamp', direction: 'desc' }], + }) + .then(setVisits); + } + if (!visits && !loading && kind === 'top') { + return await visitsApi + .list({ + limit: numVisitsTotal ?? 8, + orderBy: [{ field: 'hits', direction: 'desc' }], + }) + .then(setVisits); + } + return undefined; + }, [visitsApi, visits, loading, setVisits]); + useEffect(() => { + if (!loading) { + setLoading(reqLoading); + } + }, [loading, setLoading, reqLoading]); + + return <VisitedByType />; +}; diff --git a/plugins/home/src/homePageComponents/VisitedByType/Context.tsx b/plugins/home/src/homePageComponents/VisitedByType/Context.tsx new file mode 100644 index 0000000000..cd316d8b75 --- /dev/null +++ b/plugins/home/src/homePageComponents/VisitedByType/Context.tsx @@ -0,0 +1,122 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React, { Dispatch, SetStateAction, createContext, useMemo } from 'react'; +import { Visit } from '../../api/VisitsApi'; +import { VisitedByTypeKind } from './Content'; + +export type ContextValueOnly = { + collapsed: boolean; + numVisitsOpen: number; + numVisitsTotal: number; + visits: Array<Visit>; + loading: boolean; + kind: VisitedByTypeKind; +}; + +export type ContextValue = ContextValueOnly & { + setCollapsed: Dispatch<SetStateAction<boolean>>; + setNumVisitsOpen: Dispatch<SetStateAction<number>>; + setNumVisitsTotal: Dispatch<SetStateAction<number>>; + setVisits: Dispatch<SetStateAction<Array<Visit>>>; + setLoading: Dispatch<SetStateAction<boolean>>; + setKind: Dispatch<SetStateAction<VisitedByTypeKind>>; + setContext: Dispatch<SetStateAction<ContextValueOnly>>; +}; + +const defaultContextValueOnly: ContextValueOnly = { + collapsed: true, + numVisitsOpen: 3, + numVisitsTotal: 8, + visits: [], + loading: true, + kind: 'recent', +}; + +export const defaultContextValue: ContextValue = { + ...defaultContextValueOnly, + setCollapsed: () => {}, + setNumVisitsOpen: () => {}, + setNumVisitsTotal: () => {}, + setVisits: () => {}, + setLoading: () => {}, + setKind: () => {}, + setContext: () => {}, +}; + +export const Context = createContext<ContextValue>(defaultContextValue); + +const getFilteredSet = + <T,>( + setContext: Dispatch<SetStateAction<ContextValueOnly>>, + contextKey: keyof ContextValueOnly, + ) => + (e: SetStateAction<T>) => + setContext(state => ({ + ...state, + [contextKey]: + typeof e === 'function' ? (e as Function)(state[contextKey]) : e, + })); + +export const ContextProvider = ({ children }: { children: JSX.Element }) => { + const [context, setContext] = React.useState<ContextValueOnly>( + defaultContextValueOnly, + ); + const { + setCollapsed, + setNumVisitsOpen, + setNumVisitsTotal, + setVisits, + setLoading, + setKind, + } = useMemo( + () => ({ + setCollapsed: getFilteredSet(setContext, 'collapsed'), + setNumVisitsOpen: getFilteredSet(setContext, 'numVisitsOpen'), + setNumVisitsTotal: getFilteredSet(setContext, 'numVisitsTotal'), + setVisits: getFilteredSet(setContext, 'visits'), + setLoading: getFilteredSet(setContext, 'loading'), + setKind: getFilteredSet(setContext, 'kind'), + }), + [setContext], + ); + + const value: ContextValue = { + ...context, + setContext, + setCollapsed, + setNumVisitsOpen, + setNumVisitsTotal, + setVisits, + setLoading, + setKind, + }; + + return <Context.Provider value={value}>{children}</Context.Provider>; +}; + +export const useContext = () => { + const value = React.useContext(Context); + + if (value === undefined) + throw new Error( + 'VisitedByType useContext found undefined ContextValue, <ContextProvider/> could be missing', + ); + + return value; +}; + +export default Context; diff --git a/plugins/home/src/homePageComponents/VisitedByType/HomePageVisitedByType.stories.tsx b/plugins/home/src/homePageComponents/VisitedByType/HomePageVisitedByType.stories.tsx new file mode 100644 index 0000000000..d20d5344ae --- /dev/null +++ b/plugins/home/src/homePageComponents/VisitedByType/HomePageVisitedByType.stories.tsx @@ -0,0 +1,207 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { TestApiProvider, wrapInTestApp } from '@backstage/test-utils'; +import { ComponentType, PropsWithChildren } from 'react'; +import { Grid } from '@material-ui/core'; +import { homePlugin } from '../../plugin'; +import { Visit, visitsApiRef } from '../../api/VisitsApi'; +import { createCardExtension } from '@backstage/plugin-home-react'; +import { VisitedByTypeProps } from './Content'; + +const visits: Array<Visit> = [ + { + id: 'tech-radar', + name: 'Tech Radar', + pathname: '/tech-radar', + hits: 40, + timestamp: Date.now() - 360_000, + }, + { + id: 'explore', + name: 'Explore Backstage', + pathname: '/explore', + hits: 35, + timestamp: Date.now() - 86400_000 * 1, + }, + { + id: 'user-1', + name: 'Guest', + pathname: '/catalog/default/user/guest', + hits: 30, + timestamp: Date.now() - 86400_000 * 2, + entityRef: 'User:default/guest', + }, + { + id: 'audio-playback', + name: 'Audio Playback', + pathname: '/catalog/default/system/audio-playback', + hits: 25, + timestamp: Date.now() - 86400_000 * 3, + entityRef: 'System:default/audio-playback', + }, + { + id: 'team-a', + name: 'Team A', + pathname: '/catalog/default/group/team-a', + hits: 20, + timestamp: Date.now() - 86400_000 * 4, + entityRef: 'Group:default/team-a', + }, + { + id: 'playback-order', + name: 'Playback Order', + pathname: '/catalog/default/component/playback-order', + hits: 15, + timestamp: Date.now() - 86400_000 * 5, + entityRef: 'Component:default/playback-order', + }, + { + id: 'playback', + name: 'Playback', + pathname: '/catalog/default/domain/playback', + hits: 10, + timestamp: Date.now() - 86400_000 * 6, + entityRef: 'Domain:default/playback', + }, + { + id: 'hello-world', + name: 'Hello World gRPC', + pathname: '/catalog/default/api/hello-world', + hits: 1, + timestamp: Date.now() - 86400_000 * 7, + entityRef: 'API:default/hello-world', + }, +]; + +const HomePageVisitedByType = homePlugin.provide( + createCardExtension<VisitedByTypeProps>({ + name: 'HomePageTopVisited', + components: () => import('./'), + }), +); + +const mockVisitsApi = { + save: async () => visits[0], + list: async () => visits, +}; + +export default { + title: 'Plugins/Home/Components/VisitedByType', + decorators: [ + (Story: ComponentType<PropsWithChildren<{}>>) => + wrapInTestApp( + <TestApiProvider apis={[[visitsApiRef, mockVisitsApi]]}> + <Story /> + </TestApiProvider>, + ), + ], +}; + +export const RecentlyDefault = () => { + return ( + <Grid item xs={12} md={6}> + <HomePageVisitedByType kind="recent" /> + </Grid> + ); +}; + +export const RecentlyEmpty = () => { + return ( + <Grid item xs={12} md={6}> + <HomePageVisitedByType kind="recent" visits={[]} /> + </Grid> + ); +}; + +export const RecentlyFewItems = () => { + return ( + <Grid item xs={12} md={6}> + <HomePageVisitedByType kind="recent" visits={visits.slice(0, 1)} /> + </Grid> + ); +}; + +export const RecentlyMoreItems = () => { + return ( + <Grid item xs={12} md={6}> + <HomePageVisitedByType + kind="recent" + numVisitsOpen={5} + numVisitsTotal={6} + /> + </Grid> + ); +}; + +export const RecentlyLoading = () => { + return ( + <Grid item xs={12} md={6}> + <HomePageVisitedByType + kind="recent" + numVisitsOpen={5} + numVisitsTotal={6} + loading + /> + </Grid> + ); +}; + +export const TopDefault = () => { + return ( + <Grid item xs={12} md={6}> + <HomePageVisitedByType kind="top" /> + </Grid> + ); +}; + +export const TopEmpty = () => { + return ( + <Grid item xs={12} md={6}> + <HomePageVisitedByType kind="top" visits={[]} /> + </Grid> + ); +}; + +export const TopFewItems = () => { + return ( + <Grid item xs={12} md={6}> + <HomePageVisitedByType kind="top" visits={visits.slice(0, 1)} /> + </Grid> + ); +}; + +export const TopMoreItems = () => { + return ( + <Grid item xs={12} md={6}> + <HomePageVisitedByType kind="top" numVisitsOpen={5} numVisitsTotal={6} /> + </Grid> + ); +}; + +export const TopLoading = () => { + return ( + <Grid item xs={12} md={6}> + <HomePageVisitedByType + kind="top" + numVisitsOpen={5} + numVisitsTotal={6} + loading + /> + </Grid> + ); +}; diff --git a/plugins/home/src/homePageComponents/VisitedByType/RecentlyVisited.tsx b/plugins/home/src/homePageComponents/VisitedByType/RecentlyVisited.tsx new file mode 100644 index 0000000000..a6896f4e91 --- /dev/null +++ b/plugins/home/src/homePageComponents/VisitedByType/RecentlyVisited.tsx @@ -0,0 +1,27 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { Actions } from './Actions'; +export { ContextProvider } from './Context'; +export type { VisitedByTypeProps, VisitedByTypeKind } from './Content'; +import React from 'react'; +import { Content, VisitedByTypeProps } from './Content'; + +const RecentlyVisitedContent = (props: Partial<VisitedByTypeProps>) => ( + <Content {...props} kind="recent" /> +); + +export { RecentlyVisitedContent as Content }; diff --git a/plugins/cost-insights/src/options.ts b/plugins/home/src/homePageComponents/VisitedByType/TopVisited.tsx similarity index 57% rename from plugins/cost-insights/src/options.ts rename to plugins/home/src/homePageComponents/VisitedByType/TopVisited.tsx index acc977771d..5a326abf51 100644 --- a/plugins/cost-insights/src/options.ts +++ b/plugins/home/src/homePageComponents/VisitedByType/TopVisited.tsx @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Backstage Authors + * Copyright 2023 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,16 +14,14 @@ * limitations under the License. */ -import { usePluginOptions } from '@backstage/core-plugin-api/alpha'; +export { Actions } from './Actions'; +export { ContextProvider } from './Context'; +export type { VisitedByTypeProps, VisitedByTypeKind } from './Content'; +import React from 'react'; +import { Content, VisitedByTypeProps } from './Content'; -export type CostInsightsPluginOptions = { - hideTrendLine?: boolean; -}; +const TopVisitedContent = (props: Partial<VisitedByTypeProps>) => ( + <Content {...props} kind="top" /> +); -/** @ignore */ -export type CostInsightsInputPluginOptions = { - hideTrendLine?: boolean; -}; - -export const useCostInsightsOptions = () => - usePluginOptions<CostInsightsPluginOptions>(); +export { TopVisitedContent as Content }; diff --git a/plugins/home/src/homePageComponents/VisitedByType/VisitedByType.test.tsx b/plugins/home/src/homePageComponents/VisitedByType/VisitedByType.test.tsx new file mode 100644 index 0000000000..9e363f55aa --- /dev/null +++ b/plugins/home/src/homePageComponents/VisitedByType/VisitedByType.test.tsx @@ -0,0 +1,89 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { VisitedByType } from './VisitedByType'; +import { Context, defaultContextValue } from './Context'; +import { renderInTestApp } from '@backstage/test-utils'; +import { waitFor } from '@testing-library/react'; + +describe('<VisitedByType/> kind="top"', () => { + it('should render', async () => { + const { getByText } = await renderInTestApp( + <Context.Provider value={{ ...defaultContextValue, kind: 'top' }}> + <VisitedByType /> + </Context.Provider>, + ); + expect(getByText('Top Visited')).toBeInTheDocument(); + }); + it('should display hits', async () => { + const { getByText } = await renderInTestApp( + <Context.Provider + value={{ + ...defaultContextValue, + kind: 'top', + loading: false, + visits: [ + { + id: 'tech-radar', + name: 'Tech Radar', + pathname: '/tech-radar', + hits: 40, + timestamp: Date.now() - 360_000, + }, + ], + }} + > + <VisitedByType /> + </Context.Provider>, + ); + await waitFor(() => expect(getByText('40 times')).toBeInTheDocument()); + }); +}); + +describe('<VisitedByType/> kind="recent"', () => { + it('should render', async () => { + const { getByText } = await renderInTestApp( + <Context.Provider value={{ ...defaultContextValue, kind: 'recent' }}> + <VisitedByType /> + </Context.Provider>, + ); + expect(getByText('Recently Visited')).toBeInTheDocument(); + }); + it('should display how long ago a visit happened', async () => { + const { getByText } = await renderInTestApp( + <Context.Provider + value={{ + ...defaultContextValue, + kind: 'recent', + loading: false, + visits: [ + { + id: 'tech-radar', + name: 'Tech Radar', + pathname: '/tech-radar', + hits: 40, + timestamp: Date.now() - 86400_000, + }, + ], + }} + > + <VisitedByType /> + </Context.Provider>, + ); + await waitFor(() => expect(getByText('1 day ago')).toBeInTheDocument()); + }); +}); diff --git a/plugins/home/src/homePageComponents/VisitedByType/VisitedByType.tsx b/plugins/home/src/homePageComponents/VisitedByType/VisitedByType.tsx new file mode 100644 index 0000000000..23d7f3fffd --- /dev/null +++ b/plugins/home/src/homePageComponents/VisitedByType/VisitedByType.tsx @@ -0,0 +1,36 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { VisitList } from '../../components/VisitList'; +import { useContext } from './Context'; + +export const VisitedByType = () => { + const { collapsed, numVisitsOpen, numVisitsTotal, visits, loading, kind } = + useContext(); + + return ( + <VisitList + visits={visits} + title={kind === 'top' ? 'Top Visited' : 'Recently Visited'} + detailType={kind === 'top' ? 'hits' : 'time-ago'} + collapsed={collapsed} + numVisitsOpen={numVisitsOpen} + numVisitsTotal={numVisitsTotal} + loading={loading} + /> + ); +}; diff --git a/plugins/home/src/homePageComponents/VisitedByType/index.ts b/plugins/home/src/homePageComponents/VisitedByType/index.ts new file mode 100644 index 0000000000..f085007522 --- /dev/null +++ b/plugins/home/src/homePageComponents/VisitedByType/index.ts @@ -0,0 +1,20 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { Content } from './Content'; +export { Actions } from './Actions'; +export { ContextProvider } from './Context'; +export type { VisitedByTypeProps, VisitedByTypeKind } from './Content'; diff --git a/plugins/home/src/homePageComponents/index.ts b/plugins/home/src/homePageComponents/index.ts index 36d2335afe..9149afa295 100644 --- a/plugins/home/src/homePageComponents/index.ts +++ b/plugins/home/src/homePageComponents/index.ts @@ -17,3 +17,4 @@ export type { ToolkitContentProps, Tool } from './Toolkit'; export type { ClockConfig } from './HeaderWorldClock'; export type { WelcomeTitleLanguageProps } from './WelcomeTitle'; +export type { VisitedByTypeProps, VisitedByTypeKind } from './VisitedByType'; diff --git a/plugins/home/src/index.ts b/plugins/home/src/index.ts index 63407c8531..a80f8bd93d 100644 --- a/plugins/home/src/index.ts +++ b/plugins/home/src/index.ts @@ -32,8 +32,11 @@ export { ComponentTab, WelcomeTitle, HeaderWorldClock, + HomePageTopVisited, + HomePageRecentlyVisited, } from './plugin'; export * from './components'; export * from './assets'; export * from './homePageComponents'; export * from './deprecated'; +export * from './api'; diff --git a/plugins/home/src/plugin.ts b/plugins/home/src/plugin.ts index 74a1c11390..ab8c46baa1 100644 --- a/plugins/home/src/plugin.ts +++ b/plugins/home/src/plugin.ts @@ -15,17 +15,32 @@ */ import { + createApiFactory, createComponentExtension, createPlugin, createRoutableExtension, + identityApiRef, + storageApiRef, } from '@backstage/core-plugin-api'; import { createCardExtension } from '@backstage/plugin-home-react'; -import { ToolkitContentProps } from './homePageComponents'; +import { ToolkitContentProps, VisitedByTypeProps } from './homePageComponents'; import { rootRouteRef } from './routes'; +import { VisitsStorageApi, visitsApiRef } from './api'; /** @public */ export const homePlugin = createPlugin({ id: 'home', + apis: [ + createApiFactory({ + api: visitsApiRef, + deps: { + storageApi: storageApiRef, + identityApi: identityApiRef, + }, + factory: ({ storageApi, identityApi }) => + VisitsStorageApi.create({ storageApi, identityApi }), + }), + ], routes: { root: rootRouteRef, }, @@ -172,3 +187,26 @@ export const HeaderWorldClock = homePlugin.provide( }, }), ); + +/** + * Display top visited pages for the homepage + * @public + */ +export const HomePageTopVisited = homePlugin.provide( + createCardExtension<Partial<VisitedByTypeProps>>({ + name: 'HomePageTopVisited', + components: () => import('./homePageComponents/VisitedByType/TopVisited'), + }), +); + +/** + * Display recently visited pages for the homepage + * @public + */ +export const HomePageRecentlyVisited = homePlugin.provide( + createCardExtension<Partial<VisitedByTypeProps>>({ + name: 'HomePageRecentlyVisited', + components: () => + import('./homePageComponents/VisitedByType/RecentlyVisited'), + }), +); diff --git a/plugins/ilert/CHANGELOG.md b/plugins/ilert/CHANGELOG.md index 45fe31099a..31cace8de8 100644 --- a/plugins/ilert/CHANGELOG.md +++ b/plugins/ilert/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-ilert +## 0.2.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## 0.2.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + ## 0.2.13 ### Patch Changes diff --git a/plugins/ilert/api-report.md b/plugins/ilert/api-report.md index b2081e049e..821a3a6bd0 100644 --- a/plugins/ilert/api-report.md +++ b/plugins/ilert/api-report.md @@ -539,7 +539,6 @@ const ilertPlugin: BackstagePlugin< { root: RouteRef<undefined>; }, - {}, {} >; export { ilertPlugin }; diff --git a/plugins/ilert/package.json b/plugins/ilert/package.json index 34af0e4a5a..f84a79375d 100644 --- a/plugins/ilert/package.json +++ b/plugins/ilert/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-ilert", "description": "A Backstage plugin that integrates towards iLert", - "version": "0.2.13", + "version": "0.2.14-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/jenkins-backend/CHANGELOG.md b/plugins/jenkins-backend/CHANGELOG.md index f1ded9df99..b0aeddb339 100644 --- a/plugins/jenkins-backend/CHANGELOG.md +++ b/plugins/jenkins-backend/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/plugin-jenkins-backend +## 0.2.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/plugin-permission-node@0.7.16-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/plugin-jenkins-common@0.1.19 + - @backstage/plugin-permission-common@0.7.8 + +## 0.2.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/plugin-jenkins-common@0.1.19 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-permission-node@0.7.16-next.0 + ## 0.2.6 ### Patch Changes diff --git a/plugins/jenkins-backend/package.json b/plugins/jenkins-backend/package.json index 542907781e..12fe2debe1 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.2.6", + "version": "0.2.8-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/jenkins/CHANGELOG.md b/plugins/jenkins/CHANGELOG.md index a43b0f7031..c7b92cbcdd 100644 --- a/plugins/jenkins/CHANGELOG.md +++ b/plugins/jenkins/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/plugin-jenkins +## 0.8.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-jenkins-common@0.1.19 + +## 0.8.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-jenkins-common@0.1.19 + ## 0.8.6 ### Patch Changes diff --git a/plugins/jenkins/api-report.md b/plugins/jenkins/api-report.md index bbfc2e8802..2274c11e13 100644 --- a/plugins/jenkins/api-report.md +++ b/plugins/jenkins/api-report.md @@ -101,7 +101,6 @@ const jenkinsPlugin: BackstagePlugin< { entityContent: RouteRef<undefined>; }, - {}, {} >; export { jenkinsPlugin }; diff --git a/plugins/jenkins/package.json b/plugins/jenkins/package.json index b936aa80b3..cfbac50ae5 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.8.6", + "version": "0.8.7-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/kafka-backend/CHANGELOG.md b/plugins/kafka-backend/CHANGELOG.md index 63abf0bcc5..bccda7319f 100644 --- a/plugins/kafka-backend/CHANGELOG.md +++ b/plugins/kafka-backend/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-kafka-backend +## 0.3.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + +## 0.3.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + ## 0.3.0 ### Minor Changes diff --git a/plugins/kafka-backend/package.json b/plugins/kafka-backend/package.json index a27f72fc9a..d965258859 100644 --- a/plugins/kafka-backend/package.json +++ b/plugins/kafka-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kafka-backend", "description": "A Backstage backend plugin that integrates towards Kafka", - "version": "0.3.0", + "version": "0.3.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/kafka/CHANGELOG.md b/plugins/kafka/CHANGELOG.md index b4acb676c3..adb941bc3f 100644 --- a/plugins/kafka/CHANGELOG.md +++ b/plugins/kafka/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-kafka +## 0.3.25-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## 0.3.25-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + ## 0.3.24 ### Patch Changes diff --git a/plugins/kafka/api-report.md b/plugins/kafka/api-report.md index 990a4da295..ba0c9a3820 100644 --- a/plugins/kafka/api-report.md +++ b/plugins/kafka/api-report.md @@ -28,7 +28,6 @@ const kafkaPlugin: BackstagePlugin< { entityContent: RouteRef<undefined>; }, - {}, {} >; export { kafkaPlugin }; diff --git a/plugins/kafka/package.json b/plugins/kafka/package.json index ae8e602ce5..5e699b3bcc 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.24", + "version": "0.3.25-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/kubernetes-backend/CHANGELOG.md b/plugins/kubernetes-backend/CHANGELOG.md index 710d104033..cef2f97198 100644 --- a/plugins/kubernetes-backend/CHANGELOG.md +++ b/plugins/kubernetes-backend/CHANGELOG.md @@ -1,5 +1,43 @@ # @backstage/plugin-kubernetes-backend +## 0.12.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/plugin-kubernetes-common@0.7.0-next.0 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/plugin-permission-node@0.7.16-next.1 + - @backstage/config@1.1.0 + - @backstage/integration-aws-node@0.1.6 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.8 + +## 0.12.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/integration-aws-node@0.1.6 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-node@1.4.6-next.0 + - @backstage/plugin-kubernetes-common@0.6.6 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-permission-node@0.7.16-next.0 + ## 0.12.0 ### Minor Changes diff --git a/plugins/kubernetes-backend/package.json b/plugins/kubernetes-backend/package.json index dce7b512fd..e0df3aa94b 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.12.0", + "version": "0.12.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts b/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts index 85a4326d60..c676cc6246 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts @@ -520,6 +520,26 @@ metadata: expect(response.body).toStrictEqual({ items: [] }); }); + + it('should not permit custom auth strategies with dashes', async () => { + const throwError = () => + KubernetesBuilder.createBuilder({ + logger: getVoidLogger(), + config, + catalogApi, + permissions, + }).addAuthStrategy('custom-strategy', { + getCredential: jest + .fn< + Promise<KubernetesCredential>, + [ClusterDetails, KubernetesRequestAuth] + >() + .mockResolvedValue({ type: 'anonymous' }), + validateCluster: jest.fn().mockReturnValue([]), + }); + + expect(throwError).toThrow('Strategy name can not include dashes'); + }); }); describe('get /.well-known/backstage/permissions/metadata', () => { it('lists permissions supported by the kubernetes plugin', async () => { diff --git a/plugins/kubernetes-backend/src/service/KubernetesBuilder.ts b/plugins/kubernetes-backend/src/service/KubernetesBuilder.ts index f3766d8513..9ac1bf6e5d 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesBuilder.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesBuilder.ts @@ -205,6 +205,9 @@ export class KubernetesBuilder { } public addAuthStrategy(key: string, strategy: AuthenticationStrategy) { + if (key.includes('-')) { + throw new Error('Strategy name can not include dashes'); + } this.getAuthStrategyMap()[key] = strategy; return this; } diff --git a/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts b/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts index 327d580d10..27d57cd854 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts @@ -509,6 +509,134 @@ describe('KubernetesProxy', () => { }); }); + it('should invoke AuthStrategy if Backstage-Kubernetes-Authorization-X-X are provided', async () => { + const strategy: jest.Mocked<AuthenticationStrategy> = { + getCredential: jest + .fn() + .mockReturnValue({ type: 'bearer token', token: 'MY_TOKEN3' }), + validateCluster: jest.fn(), + }; + + proxy = new KubernetesProxy({ + logger: getVoidLogger(), + clusterSupplier: clusterSupplier, + authStrategy: strategy, + }); + + worker.use( + rest.get('https://localhost:9999/api/v1/namespaces', (req, res, ctx) => { + if (!req.headers.get('Authorization')) { + return res(ctx.status(401)); + } + + if (req.headers.get('Authorization') !== 'Bearer MY_TOKEN3') { + return res(ctx.status(403)); + } + + return res( + ctx.status(200), + ctx.json({ + kind: 'NamespaceList', + apiVersion: 'v1', + items: [], + }), + ); + }), + ); + + clusterSupplier.getClusters.mockResolvedValue([ + { + name: 'cluster1', + url: 'https://localhost:9999', + authMetadata: {}, + }, + ]); + + const requestPromise = setupProxyPromise({ + proxyPath: '/mountpath', + requestPath: '/api/v1/namespaces', + + headers: { + [HEADER_KUBERNETES_CLUSTER]: 'cluster1', + 'Backstage-Kubernetes-Authorization-google': 'MY_TOKEN1', + 'Backstage-Kubernetes-Authorization-aks': 'MY_TOKEN2', + 'Backstage-Kubernetes-Authorization-oidc-okta': 'MY_TOKEN3', + 'Backstage-Kubernetes-Authorization-oidc-gitlab': 'MY_TOKEN4', + 'Backstage-Kubernetes-Authorization-pinniped-audience1': 'MY_TOKEN5', + 'Backstage-Kubernetes-Authorization-pinniped-au-b-c-d-e': 'MY_TOKEN6', + }, + }); + + const response = await requestPromise; + + const authObj = { + google: 'MY_TOKEN1', + aks: 'MY_TOKEN2', + oidc: { okta: 'MY_TOKEN3', gitlab: 'MY_TOKEN4' }, + pinniped: { audience1: 'MY_TOKEN5', 'au-b-c-d-e': 'MY_TOKEN6' }, + }; + + expect(strategy.getCredential).toHaveBeenCalledTimes(1); + expect(strategy.getCredential).toHaveBeenCalledWith( + expect.anything(), + authObj, + ); + expect(response.status).toEqual(200); + expect(response.body).toStrictEqual({ + kind: 'NamespaceList', + apiVersion: 'v1', + items: [], + }); + }); + + it('should invoke the Auth strategy with an empty auth object when no Backstage-Kubernetes-Authorization-X-X are provided', async () => { + worker.use( + rest.get('https://localhost:9999/api/v1/namespaces', (_, res, ctx) => { + return res( + ctx.status(200), + ctx.json({ + kind: 'NamespaceList', + apiVersion: 'v1', + items: [], + }), + ); + }), + ); + + clusterSupplier.getClusters.mockResolvedValue([ + { + name: 'cluster1', + url: 'https://localhost:9999', + authMetadata: {}, + }, + ]); + + const requestPromise = setupProxyPromise({ + proxyPath: '/mountpath', + requestPath: '/api/v1/namespaces', + + headers: { + [HEADER_KUBERNETES_CLUSTER]: 'cluster1', + }, + }); + + const response = await requestPromise; + + const authObj = {}; + + expect(authStrategy.getCredential).toHaveBeenCalledTimes(1); + expect(authStrategy.getCredential).toHaveBeenCalledWith( + expect.anything(), + authObj, + ); + expect(response.status).toEqual(200); + expect(response.body).toStrictEqual({ + kind: 'NamespaceList', + apiVersion: 'v1', + items: [], + }); + }); + it('returns a response with a localKubectlProxy auth provider configuration', async () => { proxy = new KubernetesProxy({ logger: getVoidLogger(), diff --git a/plugins/kubernetes-backend/src/service/KubernetesProxy.ts b/plugins/kubernetes-backend/src/service/KubernetesProxy.ts index d2a3649c27..8a07267cde 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesProxy.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesProxy.ts @@ -21,7 +21,10 @@ import { serializeError, } from '@backstage/errors'; import { getBearerTokenFromAuthorizationHeader } from '@backstage/plugin-auth-node'; -import { kubernetesProxyPermission } from '@backstage/plugin-kubernetes-common'; +import { + KubernetesRequestAuth, + kubernetesProxyPermission, +} from '@backstage/plugin-kubernetes-common'; import { AuthorizeResult, PermissionEvaluator, @@ -34,6 +37,7 @@ import { AuthenticationStrategy } from '../auth'; import { ClusterDetails, KubernetesClustersSupplier } from '../types/types'; import type { Request } from 'express'; +import { IncomingHttpHeaders } from 'http'; export const APPLICATION_JSON: string = 'application/json'; @@ -113,9 +117,15 @@ export class KubernetesProxy { if (authHeader) { req.headers.authorization = authHeader; } else { + // Map Backstage-Kubernetes-Authorization-X-X headers to a KubernetesRequestAuth object + const authObj = KubernetesProxy.authHeadersToKubernetesRequestAuth( + req.headers, + ); + const credential = await this.getClusterForRequest(req).then(cd => { - return this.authStrategy.getCredential(cd, {}); + return this.authStrategy.getCredential(cd, authObj); }); + if (credential.type === 'bearer token') { req.headers.authorization = `Bearer ${credential.token}`; } @@ -221,4 +231,52 @@ export class KubernetesProxy { return cluster; } + + private static authHeadersToKubernetesRequestAuth( + originalHeaders: IncomingHttpHeaders, + ): KubernetesRequestAuth { + return Object.keys(originalHeaders) + .filter(header => header.startsWith('backstage-kubernetes-authorization')) + .map(header => + KubernetesProxy.headerToDictionary(header, originalHeaders), + ) + .filter(headerAsDic => Object.keys(headerAsDic).length !== 0) + .reduce(KubernetesProxy.combineHeaders, {}); + } + + private static headerToDictionary( + header: string, + originalHeaders: IncomingHttpHeaders, + ): KubernetesRequestAuth { + const obj: KubernetesRequestAuth = {}; + const headerSplitted = header.split('-'); + if (headerSplitted.length >= 4) { + const framework = headerSplitted[3].toLowerCase(); + if (headerSplitted.length >= 5) { + const provider = headerSplitted.slice(4).join('-').toLowerCase(); + obj[framework] = { [provider]: originalHeaders[header] }; + } else { + obj[framework] = originalHeaders[header]; + } + } + return obj; + } + + private static combineHeaders( + authObj: any, + header: any, + ): KubernetesRequestAuth { + const framework = Object.keys(header)[0]; + + if (authObj[framework]) { + authObj[framework] = { + ...authObj[framework], + ...header[framework], + }; + } else { + authObj[framework] = header[framework]; + } + + return authObj; + } } diff --git a/plugins/kubernetes-cluster/.eslintrc.js b/plugins/kubernetes-cluster/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/kubernetes-cluster/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/kubernetes-cluster/api-report.md b/plugins/kubernetes-cluster/api-report.md new file mode 100644 index 0000000000..10d248097a --- /dev/null +++ b/plugins/kubernetes-cluster/api-report.md @@ -0,0 +1,24 @@ +## API Report File for "@backstage/plugin-kubernetes-cluster" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +/// <reference types="react" /> + +import { Entity } from '@backstage/catalog-model'; +import { default as React_2 } from 'react'; + +// @public +export const EntityKubernetesClusterContent: ( + props: EntityKubernetesClusterContentProps, +) => JSX.Element; + +// @public +export type EntityKubernetesClusterContentProps = {}; + +// @public (undocumented) +export const isKubernetesClusterAvailable: (entity: Entity) => boolean; + +// @public (undocumented) +export const Router: () => React_2.JSX.Element; +``` diff --git a/plugins/kubernetes-cluster/catalog-info.yaml b/plugins/kubernetes-cluster/catalog-info.yaml new file mode 100644 index 0000000000..3da5102e46 --- /dev/null +++ b/plugins/kubernetes-cluster/catalog-info.yaml @@ -0,0 +1,10 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: backstage-plugin-kubernetes-cluster + title: '@backstage/plugin-kubernetes-cluster' + description: A Backstage plugin that integrates towards Kubernetes clusters +spec: + lifecycle: experimental + type: backstage-frontend-plugin + owner: kubernetes-maintainers diff --git a/plugins/kubernetes-cluster/package.json b/plugins/kubernetes-cluster/package.json new file mode 100644 index 0000000000..2e1c8d8309 --- /dev/null +++ b/plugins/kubernetes-cluster/package.json @@ -0,0 +1,80 @@ +{ + "name": "@backstage/plugin-kubernetes-cluster", + "description": "A Backstage plugin that shows details of Kubernetes clusters", + "version": "0.0.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" + }, + "homepage": "https://backstage.io", + "repository": { + "type": "git", + "url": "https://github.com/backstage/backstage", + "directory": "plugins/kubernetes-cluster" + }, + "keywords": [ + "backstage", + "kubernetes" + ], + "sideEffects": false, + "scripts": { + "build": "backstage-cli package build", + "start": "backstage-cli package start", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" + }, + "dependencies": { + "@backstage/catalog-model": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/core-components": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/plugin-catalog-react": "workspace:^", + "@backstage/plugin-kubernetes-common": "workspace:^", + "@backstage/plugin-kubernetes-react": "workspace:^", + "@backstage/theme": "workspace:^", + "@kubernetes-models/apimachinery": "^1.1.0", + "@kubernetes-models/base": "^4.0.1", + "@material-ui/core": "^4.12.2", + "@material-ui/icons": "^4.9.1", + "@material-ui/lab": "4.0.0-alpha.61", + "@types/react": "^16.13.1 || ^17.0.0", + "cronstrue": "^2.2.0", + "js-yaml": "^4.0.0", + "kubernetes-models": "^4.1.0", + "lodash": "^4.17.21", + "luxon": "^3.0.0", + "react-use": "^17.2.4" + }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0", + "react-dom": "^16.13.1 || ^17.0.0", + "react-router-dom": "6.0.0-beta.0 || ^6.3.0" + }, + "devDependencies": { + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", + "@testing-library/dom": "^8.0.0", + "@testing-library/jest-dom": "^5.10.1", + "@testing-library/react": "^12.1.3", + "@testing-library/react-hooks": "^8.0.0", + "@testing-library/user-event": "^14.0.0", + "@types/node": "^16.11.26", + "msw": "^1.0.0" + }, + "files": [ + "dist" + ] +} diff --git a/plugins/kubernetes-cluster/src/Router.tsx b/plugins/kubernetes-cluster/src/Router.tsx new file mode 100644 index 0000000000..86563439ce --- /dev/null +++ b/plugins/kubernetes-cluster/src/Router.tsx @@ -0,0 +1,56 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { Entity } from '@backstage/catalog-model'; +import { useEntity } from '@backstage/plugin-catalog-react'; +import { Route, Routes } from 'react-router-dom'; +import { MissingAnnotationEmptyState } from '@backstage/core-components'; +import { ANNOTATION_KUBERNETES_API_SERVER } from '@backstage/plugin-kubernetes-common'; +import { KubernetesClusterContent } from './components/KubernetesClusterContent'; + +/** + * + * + * @public + */ +export const isKubernetesClusterAvailable = (entity: Entity) => + Boolean(entity.metadata.annotations?.[ANNOTATION_KUBERNETES_API_SERVER]); + +/** + * + * + * @public + */ +export const Router = () => { + const { entity } = useEntity(); + + if (isKubernetesClusterAvailable(entity)) { + return ( + <Routes> + <Route path="/" element={<KubernetesClusterContent />} /> + </Routes> + ); + } + + return ( + <> + <MissingAnnotationEmptyState + annotation={ANNOTATION_KUBERNETES_API_SERVER} + /> + </> + ); +}; diff --git a/plugins/kubernetes-cluster/src/components/ApiResources/ApiResources.test.tsx b/plugins/kubernetes-cluster/src/components/ApiResources/ApiResources.test.tsx new file mode 100644 index 0000000000..601ba54a6d --- /dev/null +++ b/plugins/kubernetes-cluster/src/components/ApiResources/ApiResources.test.tsx @@ -0,0 +1,64 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; +import { renderInTestApp } from '@backstage/test-utils'; +import { ApiResources } from './ApiResources'; +import '@testing-library/jest-dom'; + +jest.mock('@backstage/plugin-catalog-react', () => ({ + useEntity: () => { + return { + entity: { + metadata: { + name: 'some-cluster', + }, + }, + }; + }, +})); + +jest.mock('./useApiResources', () => ({ + useApiResources: jest.fn().mockReturnValue({ + loading: false, + value: { + groups: [ + { + name: 'some-apiVersion', + preferredVersion: { + groupVersion: 'some-group-version', + }, + }, + ], + }, + }), +})); + +describe('ApiResources', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + it('displays ApiResources', async () => { + const { getByText } = await renderInTestApp(<ApiResources />); + + // Title + expect(getByText('Name')).toBeInTheDocument(); + expect(getByText('Preferred Version')).toBeInTheDocument(); + + // Row 1 + expect(getByText('some-apiVersion')).toBeInTheDocument(); + expect(getByText('some-group-version')).toBeInTheDocument(); + }); +}); diff --git a/plugins/kubernetes-cluster/src/components/ApiResources/ApiResources.tsx b/plugins/kubernetes-cluster/src/components/ApiResources/ApiResources.tsx new file mode 100644 index 0000000000..f6e8bc65ce --- /dev/null +++ b/plugins/kubernetes-cluster/src/components/ApiResources/ApiResources.tsx @@ -0,0 +1,80 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { useApiResources } from './useApiResources'; +import React, { useCallback, useEffect } from 'react'; +import { useEntity } from '@backstage/plugin-catalog-react'; +import { Table, TableColumn } from '@backstage/core-components'; +import { IAPIGroup } from '@kubernetes-models/apimachinery/apis/meta/v1'; +import { useKubernetesClusterError } from '../KubernetesClusterErrorContext/KubernetesClusterErrorContext'; +import { makeStyles } from '@material-ui/core'; + +const useStyles = makeStyles(theme => ({ + empty: { + padding: theme.spacing(2), + display: 'flex', + justifyContent: 'center', + }, +})); + +const defaultColumns: TableColumn<IAPIGroup>[] = [ + { + title: 'Name', + highlight: true, + render: (apiGroup: IAPIGroup) => { + return apiGroup.name; + }, + }, + { + title: 'Preferred Version', + highlight: true, + render: (apiGroup: IAPIGroup) => { + return apiGroup.preferredVersion?.groupVersion; + }, + }, +]; + +export const ApiResources = () => { + const classes = useStyles(); + const { entity } = useEntity(); + const { setError } = useKubernetesClusterError(); + const setErrorCallback = useCallback(setError, [setError]); + const { value, error, loading } = useApiResources({ + clusterName: entity.metadata.name, + }); + + useEffect(() => { + if (error) { + setErrorCallback(error.message); + } + }, [error, setErrorCallback]); + + return ( + <Table + title="API Resources" + options={{ paging: true, search: false, emptyRowsWhenPaging: false }} + isLoading={!value && loading} + data={value?.groups ?? []} + emptyContent={ + <div className={classes.empty}> + {error !== undefined + ? 'Error loading API Resources' + : 'No API Resources found'} + </div> + } + columns={defaultColumns} + /> + ); +}; diff --git a/plugins/kubernetes-cluster/src/components/ApiResources/useApiResources.ts b/plugins/kubernetes-cluster/src/components/ApiResources/useApiResources.ts new file mode 100644 index 0000000000..b28b0b0b67 --- /dev/null +++ b/plugins/kubernetes-cluster/src/components/ApiResources/useApiResources.ts @@ -0,0 +1,48 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import useAsync from 'react-use/lib/useAsync'; + +import { useApi } from '@backstage/core-plugin-api'; +import { kubernetesApiRef } from '@backstage/plugin-kubernetes-react'; +import { IAPIGroupList } from '@kubernetes-models/apimachinery/apis/meta/v1'; + +/** + * Arguments for useApiResources + * + * @public + */ +export interface ApiResourcesOptions { + clusterName: string; +} + +/** + * Retrieves the logs for the given pod + * + * @public + */ +export const useApiResources = ({ clusterName }: ApiResourcesOptions) => { + const kubernetesApi = useApi(kubernetesApiRef); + return useAsync(async () => { + return await kubernetesApi + .proxy({ + clusterName, + path: '/apis', + }) + .then(r => { + return r.json() as Promise<IAPIGroupList>; + }); + }, [clusterName]); +}; diff --git a/plugins/kubernetes-cluster/src/components/ClusterOverview/ClusterOverview.test.tsx b/plugins/kubernetes-cluster/src/components/ClusterOverview/ClusterOverview.test.tsx new file mode 100644 index 0000000000..6398093a74 --- /dev/null +++ b/plugins/kubernetes-cluster/src/components/ClusterOverview/ClusterOverview.test.tsx @@ -0,0 +1,60 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; +import { renderInTestApp } from '@backstage/test-utils'; +import { ClusterOverview } from './ClusterOverview'; +import '@testing-library/jest-dom'; + +jest.mock('@backstage/plugin-catalog-react', () => ({ + useEntity: () => { + return { + entity: { + metadata: { + name: 'some-cluster', + }, + }, + }; + }, +})); + +jest.mock('./useCluster', () => ({ + useCluster: jest.fn().mockReturnValue({ + loading: false, + value: { + name: 'some-cluster', + authProvider: 'google', + }, + }), +})); + +describe('ClusterOverview', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + it('displays ClusterOverview', async () => { + const { getByText, queryAllByText } = await renderInTestApp( + <ClusterOverview />, + ); + + expect(getByText('Name')).toBeInTheDocument(); + expect(getByText('some-cluster')).toBeInTheDocument(); + expect(getByText('Backstage Auth Provider')).toBeInTheDocument(); + expect(getByText('google')).toBeInTheDocument(); + expect(getByText('OIDC Token Provider')).toBeInTheDocument(); + expect(getByText('Dashboard Link')).toBeInTheDocument(); + expect(queryAllByText('N/A')).toHaveLength(2); + }); +}); diff --git a/plugins/kubernetes-cluster/src/components/ClusterOverview/ClusterOverview.tsx b/plugins/kubernetes-cluster/src/components/ClusterOverview/ClusterOverview.tsx new file mode 100644 index 0000000000..a4d4ffc40c --- /dev/null +++ b/plugins/kubernetes-cluster/src/components/ClusterOverview/ClusterOverview.tsx @@ -0,0 +1,65 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React, { useCallback, useEffect } from 'react'; +import { InfoCard, StructuredMetadataTable } from '@backstage/core-components'; +import { useEntity } from '@backstage/plugin-catalog-react'; +import { useCluster } from './useCluster'; +import { Skeleton } from '@material-ui/lab'; +import { Theme, createStyles, makeStyles } from '@material-ui/core'; +import { useKubernetesClusterError } from '../KubernetesClusterErrorContext/KubernetesClusterErrorContext'; + +const useStyles = makeStyles((_theme: Theme) => + createStyles({ + root: { + height: '100%', + }, + }), +); + +export const ClusterOverview = () => { + const classes = useStyles(); + const { entity } = useEntity(); + const { value, loading, error } = useCluster({ + clusterName: entity.metadata.name, + }); + const { setError } = useKubernetesClusterError(); + const setErrorCallback = useCallback(setError, [setError]); + useEffect(() => { + if (error) { + setErrorCallback(error.message); + } + }, [error, setErrorCallback]); + + return ( + <InfoCard title="Cluster Overview" className={classes.root}> + {!value && loading && ( + <> + <Skeleton height="35rem" /> + </> + )} + {value && ( + <StructuredMetadataTable + metadata={{ + name: value.name, + 'Backstage auth provider': value.authProvider, + 'OIDC Token Provider': value.oidcTokenProvider ?? 'N/A', + 'Dashboard Link': value.dashboardUrl ?? 'N/A', + }} + /> + )} + </InfoCard> + ); +}; diff --git a/plugins/kubernetes-cluster/src/components/ClusterOverview/index.ts b/plugins/kubernetes-cluster/src/components/ClusterOverview/index.ts new file mode 100644 index 0000000000..5a46125f3e --- /dev/null +++ b/plugins/kubernetes-cluster/src/components/ClusterOverview/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { ClusterOverview } from './ClusterOverview'; diff --git a/plugins/kubernetes-cluster/src/components/ClusterOverview/useCluster.ts b/plugins/kubernetes-cluster/src/components/ClusterOverview/useCluster.ts new file mode 100644 index 0000000000..05106cdc5b --- /dev/null +++ b/plugins/kubernetes-cluster/src/components/ClusterOverview/useCluster.ts @@ -0,0 +1,40 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import useAsync from 'react-use/lib/useAsync'; + +import { useApi } from '@backstage/core-plugin-api'; +import { kubernetesApiRef } from '@backstage/plugin-kubernetes-react'; + +/** + * Arguments for useApiResources + * + * @public + */ +export interface UseClusterOptions { + clusterName: string; +} + +/** + * Retrieves the logs for the given pod + * + * @public + */ +export const useCluster = ({ clusterName }: UseClusterOptions) => { + const kubernetesApi = useApi(kubernetesApiRef); + return useAsync(async () => { + return await kubernetesApi.getCluster(clusterName); + }, [clusterName]); +}; diff --git a/plugins/kubernetes-cluster/src/components/KubernetesClusterContent/KubernetesClusterContent.tsx b/plugins/kubernetes-cluster/src/components/KubernetesClusterContent/KubernetesClusterContent.tsx new file mode 100644 index 0000000000..665ca2acdd --- /dev/null +++ b/plugins/kubernetes-cluster/src/components/KubernetesClusterContent/KubernetesClusterContent.tsx @@ -0,0 +1,64 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; +import { ApiResources } from '../ApiResources/ApiResources'; +import { Grid, Typography } from '@material-ui/core'; +import { Nodes } from '../Nodes/Nodes'; +import { ClusterOverview } from '../ClusterOverview'; +import { + KubernetesClusterErrorProvider, + useKubernetesClusterError, +} from '../KubernetesClusterErrorContext/KubernetesClusterErrorContext'; +import { WarningPanel } from '@backstage/core-components'; + +const ContentGrid = () => { + const { error } = useKubernetesClusterError(); + return ( + <> + <Grid container> + {error && ( + <Grid item xs={12}> + <WarningPanel title="Error loading Kubernetes Cluster Plugin"> + <Typography>{error}</Typography> + </WarningPanel> + </Grid> + )} + <Grid item xs={6}> + <ClusterOverview /> + </Grid> + <Grid item xs={6}> + <ApiResources /> + </Grid> + <Grid item xs={12}> + <Nodes /> + </Grid> + </Grid> + </> + ); +}; + +/** + * + * + * @public + */ +export const KubernetesClusterContent = () => { + return ( + <KubernetesClusterErrorProvider> + <ContentGrid /> + </KubernetesClusterErrorProvider> + ); +}; diff --git a/plugins/kubernetes-cluster/src/components/KubernetesClusterContent/index.ts b/plugins/kubernetes-cluster/src/components/KubernetesClusterContent/index.ts new file mode 100644 index 0000000000..2f5850c10c --- /dev/null +++ b/plugins/kubernetes-cluster/src/components/KubernetesClusterContent/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { KubernetesClusterContent } from './KubernetesClusterContent'; diff --git a/plugins/kubernetes-cluster/src/components/KubernetesClusterErrorContext/KubernetesClusterErrorContext.tsx b/plugins/kubernetes-cluster/src/components/KubernetesClusterErrorContext/KubernetesClusterErrorContext.tsx new file mode 100644 index 0000000000..049a7b541d --- /dev/null +++ b/plugins/kubernetes-cluster/src/components/KubernetesClusterErrorContext/KubernetesClusterErrorContext.tsx @@ -0,0 +1,50 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React, { useCallback, useContext, useState } from 'react'; + +export interface ErrorContext { + error?: string; + setError: (message: string) => void; +} + +export const KubernetesClusterErrorContext = React.createContext<ErrorContext>({ + setError: (_: string) => {}, +}); + +export interface KubernetesClusterErrorProviderProps { + children: React.ReactNode; +} + +export const KubernetesClusterErrorProvider = ({ + children, +}: KubernetesClusterErrorProviderProps) => { + const [error, setError] = useState<string | undefined>(undefined); + + const contextValue: ErrorContext = { + error, + setError: useCallback((message: string) => setError(message), []), + }; + + return ( + <KubernetesClusterErrorContext.Provider value={contextValue}> + {children} + </KubernetesClusterErrorContext.Provider> + ); +}; + +export const useKubernetesClusterError = () => { + return useContext(KubernetesClusterErrorContext); +}; diff --git a/plugins/kubernetes-cluster/src/components/Nodes/Nodes.test.tsx b/plugins/kubernetes-cluster/src/components/Nodes/Nodes.test.tsx new file mode 100644 index 0000000000..f48fdfbcef --- /dev/null +++ b/plugins/kubernetes-cluster/src/components/Nodes/Nodes.test.tsx @@ -0,0 +1,107 @@ +/* + * 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 { renderInTestApp } from '@backstage/test-utils'; +import { Nodes } from './Nodes'; +import '@testing-library/jest-dom'; + +jest.mock('@backstage/plugin-catalog-react', () => ({ + useEntity: () => { + return { + entity: { + metadata: { + name: 'some-cluster', + }, + }, + }; + }, +})); + +jest.mock('./useNodes', () => ({ + useNodes: jest.fn().mockReturnValue({ + loading: false, + value: { + items: [ + { + metadata: { + name: 'some-node-name', + }, + status: { + conditions: [ + { + type: 'Ready', + status: 'True', + }, + ], + nodeInfo: { + operatingSystem: 'linux', + architecture: 'ARM', + }, + }, + }, + { + metadata: { + name: 'some-node-bad-name', + }, + spec: { + unschedulable: true, + }, + status: { + conditions: [ + { + type: 'Ready', + status: 'False', + }, + ], + nodeInfo: { + operatingSystem: 'windows', + architecture: 'x86', + }, + }, + }, + ], + }, + }), +})); + +describe('Nodes', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + it('displays nodes table - ready schedulable node', async () => { + const { getByText } = await renderInTestApp(<Nodes />); + + expect(getByText('Nodes')).toBeInTheDocument(); + + // Titles + expect(getByText('Name')).toBeInTheDocument(); + expect(getByText('Schedulable')).toBeInTheDocument(); + expect(getByText('Status')).toBeInTheDocument(); + expect(getByText('OS')).toBeInTheDocument(); + + // Row 1 + expect(getByText('some-node-name')).toBeInTheDocument(); + expect(getByText('✅')).toBeInTheDocument(); + expect(getByText('Ready')).toBeInTheDocument(); + expect(getByText('linux (ARM)')).toBeInTheDocument(); + + // Row 2 + expect(getByText('some-node-bad-name')).toBeInTheDocument(); + expect(getByText('❌')).toBeInTheDocument(); + expect(getByText('Not Ready')).toBeInTheDocument(); + expect(getByText('windows (x86)')).toBeInTheDocument(); + }); +}); diff --git a/plugins/kubernetes-cluster/src/components/Nodes/Nodes.tsx b/plugins/kubernetes-cluster/src/components/Nodes/Nodes.tsx new file mode 100644 index 0000000000..e7f6e957ae --- /dev/null +++ b/plugins/kubernetes-cluster/src/components/Nodes/Nodes.tsx @@ -0,0 +1,144 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { useNodes } from './useNodes'; +import React, { useCallback, useEffect } from 'react'; +import { useEntity } from '@backstage/plugin-catalog-react'; +import { + StructuredMetadataTable, + Table, + TableColumn, +} from '@backstage/core-components'; +import { INode } from 'kubernetes-models/v1'; +import { Grid, Typography, makeStyles } from '@material-ui/core'; +import { useKubernetesClusterError } from '../KubernetesClusterErrorContext/KubernetesClusterErrorContext'; +import { KubernetesDrawer } from '@backstage/plugin-kubernetes-react'; + +const useStyles = makeStyles(theme => ({ + empty: { + padding: theme.spacing(2), + display: 'flex', + justifyContent: 'center', + }, +})); + +const defaultColumns: TableColumn<INode>[] = [ + { + title: 'Name', + highlight: true, + width: 'auto', + render: (node: INode) => { + return ( + <KubernetesDrawer + kubernetesObject={node} + label={node.metadata?.name ?? 'unknown-node'} + > + <Grid container> + <Grid item xs={12}> + <Typography variant="h5">Node Info</Typography> + <StructuredMetadataTable metadata={node.status?.nodeInfo ?? {}} /> + </Grid> + <Grid item xs={12}> + <Typography variant="h5">Addresses</Typography> + <StructuredMetadataTable + metadata={ + node.status?.addresses?.reduce((accum, next) => { + accum[next.type] = next.address; + return accum; + }, {} as any) ?? {} + } + /> + </Grid> + <Grid item xs={12}> + <Typography variant="h5">Taints</Typography> + <StructuredMetadataTable + metadata={ + node.spec?.taints?.reduce((accum, next) => { + accum[`${next.effect}`] = `${next.key} (${next.value})`; + return accum; + }, {} as any) ?? {} + } + /> + </Grid> + </Grid> + </KubernetesDrawer> + ); + }, + }, + { + title: 'Schedulable', + align: 'center', + width: 'auto', + render: (node: INode) => { + if (node.spec?.unschedulable) { + return '❌'; + } + return '✅'; + }, + }, + { + title: 'Status', + width: 'auto', + render: (node: INode) => { + // TODO add an icon + const readyCondition = node.status?.conditions?.find(c => { + return c.type === 'Ready'; + }); + if (!readyCondition) { + return 'Unknown'; + } + return readyCondition.status === 'True' ? 'Ready' : 'Not Ready'; + }, + }, + { + title: 'OS', + width: 'auto', + render: (node: INode) => { + return `${node.status?.nodeInfo?.operatingSystem ?? 'unknown'} (${ + node.status?.nodeInfo?.architecture ?? '?' + })`; + }, + }, +]; + +export const Nodes = () => { + const classes = useStyles(); + const { entity } = useEntity(); + const { value, error, loading } = useNodes({ + clusterName: entity.metadata.name, + }); + const { setError } = useKubernetesClusterError(); + const setErrorCallback = useCallback(setError, [setError]); + useEffect(() => { + if (error) { + setErrorCallback(error.message); + } + }, [error, setErrorCallback]); + + return ( + <Table + title="Nodes" + options={{ paging: true, search: false, emptyRowsWhenPaging: false }} + isLoading={!value && loading} + data={value?.items ?? []} + emptyContent={ + <div className={classes.empty}> + {error !== undefined ? 'Error loading nodes' : 'No nodes found'} + </div> + } + columns={defaultColumns} + /> + ); +}; diff --git a/plugins/kubernetes-cluster/src/components/Nodes/useNodes.ts b/plugins/kubernetes-cluster/src/components/Nodes/useNodes.ts new file mode 100644 index 0000000000..1feaff3bdb --- /dev/null +++ b/plugins/kubernetes-cluster/src/components/Nodes/useNodes.ts @@ -0,0 +1,48 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import useAsync from 'react-use/lib/useAsync'; + +import { useApi } from '@backstage/core-plugin-api'; +import { kubernetesApiRef } from '@backstage/plugin-kubernetes-react'; +import { NodeList } from 'kubernetes-models/v1'; + +/** + * Arguments for useApiResources + * + * @public + */ +export interface useNodesOptions { + clusterName: string; +} + +/** + * Retrieves nodes for a cluster + * + * @public + */ +export const useNodes = ({ clusterName }: useNodesOptions) => { + const kubernetesApi = useApi(kubernetesApiRef); + return useAsync(async () => { + return await kubernetesApi + .proxy({ + clusterName, + path: '/api/v1/nodes?limit=500', + }) + .then(r => { + return r.json() as Promise<NodeList>; + }); + }, [clusterName]); +}; diff --git a/plugins/kubernetes-cluster/src/index.ts b/plugins/kubernetes-cluster/src/index.ts new file mode 100644 index 0000000000..6171b151e4 --- /dev/null +++ b/plugins/kubernetes-cluster/src/index.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * A Backstage plugin that integrates towards Kubernetes + * + * @packageDocumentation + */ + +export { + EntityKubernetesClusterContent, + type EntityKubernetesClusterContentProps, +} from './plugin'; +export { Router, isKubernetesClusterAvailable } from './Router'; diff --git a/plugins/kubernetes-cluster/src/plugin.ts b/plugins/kubernetes-cluster/src/plugin.ts new file mode 100644 index 0000000000..5cd9b2287c --- /dev/null +++ b/plugins/kubernetes-cluster/src/plugin.ts @@ -0,0 +1,54 @@ +/* + * 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 { + createPlugin, + createRouteRef, + createRoutableExtension, +} from '@backstage/core-plugin-api'; + +export const rootCatalogKubernetesClusterRouteRef = createRouteRef({ + id: 'kubernetes-cluster', +}); + +export const kubernetesClusterPlugin = createPlugin({ + id: 'kubernetes-cluster', + apis: [], + routes: { + entityContent: rootCatalogKubernetesClusterRouteRef, + }, +}); + +/** + * Props of EntityKubernetesContent + * + * @public + */ +export type EntityKubernetesClusterContentProps = {}; + +/** + * Props of EntityKubernetesContent + * + * @public + */ +export const EntityKubernetesClusterContent: ( + props: EntityKubernetesClusterContentProps, +) => JSX.Element = kubernetesClusterPlugin.provide( + createRoutableExtension({ + name: 'EntityKubernetesClusterContent', + component: () => import('./Router').then(m => m.Router), + mountPoint: rootCatalogKubernetesClusterRouteRef, + }), +); diff --git a/plugins/kubernetes-common/CHANGELOG.md b/plugins/kubernetes-common/CHANGELOG.md index 83451a1999..4bd84d3ca7 100644 --- a/plugins/kubernetes-common/CHANGELOG.md +++ b/plugins/kubernetes-common/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-kubernetes-common +## 0.7.0-next.0 + +### Minor Changes + +- 2d8151061c: Refactor Kubernetes plugins in line with ADR 11, no breaking changes yet + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.8 + ## 0.6.6 ### Patch Changes diff --git a/plugins/kubernetes-common/api-report.md b/plugins/kubernetes-common/api-report.md index 051293f37f..8daeb9a875 100644 --- a/plugins/kubernetes-common/api-report.md +++ b/plugins/kubernetes-common/api-report.md @@ -5,7 +5,10 @@ ```ts import { BasicPermission } from '@backstage/plugin-permission-common'; import { Entity } from '@backstage/catalog-model'; +import { FetchResponse as FetchResponse_2 } from '@backstage/plugin-kubernetes-common'; import type { JsonObject } from '@backstage/types'; +import type { JsonValue } from '@backstage/types'; +import { ObjectsByEntityResponse as ObjectsByEntityResponse_2 } from '@backstage/plugin-kubernetes-common'; import { PodStatus } from '@kubernetes/client-node'; import { V1ConfigMap } from '@kubernetes/client-node'; import { V1CronJob } from '@kubernetes/client-node'; @@ -174,6 +177,67 @@ export interface DeploymentFetchResponse { type: 'deployments'; } +// @public (undocumented) +export interface DeploymentResources { + // (undocumented) + deployments: V1Deployment[]; + // (undocumented) + horizontalPodAutoscalers: V1HorizontalPodAutoscaler[]; + // (undocumented) + pods: V1Pod[]; + // (undocumented) + replicaSets: V1ReplicaSet[]; +} + +// @public +export interface DetectedError { + // (undocumented) + message: string; + // (undocumented) + occurrenceCount: number; + // (undocumented) + proposedFix?: ProposedFix; + // (undocumented) + severity: ErrorSeverity; + // (undocumented) + sourceRef: ResourceRef; + // (undocumented) + type: string; +} + +// @public +export type DetectedErrorsByCluster = Map<string, DetectedError[]>; + +// @public +export const detectErrors: ( + objects: ObjectsByEntityResponse_2, +) => DetectedErrorsByCluster; + +// @public (undocumented) +export interface DocsSolution extends ProposedFixBase { + // (undocumented) + docsLink: string; + // (undocumented) + type: 'docs'; +} + +// @public (undocumented) +export interface ErrorMapper<T> { + // (undocumented) + detectErrors: (resource: T) => DetectedError[]; +} + +// @public +export type ErrorSeverity = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10; + +// @public (undocumented) +export interface EventsSolution extends ProposedFixBase { + // (undocumented) + podName: string; + // (undocumented) + type: 'events'; +} + // @public (undocumented) export type FetchResponse = | PodFetchResponse @@ -191,6 +255,29 @@ export type FetchResponse = | DaemonSetsFetchResponse | PodStatusFetchResponse; +// @public (undocumented) +export interface GroupedResponses extends DeploymentResources { + // (undocumented) + configMaps: V1ConfigMap[]; + // (undocumented) + cronJobs: V1CronJob[]; + // (undocumented) + customResources: any[]; + // (undocumented) + ingresses: V1Ingress[]; + // (undocumented) + jobs: V1Job[]; + // (undocumented) + services: V1Service[]; + // (undocumented) + statefulsets: V1StatefulSet[]; +} + +// @public (undocumented) +export const groupResponses: ( + fetchResponse: FetchResponse_2[], +) => GroupedResponses; + // @public (undocumented) export interface HorizontalPodAutoscalersFetchResponse { // (undocumented) @@ -233,7 +320,9 @@ export const kubernetesPermissions: BasicPermission[]; export const kubernetesProxyPermission: BasicPermission; // @public (undocumented) -export type KubernetesRequestAuth = JsonObject; +export type KubernetesRequestAuth = { + [providerKey: string]: JsonValue | undefined; +}; // @public (undocumented) export interface KubernetesRequestBody { @@ -251,6 +340,14 @@ export interface LimitRangeFetchResponse { type: 'limitranges'; } +// @public (undocumented) +export interface LogSolution extends ProposedFixBase { + // (undocumented) + container: string; + // (undocumented) + type: 'logs'; +} + // @public (undocumented) export interface ObjectsByEntityResponse { // (undocumented) @@ -273,6 +370,19 @@ export interface PodStatusFetchResponse { type: 'podstatus'; } +// @public (undocumented) +export type ProposedFix = LogSolution | DocsSolution | EventsSolution; + +// @public (undocumented) +export interface ProposedFixBase { + // (undocumented) + actions: string[]; + // (undocumented) + errorType: string; + // (undocumented) + rootCauseExplanation: string; +} + // @public (undocumented) export interface RawFetchError { // (undocumented) @@ -289,6 +399,18 @@ export interface ReplicaSetsFetchResponse { type: 'replicasets'; } +// @public +export interface ResourceRef { + // (undocumented) + apiGroup: string; + // (undocumented) + kind: string; + // (undocumented) + name: string; + // (undocumented) + namespace: string; +} + // @public (undocumented) export interface ServiceFetchResponse { // (undocumented) diff --git a/plugins/kubernetes-common/package.json b/plugins/kubernetes-common/package.json index b563cbff4e..baf24cea5d 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.6.6", + "version": "0.7.0-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -40,11 +40,20 @@ }, "dependencies": { "@backstage/catalog-model": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@backstage/errors": "workspace:^", "@backstage/plugin-permission-common": "workspace:^", - "@kubernetes/client-node": "0.18.1" + "@backstage/types": "workspace:^", + "@kubernetes/client-node": "0.18.1", + "kubernetes-models": "^4.3.1", + "lodash": "^4.17.21", + "luxon": "^3.0.0" }, "devDependencies": { - "@backstage/cli": "workspace:^" + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/test-utils": "workspace:^", + "msw": "^1.3.1" }, "jest": { "roots": [ diff --git a/plugins/kubernetes/src/error-detection/__fixtures__/deploy-bad.json b/plugins/kubernetes-common/src/error-detection/__fixtures__/deploy-bad.json similarity index 100% rename from plugins/kubernetes/src/error-detection/__fixtures__/deploy-bad.json rename to plugins/kubernetes-common/src/error-detection/__fixtures__/deploy-bad.json diff --git a/plugins/kubernetes/src/error-detection/__fixtures__/deploy-healthy.json b/plugins/kubernetes-common/src/error-detection/__fixtures__/deploy-healthy.json similarity index 100% rename from plugins/kubernetes/src/error-detection/__fixtures__/deploy-healthy.json rename to plugins/kubernetes-common/src/error-detection/__fixtures__/deploy-healthy.json diff --git a/plugins/kubernetes/src/error-detection/__fixtures__/hpa-healthy.json b/plugins/kubernetes-common/src/error-detection/__fixtures__/hpa-healthy.json similarity index 100% rename from plugins/kubernetes/src/error-detection/__fixtures__/hpa-healthy.json rename to plugins/kubernetes-common/src/error-detection/__fixtures__/hpa-healthy.json diff --git a/plugins/kubernetes/src/error-detection/__fixtures__/hpa-maxed-out.json b/plugins/kubernetes-common/src/error-detection/__fixtures__/hpa-maxed-out.json similarity index 100% rename from plugins/kubernetes/src/error-detection/__fixtures__/hpa-maxed-out.json rename to plugins/kubernetes-common/src/error-detection/__fixtures__/hpa-maxed-out.json diff --git a/plugins/kubernetes/src/error-detection/__fixtures__/pod-crashing.json b/plugins/kubernetes-common/src/error-detection/__fixtures__/pod-crashing.json similarity index 100% rename from plugins/kubernetes/src/error-detection/__fixtures__/pod-crashing.json rename to plugins/kubernetes-common/src/error-detection/__fixtures__/pod-crashing.json diff --git a/plugins/kubernetes/src/error-detection/__fixtures__/pod-missing-cm.json b/plugins/kubernetes-common/src/error-detection/__fixtures__/pod-missing-cm.json similarity index 100% rename from plugins/kubernetes/src/error-detection/__fixtures__/pod-missing-cm.json rename to plugins/kubernetes-common/src/error-detection/__fixtures__/pod-missing-cm.json diff --git a/plugins/kubernetes/src/components/Pods/__fixtures__/pod.json b/plugins/kubernetes-common/src/error-detection/__fixtures__/pod.json similarity index 100% rename from plugins/kubernetes/src/components/Pods/__fixtures__/pod.json rename to plugins/kubernetes-common/src/error-detection/__fixtures__/pod.json diff --git a/plugins/kubernetes/src/error-detection/common.ts b/plugins/kubernetes-common/src/error-detection/common.ts similarity index 100% rename from plugins/kubernetes/src/error-detection/common.ts rename to plugins/kubernetes-common/src/error-detection/common.ts diff --git a/plugins/kubernetes/src/error-detection/deployments.ts b/plugins/kubernetes-common/src/error-detection/deployments.ts similarity index 100% rename from plugins/kubernetes/src/error-detection/deployments.ts rename to plugins/kubernetes-common/src/error-detection/deployments.ts diff --git a/plugins/kubernetes/src/error-detection/error-detection.test.ts b/plugins/kubernetes-common/src/error-detection/error-detection.test.ts similarity index 100% rename from plugins/kubernetes/src/error-detection/error-detection.test.ts rename to plugins/kubernetes-common/src/error-detection/error-detection.test.ts diff --git a/plugins/kubernetes/src/error-detection/error-detection.ts b/plugins/kubernetes-common/src/error-detection/error-detection.ts similarity index 97% rename from plugins/kubernetes/src/error-detection/error-detection.ts rename to plugins/kubernetes-common/src/error-detection/error-detection.ts index c33de18b80..a3a4d58d9e 100644 --- a/plugins/kubernetes/src/error-detection/error-detection.ts +++ b/plugins/kubernetes-common/src/error-detection/error-detection.ts @@ -16,7 +16,7 @@ import { DetectedError, DetectedErrorsByCluster } from './types'; import { ObjectsByEntityResponse } from '@backstage/plugin-kubernetes-common'; -import { groupResponses } from '../utils/response'; +import { groupResponses } from '../util'; import { detectErrorsInPods } from './pods'; import { detectErrorsInDeployments } from './deployments'; import { detectErrorsInHpa } from './hpas'; diff --git a/plugins/kubernetes/src/error-detection/hpas.ts b/plugins/kubernetes-common/src/error-detection/hpas.ts similarity index 100% rename from plugins/kubernetes/src/error-detection/hpas.ts rename to plugins/kubernetes-common/src/error-detection/hpas.ts diff --git a/plugins/catalog-customized/src/index.ts b/plugins/kubernetes-common/src/error-detection/index.ts similarity index 88% rename from plugins/catalog-customized/src/index.ts rename to plugins/kubernetes-common/src/error-detection/index.ts index cc8aefeaa6..0b79b023c2 100644 --- a/plugins/catalog-customized/src/index.ts +++ b/plugins/kubernetes-common/src/error-detection/index.ts @@ -13,6 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import './plugin'; -export * from '@backstage/plugin-catalog'; +export * from './types'; +export { detectErrors } from './error-detection'; diff --git a/plugins/kubernetes/src/error-detection/pods.ts b/plugins/kubernetes-common/src/error-detection/pods.ts similarity index 100% rename from plugins/kubernetes/src/error-detection/pods.ts rename to plugins/kubernetes-common/src/error-detection/pods.ts diff --git a/plugins/kubernetes/src/error-detection/types.ts b/plugins/kubernetes-common/src/error-detection/types.ts similarity index 93% rename from plugins/kubernetes/src/error-detection/types.ts rename to plugins/kubernetes-common/src/error-detection/types.ts index 4148056171..bf918bbacb 100644 --- a/plugins/kubernetes/src/error-detection/types.ts +++ b/plugins/kubernetes-common/src/error-detection/types.ts @@ -54,29 +54,35 @@ export interface DetectedError { occurrenceCount: number; } +/** @public */ export type ProposedFix = LogSolution | DocsSolution | EventsSolution; -interface ProposedFixBase { +/** @public */ +export interface ProposedFixBase { errorType: string; rootCauseExplanation: string; actions: string[]; } +/** @public */ export interface LogSolution extends ProposedFixBase { type: 'logs'; container: string; } +/** @public */ export interface DocsSolution extends ProposedFixBase { type: 'docs'; docsLink: string; } +/** @public */ export interface EventsSolution extends ProposedFixBase { type: 'events'; podName: string; } +/** @public */ export interface ErrorMapper<T> { detectErrors: (resource: T) => DetectedError[]; } diff --git a/plugins/kubernetes-common/src/index.ts b/plugins/kubernetes-common/src/index.ts index d5cf8dcf61..6704242383 100644 --- a/plugins/kubernetes-common/src/index.ts +++ b/plugins/kubernetes-common/src/index.ts @@ -26,3 +26,5 @@ export { kubernetesProxyPermission, kubernetesPermissions, } from './permissions'; +export * from './error-detection'; +export * from './util'; diff --git a/plugins/kubernetes-common/src/types.ts b/plugins/kubernetes-common/src/types.ts index feb213d520..9f8d5eed82 100644 --- a/plugins/kubernetes-common/src/types.ts +++ b/plugins/kubernetes-common/src/types.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import type { JsonObject } from '@backstage/types'; +import type { JsonObject, JsonValue } from '@backstage/types'; import { PodStatus, V1ConfigMap, @@ -33,7 +33,9 @@ import { import { Entity } from '@backstage/catalog-model'; /** @public */ -export type KubernetesRequestAuth = JsonObject; +export type KubernetesRequestAuth = { + [providerKey: string]: JsonValue | undefined; +}; /** @public */ export interface CustomResourceMatcher { @@ -262,3 +264,22 @@ export interface ClientPodStatus { memory: ClientCurrentResourceUsage; containers: ClientContainerStatus[]; } + +/** @public */ +export interface DeploymentResources { + pods: V1Pod[]; + replicaSets: V1ReplicaSet[]; + deployments: V1Deployment[]; + horizontalPodAutoscalers: V1HorizontalPodAutoscaler[]; +} + +/** @public */ +export interface GroupedResponses extends DeploymentResources { + services: V1Service[]; + configMaps: V1ConfigMap[]; + ingresses: V1Ingress[]; + jobs: V1Job[]; + cronJobs: V1CronJob[]; + customResources: any[]; + statefulsets: V1StatefulSet[]; +} diff --git a/plugins/kubernetes/src/components/Cluster/index.ts b/plugins/kubernetes-common/src/util/index.ts similarity index 94% rename from plugins/kubernetes/src/components/Cluster/index.ts rename to plugins/kubernetes-common/src/util/index.ts index dc9df63d42..1cc287df08 100644 --- a/plugins/kubernetes/src/components/Cluster/index.ts +++ b/plugins/kubernetes-common/src/util/index.ts @@ -13,4 +13,5 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export { Cluster } from './Cluster'; + +export * from './response'; diff --git a/plugins/kubernetes/src/utils/response.ts b/plugins/kubernetes-common/src/util/response.ts similarity index 95% rename from plugins/kubernetes/src/utils/response.ts rename to plugins/kubernetes-common/src/util/response.ts index 894b881f22..a86d90f780 100644 --- a/plugins/kubernetes/src/utils/response.ts +++ b/plugins/kubernetes-common/src/util/response.ts @@ -15,12 +15,13 @@ */ import { FetchResponse } from '@backstage/plugin-kubernetes-common'; -import { GroupedResponses } from '../types/types'; +import { GroupedResponses } from '../types'; -// TODO this could probably be a lodash groupBy +/** @public */ export const groupResponses = ( fetchResponse: FetchResponse[], ): GroupedResponses => { + // TODO this could probably be a lodash groupBy return fetchResponse.reduce( (prev, next) => { switch (next.type) { diff --git a/plugins/kubernetes-react/.eslintrc.js b/plugins/kubernetes-react/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/kubernetes-react/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/kubernetes-react/CHANGELOG.md b/plugins/kubernetes-react/CHANGELOG.md new file mode 100644 index 0000000000..f7ed7bb39d --- /dev/null +++ b/plugins/kubernetes-react/CHANGELOG.md @@ -0,0 +1,17 @@ +# @backstage/plugin-kubernetes-react + +## 0.1.0-next.0 + +### Minor Changes + +- 2d8151061c: Refactor Kubernetes plugins in line with ADR 11, no breaking changes yet + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-kubernetes-common@0.7.0-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 diff --git a/plugins/kubernetes-react/README.md b/plugins/kubernetes-react/README.md new file mode 100644 index 0000000000..02963c2e0a --- /dev/null +++ b/plugins/kubernetes-react/README.md @@ -0,0 +1,5 @@ +# @backstage/plugin-kubernetes-react + +Welcome to the web library package for the kubernetes-react plugin! + +_This plugin was created through the Backstage CLI_ diff --git a/plugins/kubernetes-react/api-report.md b/plugins/kubernetes-react/api-report.md new file mode 100644 index 0000000000..bb8e4923f6 --- /dev/null +++ b/plugins/kubernetes-react/api-report.md @@ -0,0 +1,767 @@ +## API Report File for "@backstage/plugin-kubernetes-react" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { ApiRef } from '@backstage/core-plugin-api'; +import { AsyncState } from 'react-use/lib/useAsyncFn'; +import { ClientContainerStatus } from '@backstage/plugin-kubernetes-common'; +import { ClientPodStatus } from '@backstage/plugin-kubernetes-common'; +import { ClusterAttributes } from '@backstage/plugin-kubernetes-common'; +import { ClusterObjects } from '@backstage/plugin-kubernetes-common'; +import { CustomObjectsByEntityRequest } from '@backstage/plugin-kubernetes-common'; +import { CustomResourceMatcher } from '@backstage/plugin-kubernetes-common'; +import { DetectedError } from '@backstage/plugin-kubernetes-common'; +import { DetectedErrorsByCluster } from '@backstage/plugin-kubernetes-common'; +import { DiscoveryApi } from '@backstage/core-plugin-api'; +import { Entity } from '@backstage/catalog-model'; +import { Event as Event_2 } from 'kubernetes-models/v1'; +import { GroupedResponses } from '@backstage/plugin-kubernetes-common'; +import { IContainer } from 'kubernetes-models/v1'; +import { IContainerStatus } from 'kubernetes-models/v1'; +import { IdentityApi } from '@backstage/core-plugin-api'; +import { IIoK8sApimachineryPkgApisMetaV1ObjectMeta } from '@kubernetes-models/apimachinery/apis/meta/v1/ObjectMeta'; +import { IObjectMeta } from '@kubernetes-models/apimachinery/apis/meta/v1/ObjectMeta'; +import { KubernetesRequestBody } from '@backstage/plugin-kubernetes-common'; +import { OAuthApi } from '@backstage/core-plugin-api'; +import { ObjectsByEntityResponse } from '@backstage/plugin-kubernetes-common'; +import { OpenIdConnectApi } from '@backstage/core-plugin-api'; +import { Pod } from 'kubernetes-models/v1'; +import { Pod as Pod_2 } from 'kubernetes-models/v1/Pod'; +import { default as React_2 } from 'react'; +import * as React_3 from 'react'; +import { TypeMeta } from '@kubernetes-models/base'; +import { V1HorizontalPodAutoscaler } from '@kubernetes/client-node'; +import { V1Job } from '@kubernetes/client-node'; +import { V1ObjectMeta } from '@kubernetes/client-node'; +import { V1Pod } from '@kubernetes/client-node'; +import { WorkloadsByEntityRequest } from '@backstage/plugin-kubernetes-common'; + +// @public (undocumented) +export class AksKubernetesAuthProvider implements KubernetesAuthProvider { + constructor(microsoftAuthApi: OAuthApi); + // (undocumented) + decorateRequestBodyForAuth( + requestBody: KubernetesRequestBody, + ): Promise<KubernetesRequestBody>; + // (undocumented) + getCredentials(): Promise<{ + token?: string; + }>; +} + +// @public +export const Cluster: ({ + clusterObjects, + podsWithErrors, +}: ClusterProps) => React_2.JSX.Element; + +// @public (undocumented) +export const ClusterContext: React_2.Context<ClusterAttributes>; + +// @public +export type ClusterProps = { + clusterObjects: ClusterObjects; + podsWithErrors: Set<string>; + children?: React_2.ReactNode; +}; + +// @public +export const ContainerCard: React_2.FC<ContainerCardProps>; + +// @public +export interface ContainerCardProps { + // (undocumented) + containerMetrics?: ClientContainerStatus; + // (undocumented) + containerSpec?: IContainer; + // (undocumented) + containerStatus: IContainerStatus; + // (undocumented) + podScope: PodScope; +} + +// @public +export interface ContainerScope extends PodScope { + // (undocumented) + containerName: string; +} + +// @public (undocumented) +export const CronJobsAccordions: ({}: CronJobsAccordionsProps) => React_2.JSX.Element; + +// @public (undocumented) +export type CronJobsAccordionsProps = { + children?: React_2.ReactNode; +}; + +// @public (undocumented) +export const CustomResources: ({}: CustomResourcesProps) => React_2.JSX.Element; + +// @public (undocumented) +export interface CustomResourcesProps { + // (undocumented) + children?: React_2.ReactNode; +} + +// @public +export const DetectedErrorsContext: React_2.Context<DetectedError[]>; + +// @public +export const ErrorList: ({ + podAndErrors, +}: ErrorListProps) => React_2.JSX.Element; + +// @public +export interface ErrorListProps { + // (undocumented) + podAndErrors: PodAndErrors[]; +} + +// @public (undocumented) +export type ErrorMatcher = { + metadata?: IIoK8sApimachineryPkgApisMetaV1ObjectMeta; +} & TypeMeta; + +// @public (undocumented) +export const ErrorPanel: ({ + entityName, + errorMessage, + clustersWithErrors, +}: ErrorPanelProps) => React_2.JSX.Element; + +// @public (undocumented) +export type ErrorPanelProps = { + entityName: string; + errorMessage?: string; + clustersWithErrors?: ClusterObjects[]; + children?: React_2.ReactNode; +}; + +// @public (undocumented) +export const ErrorReporting: ({ + detectedErrors, +}: ErrorReportingProps) => React_3.JSX.Element; + +// @public (undocumented) +export type ErrorReportingProps = { + detectedErrors: DetectedErrorsByCluster; +}; + +// @public +export const Events: ({ + involvedObjectName, + namespace, + clusterName, + warningEventsOnly, +}: EventsProps) => React_2.JSX.Element; + +// @public +export const EventsContent: ({ + events, + warningEventsOnly, +}: EventsContentProps) => React_2.JSX.Element; + +// @public +export interface EventsContentProps { + // (undocumented) + events: Event_2[]; + // (undocumented) + warningEventsOnly?: boolean; +} + +// @public +export interface EventsOptions { + // (undocumented) + clusterName: string; + // (undocumented) + involvedObjectName: string; + // (undocumented) + namespace: string; +} + +// @public +export interface EventsProps { + // (undocumented) + clusterName: string; + // (undocumented) + involvedObjectName: string; + // (undocumented) + namespace: string; + // (undocumented) + warningEventsOnly?: boolean; +} + +// @public +export const FixDialog: React_2.FC<FixDialogProps>; + +// @public +export interface FixDialogProps { + // (undocumented) + clusterName: string; + // (undocumented) + error: DetectedError; + // (undocumented) + open?: boolean; + // (undocumented) + pod: Pod_2; +} + +// @public (undocumented) +export class GoogleKubernetesAuthProvider implements KubernetesAuthProvider { + constructor(authProvider: OAuthApi); + // (undocumented) + authProvider: OAuthApi; + // (undocumented) + decorateRequestBodyForAuth( + requestBody: KubernetesRequestBody, + ): Promise<KubernetesRequestBody>; + // (undocumented) + getCredentials(): Promise<{ + token: string; + }>; +} + +// @public (undocumented) +export const GroupedResponsesContext: React_2.Context<GroupedResponses>; + +// @public (undocumented) +export const HorizontalPodAutoscalerDrawer: (props: { + hpa: V1HorizontalPodAutoscaler; + expanded?: boolean; + children?: React_2.ReactNode; +}) => React_2.JSX.Element; + +// @public (undocumented) +export const IngressesAccordions: ({}: IngressesAccordionsProps) => React_2.JSX.Element; + +// @public (undocumented) +export type IngressesAccordionsProps = {}; + +// @public (undocumented) +export const JobsAccordions: ({ + jobs, +}: JobsAccordionsProps) => React_2.JSX.Element; + +// @public (undocumented) +export type JobsAccordionsProps = { + jobs: V1Job[]; + children?: React_2.ReactNode; +}; + +// @public (undocumented) +export interface KubernetesApi { + // (undocumented) + getCluster(clusterName: string): Promise< + | { + name: string; + authProvider: string; + oidcTokenProvider?: string; + dashboardUrl?: string; + } + | undefined + >; + // (undocumented) + getClusters(): Promise< + { + name: string; + authProvider: string; + oidcTokenProvider?: string; + }[] + >; + // (undocumented) + getCustomObjectsByEntity( + request: CustomObjectsByEntityRequest, + ): Promise<ObjectsByEntityResponse>; + // (undocumented) + getObjectsByEntity( + requestBody: KubernetesRequestBody, + ): Promise<ObjectsByEntityResponse>; + // (undocumented) + getWorkloadsByEntity( + request: WorkloadsByEntityRequest, + ): Promise<ObjectsByEntityResponse>; + // (undocumented) + proxy(options: { + clusterName: string; + path: string; + init?: RequestInit; + }): Promise<Response>; +} + +// @public (undocumented) +export const kubernetesApiRef: ApiRef<KubernetesApi>; + +// @public (undocumented) +export interface KubernetesAuthProvider { + // (undocumented) + decorateRequestBodyForAuth( + requestBody: KubernetesRequestBody, + ): Promise<KubernetesRequestBody>; + // (undocumented) + getCredentials(): Promise<{ + token?: string; + }>; +} + +// @public (undocumented) +export class KubernetesAuthProviders implements KubernetesAuthProvidersApi { + constructor(options: { + microsoftAuthApi: OAuthApi; + googleAuthApi: OAuthApi; + oidcProviders?: { + [key: string]: OpenIdConnectApi; + }; + }); + // (undocumented) + decorateRequestBodyForAuth( + authProvider: string, + requestBody: KubernetesRequestBody, + ): Promise<KubernetesRequestBody>; + // (undocumented) + getCredentials(authProvider: string): Promise<{ + token?: string; + }>; +} + +// @public (undocumented) +export interface KubernetesAuthProvidersApi { + // (undocumented) + decorateRequestBodyForAuth( + authProvider: string, + requestBody: KubernetesRequestBody, + ): Promise<KubernetesRequestBody>; + // (undocumented) + getCredentials(authProvider: string): Promise<{ + token?: string; + }>; +} + +// @public (undocumented) +export const kubernetesAuthProvidersApiRef: ApiRef<KubernetesAuthProvidersApi>; + +// @public (undocumented) +export class KubernetesBackendClient implements KubernetesApi { + constructor(options: { + discoveryApi: DiscoveryApi; + identityApi: IdentityApi; + kubernetesAuthProvidersApi: KubernetesAuthProvidersApi; + }); + // (undocumented) + getCluster(clusterName: string): Promise<{ + name: string; + authProvider: string; + oidcTokenProvider?: string; + }>; + // (undocumented) + getClusters(): Promise< + { + name: string; + authProvider: string; + }[] + >; + // (undocumented) + getCustomObjectsByEntity( + request: CustomObjectsByEntityRequest, + ): Promise<ObjectsByEntityResponse>; + // (undocumented) + getObjectsByEntity( + requestBody: KubernetesRequestBody, + ): Promise<ObjectsByEntityResponse>; + // (undocumented) + getWorkloadsByEntity( + request: WorkloadsByEntityRequest, + ): Promise<ObjectsByEntityResponse>; + // (undocumented) + proxy(options: { + clusterName: string; + path: string; + init?: RequestInit; + }): Promise<Response>; +} + +// @public +export const KubernetesDrawer: ({ + open, + label, + drawerContentsHeader, + kubernetesObject, + children, +}: KubernetesDrawerProps) => React_2.JSX.Element; + +// @public (undocumented) +export interface KubernetesDrawerable { + // (undocumented) + metadata?: V1ObjectMeta; +} + +// @public +export interface KubernetesDrawerProps { + // (undocumented) + children?: React_2.ReactNode; + // (undocumented) + drawerContentsHeader?: React_2.ReactNode; + // (undocumented) + kubernetesObject: KubernetesObject; + // (undocumented) + label: React_2.ReactNode; + // (undocumented) + open?: boolean; +} + +// @public +export interface KubernetesObject { + // (undocumented) + kind: string; + // (undocumented) + metadata?: IObjectMeta; +} + +// @public (undocumented) +export interface KubernetesObjects { + // (undocumented) + error?: string; + // (undocumented) + kubernetesObjects?: ObjectsByEntityResponse; + // (undocumented) + loading: boolean; +} + +// @public (undocumented) +export interface KubernetesProxyApi { + // (undocumented) + getEventsByInvolvedObjectName(request: { + clusterName: string; + involvedObjectName: string; + namespace: string; + }): Promise<Event_2[]>; + // (undocumented) + getPodLogs(request: { + podName: string; + namespace: string; + clusterName: string; + containerName: string; + previous?: boolean; + }): Promise<{ + text: string; + }>; +} + +// @public (undocumented) +export const kubernetesProxyApiRef: ApiRef<KubernetesProxyApi>; + +// @public +export class KubernetesProxyClient { + constructor(options: { kubernetesApi: KubernetesApi }); + // (undocumented) + getEventsByInvolvedObjectName({ + clusterName, + involvedObjectName, + namespace, + }: { + clusterName: string; + involvedObjectName: string; + namespace: string; + }): Promise<Event_2[]>; + // (undocumented) + getPodLogs({ + podName, + namespace, + clusterName, + containerName, + previous, + }: { + podName: string; + namespace: string; + clusterName: string; + containerName: string; + previous?: boolean; + }): Promise<{ + text: string; + }>; +} + +// @public (undocumented) +export const KubernetesStructuredMetadataTableDrawer: < + T extends KubernetesDrawerable, +>({ + object, + renderObject, + kind, + buttonVariant, + expanded, + children, +}: KubernetesStructuredMetadataTableDrawerProps<T>) => React_2.JSX.Element; + +// @public (undocumented) +export interface KubernetesStructuredMetadataTableDrawerProps< + T extends KubernetesDrawerable, +> { + // (undocumented) + buttonVariant?: 'h5' | 'subtitle2'; + // (undocumented) + children?: React_2.ReactNode; + // (undocumented) + expanded?: boolean; + // (undocumented) + kind: string; + // (undocumented) + object: T; + // (undocumented) + renderObject: (obj: T) => object; +} + +// @public (undocumented) +export const LinkErrorPanel: ({ + cluster, + errorMessage, +}: LinkErrorPanelProps) => React_2.JSX.Element; + +// @public (undocumented) +export type LinkErrorPanelProps = { + cluster: ClusterAttributes; + errorMessage?: string; + children?: React_2.ReactNode; +}; + +// @public +export const ManifestYaml: ({ + object, +}: ManifestYamlProps) => React_2.JSX.Element; + +// @public +export interface ManifestYamlProps { + // (undocumented) + object: object; +} + +// @public (undocumented) +export class OidcKubernetesAuthProvider implements KubernetesAuthProvider { + constructor(providerName: string, authProvider: OpenIdConnectApi); + // (undocumented) + authProvider: OpenIdConnectApi; + // (undocumented) + decorateRequestBodyForAuth( + requestBody: KubernetesRequestBody, + ): Promise<KubernetesRequestBody>; + // (undocumented) + getCredentials(): Promise<{ + token: string; + }>; + // (undocumented) + providerName: string; +} + +// @public +export const PendingPodContent: ({ + pod, +}: PendingPodContentProps) => React_2.JSX.Element; + +// @public +export interface PendingPodContentProps { + // (undocumented) + pod: Pod; +} + +// @public +export interface PodAndErrors { + // (undocumented) + clusterName: string; + // (undocumented) + errors: DetectedError[]; + // (undocumented) + pod: Pod; +} + +// @public (undocumented) +export type PodColumns = 'READY' | 'RESOURCE'; + +// @public +export const PodDrawer: ({ + podAndErrors, + open, +}: PodDrawerProps) => React_2.JSX.Element; + +// @public +export interface PodDrawerProps { + // (undocumented) + open?: boolean; + // (undocumented) + podAndErrors: PodAndErrors; +} + +// @public +export const PodExecTerminal: ( + props: PodExecTerminalProps, +) => React_2.JSX.Element; + +// @public +export const PodExecTerminalDialog: ( + props: PodExecTerminalProps, +) => React_2.JSX.Element; + +// @public +export interface PodExecTerminalProps { + // (undocumented) + clusterName: string; + // (undocumented) + containerName: string; + // (undocumented) + podName: string; + // (undocumented) + podNamespace: string; +} + +// @public +export const PodLogs: React_2.FC<PodLogsProps>; + +// @public +export const PodLogsDialog: ({ + containerScope, +}: PodLogsDialogProps) => React_2.JSX.Element; + +// @public +export interface PodLogsDialogProps { + // (undocumented) + containerScope: ContainerScope; +} + +// @public +export interface PodLogsOptions { + // (undocumented) + containerScope: ContainerScope; + // (undocumented) + previous?: boolean; +} + +// @public +export interface PodLogsProps { + // (undocumented) + containerScope: ContainerScope; + // (undocumented) + previous?: boolean; +} + +// @public +export const PodMetricsContext: React_2.Context<Map<string, ClientPodStatus[]>>; + +// @public (undocumented) +export type PodMetricsMatcher = { + metadata?: IObjectMeta; +}; + +// @public (undocumented) +export const PodNamesWithErrorsContext: React_2.Context<Set<string>>; + +// @public (undocumented) +export const PodNamesWithMetricsContext: React_2.Context< + Map<string, ClientPodStatus> +>; + +// @public +export interface PodScope { + // (undocumented) + clusterName: string; + // (undocumented) + podName: string; + // (undocumented) + podNamespace: string; +} + +// @public (undocumented) +export const PodsTable: ({ + pods, + extraColumns, +}: PodsTablesProps) => React_2.JSX.Element; + +// @public (undocumented) +export type PodsTablesProps = { + pods: Pod_2 | V1Pod[]; + extraColumns?: PodColumns[]; + children?: React_2.ReactNode; +}; + +// @public (undocumented) +export const READY_COLUMNS: PodColumns; + +// @public (undocumented) +export const RESOURCE_COLUMNS: PodColumns; + +// @public +export const ResourceUtilization: ({ + compressed, + title, + usage, + total, + totalFormatted, +}: ResourceUtilizationProps) => React_2.JSX.Element; + +// @public +export interface ResourceUtilizationProps { + // (undocumented) + compressed?: boolean; + // (undocumented) + title: string; + // (undocumented) + total: number | string; + // (undocumented) + totalFormatted: string; + // (undocumented) + usage: number | string; +} + +// @public +export class ServerSideKubernetesAuthProvider + implements KubernetesAuthProvider +{ + // (undocumented) + decorateRequestBodyForAuth( + requestBody: KubernetesRequestBody, + ): Promise<KubernetesRequestBody>; + // (undocumented) + getCredentials(): Promise<{}>; +} + +// @public (undocumented) +export const ServicesAccordions: ({}: ServicesAccordionsProps) => React_2.JSX.Element; + +// @public (undocumented) +export type ServicesAccordionsProps = {}; + +// @public +export const useCustomResources: ( + entity: Entity, + customResourceMatchers: CustomResourceMatcher[], + intervalMs?: number, +) => KubernetesObjects; + +// @public +export const useEvents: ({ + involvedObjectName, + namespace, + clusterName, +}: EventsOptions) => AsyncState<Event_2[]>; + +// @public (undocumented) +export const useKubernetesObjects: ( + entity: Entity, + intervalMs?: number, +) => KubernetesObjects; + +// @public +export const useMatchingErrors: (matcher: ErrorMatcher) => DetectedError[]; + +// @public +export const usePodLogs: ({ + containerScope, + previous, +}: PodLogsOptions) => AsyncState<{ + text: string; +}>; + +// @public +export const usePodMetrics: ( + clusterName: string, + matcher: PodMetricsMatcher, +) => ClientPodStatus | undefined; +``` diff --git a/plugins/kubernetes-react/catalog-info.yaml b/plugins/kubernetes-react/catalog-info.yaml new file mode 100644 index 0000000000..a2fb40d32c --- /dev/null +++ b/plugins/kubernetes-react/catalog-info.yaml @@ -0,0 +1,11 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: backstage-plugin-kubernetes-react + title: '@backstage/plugin-kubernetes-react' + description: >- + Shared frontend utilities for Kubernetes plugins +spec: + lifecycle: experimental + type: backstage-web-library + owner: kubernetes-maintainers diff --git a/plugins/kubernetes-react/package.json b/plugins/kubernetes-react/package.json new file mode 100644 index 0000000000..e708e9e455 --- /dev/null +++ b/plugins/kubernetes-react/package.json @@ -0,0 +1,66 @@ +{ + "name": "@backstage/plugin-kubernetes-react", + "description": "Web library for the kubernetes-react plugin", + "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": "web-library" + }, + "sideEffects": false, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "dependencies": { + "@backstage/catalog-model": "workspace:^", + "@backstage/core-components": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/plugin-kubernetes-common": "workspace:^", + "@backstage/types": "workspace:^", + "@kubernetes-models/apimachinery": "^1.1.0", + "@kubernetes-models/base": "^4.0.1", + "@kubernetes/client-node": "^0.19.0", + "@material-ui/core": "^4.9.13", + "@material-ui/icons": "^4.11.3", + "@material-ui/lab": "^4.0.0-alpha.61", + "@types/react": "^16.13.1 || ^17.0.0", + "cronstrue": "^2.32.0", + "js-yaml": "^4.1.0", + "kubernetes-models": "^4.3.1", + "lodash": "^4.17.21", + "luxon": "^3.0.0", + "react-use": "^17.4.0", + "xterm": "^5.3.0", + "xterm-addon-attach": "^0.9.0", + "xterm-addon-fit": "^0.8.0" + }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, + "devDependencies": { + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/test-utils": "workspace:^", + "@testing-library/jest-dom": "^5.10.1", + "@testing-library/react": "^12.1.3", + "@testing-library/react-hooks": "^8.0.1", + "jest-websocket-mock": "^2.5.0", + "msw": "^1.3.1" + }, + "files": [ + "dist" + ] +} diff --git a/plugins/kubernetes-react/src/__fixtures__/1-cronjobs.json b/plugins/kubernetes-react/src/__fixtures__/1-cronjobs.json new file mode 100644 index 0000000000..1edc43710d --- /dev/null +++ b/plugins/kubernetes-react/src/__fixtures__/1-cronjobs.json @@ -0,0 +1,446 @@ +{ + "cronJobs": [ + { + "metadata": { + "name": "dice-roller-cronjob", + "namespace": "default", + "uid": "9ea073bc-7a4b-4b99-8321-0305bce85568", + "resourceVersion": "1362732552", + "creationTimestamp": "2021-07-16T22:39:58Z", + "labels": { + "backstage.io/kubernetes-id": "dice-roller" + }, + "annotations": {} + }, + "spec": { + "schedule": "30 5 * * *", + "startingDeadlineSeconds": 1800, + "concurrencyPolicy": "Forbid", + "suspend": false, + "jobTemplate": { + "metadata": { "creationTimestamp": null }, + "spec": { + "backoffLimit": 2, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "backstage.io/kubernetes-id": "dice-roller" + }, + "annotations": {} + }, + "spec": { + "containers": [ + { + "name": "busybox", + "image": "busybox", + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "imagePullPolicy": "IfNotPresent", + "command": ["/bin/sh", "-c", "date; echo Rolling a die!"] + } + ], + "restartPolicy": "Never", + "terminationGracePeriodSeconds": 30, + "dnsPolicy": "ClusterFirst", + "securityContext": {}, + "schedulerName": "default-scheduler" + } + } + } + }, + "successfulJobsHistoryLimit": 2, + "failedJobsHistoryLimit": 2 + }, + "status": { + "active": [ + { + "kind": "Job", + "namespace": "default", + "name": "dice-roller-cronjob-1637028600", + "uid": "32be1b89-5b53-45b2-aa84-277e75214f61", + "apiVersion": "batch/v1", + "resourceVersion": "1361174163" + } + ], + "lastScheduleTime": "2021-11-16T02:10:00Z" + } + } + ], + "jobs": [ + { + "metadata": { + "name": "dice-roller-cronjob-1637025000", + "namespace": "default", + "uid": "69d5d242-a9a4-47b8-b9c7-c536ae8f151a", + "resourceVersion": "1361029181", + "creationTimestamp": "2021-11-16T01:10:24Z", + "labels": { + "backstage.io/kubernetes-id": "dice-roller" + }, + "ownerReferences": [ + { + "apiVersion": "batch/v1", + "kind": "CronJob", + "name": "dice-roller-cronjob", + "uid": "9ea073bc-7a4b-4b99-8321-0305bce85568", + "controller": true, + "blockOwnerDeletion": true + } + ] + }, + "spec": { + "parallelism": 1, + "completions": 1, + "backoffLimit": 2, + "selector": { + "matchLabels": { + "controller-uid": "69d5d242-a9a4-47b8-b9c7-c536ae8f151a" + } + }, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "backstage.io/kubernetes-id": "dice-roller", + "controller-uid": "69d5d242-a9a4-47b8-b9c7-c536ae8f151a", + "job-name": "dice-roller-cronjob-1637025000" + }, + "annotations": {} + }, + "spec": { + "containers": [ + { + "command": ["/bin/sh", "-c", "date; echo Rolling a die!"], + "image": "busybox", + "imagePullPolicy": "IfNotPresent", + "name": "busybox", + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + } + ], + "restartPolicy": "Never", + "terminationGracePeriodSeconds": 30, + "dnsPolicy": "ClusterFirst", + "securityContext": {}, + "schedulerName": "default-scheduler" + } + } + }, + "status": { + "conditions": [ + { + "type": "Complete", + "status": "True", + "lastProbeTime": "2021-11-16T01:11:31Z", + "lastTransitionTime": "2021-11-16T01:11:31Z" + } + ], + "startTime": "2021-11-16T01:10:24Z", + "completionTime": "2021-11-16T01:11:31Z", + "succeeded": 1 + } + }, + { + "metadata": { + "name": "dice-roller-cronjob-1637028600", + "namespace": "default", + "uid": "32be1b89-5b53-45b2-aa84-277e75214f61", + "resourceVersion": "1361174166", + "creationTimestamp": "2021-11-16T02:10:22Z", + "labels": { + "backstage.io/kubernetes-id": "dice-roller" + }, + "ownerReferences": [ + { + "apiVersion": "batch/v1", + "kind": "CronJob", + "name": "dice-roller-cronjob", + "uid": "9ea073bc-7a4b-4b99-8321-0305bce85568", + "controller": true, + "blockOwnerDeletion": true + } + ] + }, + "spec": { + "parallelism": 1, + "completions": 1, + "backoffLimit": 2, + "selector": { + "matchLabels": { + "controller-uid": "32be1b89-5b53-45b2-aa84-277e75214f61" + } + }, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "backstage.io/kubernetes-id": "dice-roller", + "controller-uid": "32be1b89-5b53-45b2-aa84-277e75214f61", + "job-name": "dice-roller-cronjob-1637028600" + }, + "annotations": {} + }, + "spec": { + "containers": [ + { + "command": ["/bin/sh", "-c", "date; echo Rolling a die!"], + "image": "busybox", + "imagePullPolicy": "IfNotPresent", + "name": "busybox", + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + } + ], + "restartPolicy": "Never", + "terminationGracePeriodSeconds": 30, + "dnsPolicy": "ClusterFirst", + "securityContext": {}, + "schedulerName": "default-scheduler" + } + } + }, + "status": { "startTime": "2021-11-16T02:10:22Z", "active": 1 } + } + ], + "pods": [ + { + "metadata": { + "name": "dice-roller-cronjob-1637025000-gstc4", + "generateName": "dice-roller-cronjob-1637025000-", + "namespace": "default", + "uid": "3b0f2b65-5ae2-441a-beda-bdc92bcafaf0", + "resourceVersion": "1361029179", + "creationTimestamp": "2021-11-16T01:10:24Z", + "labels": { + "backstage.io/kubernetes-id": "dice-roller", + "controller-uid": "69d5d242-a9a4-47b8-b9c7-c536ae8f151a", + "job-name": "dice-roller-cronjob-1637025000" + }, + "annotations": {}, + "ownerReferences": [ + { + "apiVersion": "batch/v1", + "kind": "Job", + "name": "dice-roller-cronjob-1637025000", + "uid": "69d5d242-a9a4-47b8-b9c7-c536ae8f151a", + "controller": true, + "blockOwnerDeletion": true + } + ] + }, + "spec": { + "volumes": [], + "containers": [ + { + "command": ["/bin/sh", "-c", "date; echo Rolling a die!"], + "image": "busybox", + "imagePullPolicy": "IfNotPresent", + "name": "busybox", + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + } + ], + "restartPolicy": "Never", + "terminationGracePeriodSeconds": 30, + "dnsPolicy": "ClusterFirst", + "serviceAccountName": "default", + "serviceAccount": "default", + "nodeName": "minikube", + "securityContext": {}, + "schedulerName": "default-scheduler", + "tolerations": [ + { + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "effect": "NoExecute", + "tolerationSeconds": 300 + }, + { + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "effect": "NoExecute", + "tolerationSeconds": 300 + } + ], + "priority": 0, + "enableServiceLinks": true + }, + "status": { + "phase": "Succeeded", + "conditions": [ + { + "type": "Initialized", + "status": "True", + "lastProbeTime": null, + "lastTransitionTime": "2021-11-16T01:10:27Z", + "reason": "PodCompleted" + }, + { + "type": "Ready", + "status": "False", + "lastProbeTime": null, + "lastTransitionTime": "2021-11-16T01:11:31Z", + "reason": "PodCompleted" + }, + { + "type": "ContainersReady", + "status": "False", + "lastProbeTime": null, + "lastTransitionTime": "2021-11-16T01:11:31Z", + "reason": "PodCompleted" + }, + { + "type": "PodScheduled", + "status": "True", + "lastProbeTime": null, + "lastTransitionTime": "2021-11-16T01:10:24Z" + } + ], + "hostIP": "192.168.49.2", + "podIP": "172.17.0.25", + "podIPs": [{ "ip": "172.17.0.25" }], + "startTime": "2021-11-16T01:10:24Z", + "containerStatuses": [ + { + "name": "busybox", + "state": { + "terminated": { + "exitCode": 0, + "reason": "Completed", + "startedAt": "2021-11-16T01:10:31Z", + "finishedAt": "2021-11-16T01:11:30Z", + "containerID": "docker://1062343e1bb3625e36717bc15617c1bbca976366c3c9dd87035c71f33d015615" + } + }, + "lastState": {}, + "ready": false, + "restartCount": 0, + "image": "busybox:latest/node", + "imageID": "docker-pullable://busybox@sha256:e7157b6d7ebbe2cce5eaa8cfe8aa4fa82d173999b9f90a9ec42e57323546c353", + "containerID": "docker://1062343e1bb3625e36717bc15617c1bbca976366c3c9dd87035c71f33d015615", + "started": false + } + ], + "qosClass": "Burstable" + } + }, + { + "metadata": { + "name": "dice-roller-cronjob-1637028600-p4mlc", + "generateName": "dice-roller-cronjob-1637028600-", + "namespace": "default", + "uid": "acddd5d2-ac7f-473b-a9d8-17a89f99ac39", + "resourceVersion": "1361174579", + "creationTimestamp": "2021-11-16T02:10:22Z", + "labels": { + "backstage.io/kubernetes-id": "dice-roller", + "controller-uid": "32be1b89-5b53-45b2-aa84-277e75214f61", + "job-name": "dice-roller-cronjob-1637028600" + }, + "annotations": {}, + "ownerReferences": [ + { + "apiVersion": "batch/v1", + "kind": "Job", + "name": "dice-roller-cronjob-1637028600", + "uid": "32be1b89-5b53-45b2-aa84-277e75214f61", + "controller": true, + "blockOwnerDeletion": true + } + ] + }, + "spec": { + "volumes": [], + "containers": [ + { + "command": ["/bin/sh", "-c", "date; echo Rolling a die!"], + "image": "busybox", + "imagePullPolicy": "IfNotPresent", + "name": "busybox", + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + } + ], + "restartPolicy": "Never", + "terminationGracePeriodSeconds": 30, + "dnsPolicy": "ClusterFirst", + "serviceAccountName": "default", + "serviceAccount": "default", + "nodeName": "minikube", + "securityContext": {}, + "schedulerName": "default-scheduler", + "tolerations": [ + { + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "effect": "NoExecute", + "tolerationSeconds": 300 + }, + { + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "effect": "NoExecute", + "tolerationSeconds": 300 + } + ], + "priority": 0, + "enableServiceLinks": true + }, + "status": { + "phase": "Running", + "conditions": [ + { + "type": "Initialized", + "status": "True", + "lastProbeTime": null, + "lastTransitionTime": "2021-11-16T02:10:25Z" + }, + { + "type": "Ready", + "status": "True", + "lastProbeTime": null, + "lastTransitionTime": "2021-11-16T02:10:35Z" + }, + { + "type": "ContainersReady", + "status": "True", + "lastProbeTime": null, + "lastTransitionTime": "2021-11-16T02:10:35Z" + }, + { + "type": "PodScheduled", + "status": "True", + "lastProbeTime": null, + "lastTransitionTime": "2021-11-16T02:10:22Z" + } + ], + "hostIP": "192.168.49.2", + "podIP": "172.17.0.25", + "podIPs": [{ "ip": "172.17.0.25" }], + "startTime": "2021-11-16T02:10:22Z", + "containerStatuses": [ + { + "name": "busybox", + "state": { + "running": { "startedAt": "2021-11-16T02:10:31Z" } + }, + "lastState": {}, + "ready": true, + "restartCount": 0, + "image": "busybox:latest", + "imageID": "docker-pullable://busybox@sha256:e7157b6d7ebbe2cce5eaa8cfe8aa4fa82d173999b9f90a9ec42e57323546c353", + "containerID": "docker://1062343e1bb3625e36717bc15617c1bbca976366c3c9dd87035c71f33d015615", + "started": true + } + ], + "qosClass": "Burstable" + } + } + ] +} diff --git a/plugins/kubernetes-react/src/__fixtures__/1-deployments.json b/plugins/kubernetes-react/src/__fixtures__/1-deployments.json new file mode 100644 index 0000000000..5ad847dc49 --- /dev/null +++ b/plugins/kubernetes-react/src/__fixtures__/1-deployments.json @@ -0,0 +1,2911 @@ +{ + "pods": [ + { + "metadata": { + "creationTimestamp": "2020-09-25T09:58:50.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.11\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T09:58:55.000Z" + } + ], + "name": "dice-roller-6c8646bfd-2m5hv", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "593216", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-2m5hv", + "uid": "aadb71c0-36fa-43e3-b38a-162f134d4359" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://aa4489297c34c48bb33c18474a8d2b33854a82ed42155680b259f635f556ce70", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T09:58:53.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.11", + "podIPs": [ + { + "ip": "172.17.0.11" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T09:58:50.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-25T09:58:50.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.7\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T09:58:55.000Z" + } + ], + "name": "dice-roller-6c8646bfd-4v6s8", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "593221", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-4v6s8", + "uid": "32e56490-6f20-4757-991f-a0c7fb407358" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://d91cc76c41249b8d3dfcf538d180b471b2a7966aae0d17a818307c8a9b4af897", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T09:58:53.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.7", + "podIPs": [ + { + "ip": "172.17.0.7" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T09:58:50.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-24T11:39:26.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-24T11:39:26.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.6\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-24T11:39:27.000Z" + } + ], + "name": "dice-roller-6c8646bfd-b9zt5", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "503886", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-b9zt5", + "uid": "8b6601b6-469e-4e89-8fd0-abb2f1a567e4" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-24T11:39:26.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-24T11:39:27.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-24T11:39:27.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-24T11:39:26.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://c50e0d0fa96f09a2ed5df7dd5a7f7de88e6b7c7addb8f002f299d6afc52d82ce", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-24T11:39:27.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.6", + "podIPs": [ + { + "ip": "172.17.0.6" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-24T11:39:26.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-25T09:58:50.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.13\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T09:58:55.000Z" + } + ], + "name": "dice-roller-6c8646bfd-cfxqc", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "593211", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-cfxqc", + "uid": "e87e1776-0ca7-41fb-aeea-e1f648387545" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:51.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://c1641d986aae424429b7c2c1117baeb17d3794f73206bd57292cdf8264f929b2", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T09:58:53.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.13", + "podIPs": [ + { + "ip": "172.17.0.13" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T09:58:51.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-25T09:58:50.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.15\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T09:58:54.000Z" + } + ], + "name": "dice-roller-6c8646bfd-dtv5z", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "593190", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-dtv5z", + "uid": "1638a41b-e47e-4c17-a1f7-7b447df248b6" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:51.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:53.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:53.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://e62c32db58dbfe0a74b2d2cba0e0a97b7f222693c68e930037ac8738c4758ca3", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T09:58:53.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.15", + "podIPs": [ + { + "ip": "172.17.0.15" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T09:58:51.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-25T09:58:50.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.12\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T09:58:53.000Z" + } + ], + "name": "dice-roller-6c8646bfd-hhts2", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "593186", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-hhts2", + "uid": "ea0b147a-c56a-46e6-9445-7a0b1b0ed3c0" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:53.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:53.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://bcdbc153630f90556d57ff0d62f04d847ca63a5f0a7e5d9230683623d33d4b8d", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T09:58:53.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.12", + "podIPs": [ + { + "ip": "172.17.0.12" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T09:58:50.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-25T09:58:50.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.14\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T09:58:55.000Z" + } + ], + "name": "dice-roller-6c8646bfd-j68lm", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "593226", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-j68lm", + "uid": "b230ff1d-7a13-479b-9c7b-77c26bd79f62" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://30fa8a3429f86ab8e9a4cec472b79d74266609082703f48950f4aae021e9d6a2", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T09:58:53.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.14", + "podIPs": [ + { + "ip": "172.17.0.14" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T09:58:50.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-25T09:58:50.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.9\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T09:58:53.000Z" + } + ], + "name": "dice-roller-6c8646bfd-m6f9w", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "593181", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-m6f9w", + "uid": "9b0079f6-ff29-4619-bf6e-71cc10199ac5" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:53.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:53.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://f78767ee90eedffe46ff64bfe76d7f69426800dd89f3df012daf0baf3a9c5bdd", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T09:58:53.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.9", + "podIPs": [ + { + "ip": "172.17.0.9" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T09:58:50.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-24T11:39:27.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-24T11:39:27.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.4\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-24T11:39:28.000Z" + } + ], + "name": "dice-roller-6c8646bfd-nv9pk", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "503918", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-nv9pk", + "uid": "acf7f77f-78c6-4d4b-bc73-637211770ffc" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-24T11:39:27.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-24T11:39:28.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-24T11:39:28.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-24T11:39:27.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://63dec9b32942c4b09ae43d09d6978261f674a3ee623823b8f1d20da8044c12ac", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-24T11:39:28.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.4", + "podIPs": [ + { + "ip": "172.17.0.4" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-24T11:39:27.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-25T09:58:50.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.10\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T09:58:55.000Z" + } + ], + "name": "dice-roller-6c8646bfd-pjhfj", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "593205", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-pjhfj", + "uid": "78775c3a-7af2-4ebe-a676-bc2e5dfa2bcc" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://cbb83dda250db74285dcbe0b81bd0896acf402bac9710af090311f7360f824aa", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T09:58:53.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.10", + "podIPs": [ + { + "ip": "172.17.0.10" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T09:58:50.000Z" + } + } + ], + "replicaSets": [ + { + "metadata": { + "annotations": { + "deployment.kubernetes.io/desired-replicas": "10", + "deployment.kubernetes.io/max-replicas": "13", + "deployment.kubernetes.io/revision": "2" + }, + "creationTimestamp": "2020-09-24T11:39:26.000Z", + "generation": 3, + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "apps/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:annotations": { + ".": {}, + "f:deployment.kubernetes.io/desired-replicas": {}, + "f:deployment.kubernetes.io/max-replicas": {}, + "f:deployment.kubernetes.io/revision": {} + }, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"7551e949-42d1-4061-83c5-9da107186e47\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:replicas": {}, + "f:selector": { + "f:matchLabels": { + ".": {}, + "f:app": {}, + "f:pod-template-hash": {} + } + }, + "f:template": { + "f:metadata": { + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + } + }, + "f:status": { + "f:availableReplicas": {}, + "f:fullyLabeledReplicas": {}, + "f:observedGeneration": {}, + "f:readyReplicas": {}, + "f:replicas": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:55.000Z" + } + ], + "name": "dice-roller-6c8646bfd", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "Deployment", + "name": "dice-roller", + "uid": "7551e949-42d1-4061-83c5-9da107186e47" + } + ], + "resourceVersion": "593228", + "selfLink": "/apis/apps/v1/namespaces/default/replicasets/dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + }, + "spec": { + "replicas": 10, + "selector": { + "matchLabels": { + "app": "dice-roller", + "pod-template-hash": "6c8646bfd" + } + }, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + } + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + } + ], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "terminationGracePeriodSeconds": 30 + } + } + }, + "status": { + "availableReplicas": 10, + "fullyLabeledReplicas": 10, + "observedGeneration": 3, + "readyReplicas": 10, + "replicas": 10 + } + } + ], + "deployments": [ + { + "metadata": { + "annotations": { + "deployment.kubernetes.io/revision": "2", + "kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"apps/v1\",\"kind\":\"Deployment\",\"metadata\":{\"annotations\":{},\"labels\":{\"backstage.io/kubernetes-id\":\"dice-roller\"},\"name\":\"dice-roller\",\"namespace\":\"default\"},\"spec\":{\"replicas\":10,\"selector\":{\"matchLabels\":{\"app\":\"dice-roller\"}},\"template\":{\"metadata\":{\"labels\":{\"app\":\"dice-roller\",\"backstage.io/kubernetes-id\":\"dice-roller\"}},\"spec\":{\"containers\":[{\"image\":\"nginx:1.14.2\",\"name\":\"nginx\",\"ports\":[{\"containerPort\":80}]}]}}}}\n" + }, + "creationTimestamp": "2020-09-23T12:00:55.000Z", + "generation": 3, + "labels": { + "backstage.io/kubernetes-id": "dice-roller" + }, + "managedFields": [ + { + "apiVersion": "apps/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:annotations": { + ".": {}, + "f:kubectl.kubernetes.io/last-applied-configuration": {} + }, + "f:labels": { + ".": {}, + "f:backstage.io/kubernetes-id": {} + } + }, + "f:spec": { + "f:progressDeadlineSeconds": {}, + "f:replicas": {}, + "f:revisionHistoryLimit": {}, + "f:selector": { + "f:matchLabels": { + ".": {}, + "f:app": {} + } + }, + "f:strategy": { + "f:rollingUpdate": { + ".": {}, + "f:maxSurge": {}, + "f:maxUnavailable": {} + }, + "f:type": {} + }, + "f:template": { + "f:metadata": { + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {} + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + } + } + }, + "manager": "kubectl", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "apps/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:annotations": { + "f:deployment.kubernetes.io/revision": {} + } + }, + "f:status": { + "f:availableReplicas": {}, + "f:conditions": { + ".": {}, + "k:{\"type\":\"Available\"}": { + ".": {}, + "f:lastTransitionTime": {}, + "f:lastUpdateTime": {}, + "f:message": {}, + "f:reason": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Progressing\"}": { + ".": {}, + "f:lastTransitionTime": {}, + "f:lastUpdateTime": {}, + "f:message": {}, + "f:reason": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:observedGeneration": {}, + "f:readyReplicas": {}, + "f:replicas": {}, + "f:updatedReplicas": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:55.000Z" + } + ], + "name": "dice-roller", + "namespace": "default", + "resourceVersion": "593230", + "selfLink": "/apis/apps/v1/namespaces/default/deployments/dice-roller", + "uid": "7551e949-42d1-4061-83c5-9da107186e47" + }, + "spec": { + "progressDeadlineSeconds": 600, + "replicas": 10, + "revisionHistoryLimit": 10, + "selector": { + "matchLabels": { + "app": "dice-roller" + } + }, + "strategy": { + "rollingUpdate": { + "maxSurge": "25%", + "maxUnavailable": "25%" + }, + "type": "RollingUpdate" + }, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller" + } + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + } + ], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "terminationGracePeriodSeconds": 30 + } + } + }, + "status": { + "availableReplicas": 10, + "conditions": [ + { + "lastTransitionTime": "2020-09-23T12:00:55.000Z", + "lastUpdateTime": "2020-09-24T11:39:28.000Z", + "message": "ReplicaSet \"dice-roller-6c8646bfd\" has successfully progressed.", + "reason": "NewReplicaSetAvailable", + "status": "True", + "type": "Progressing" + }, + { + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "lastUpdateTime": "2020-09-25T09:58:55.000Z", + "message": "Deployment has minimum availability.", + "reason": "MinimumReplicasAvailable", + "status": "True", + "type": "Available" + } + ], + "observedGeneration": 3, + "readyReplicas": 10, + "replicas": 10, + "updatedReplicas": 10 + } + } + ], + "horizontalPodAutoscalers": [ + { + "apiVersion": "autoscaling/v1", + "kind": "HorizontalPodAutoscaler", + "metadata": { + "annotations": { + "autoscaling.alpha.kubernetes.io/conditions": "[{\"type\":\"AbleToScale\",\"status\":\"True\",\"lastTransitionTime\":\"2021-01-05T10:26:04Z\",\"reason\":\"SucceededGetScale\",\"message\":\"the HPA controller was able to get the target's current scale\"},{\"type\":\"ScalingActive\",\"status\":\"False\",\"lastTransitionTime\":\"2021-01-05T10:26:04Z\",\"reason\":\"FailedGetResourceMetric\",\"message\":\"the HPA was unable to compute the replica count: unable to get metrics for resource cpu: no metrics returned from resource metrics API\"}]", + "kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"autoscaling/v1\",\"kind\":\"HorizontalPodAutoscaler\",\"metadata\":{\"annotations\":{},\"labels\":{\"backstage.io/kubernetes-id\":\"dice-roller\"},\"name\":\"dice-roller\",\"namespace\":\"default\"},\"spec\":{\"maxReplicas\":15,\"minReplicas\":10,\"scaleTargetRef\":{\"apiVersion\":\"apps/v1\",\"kind\":\"Deployment\",\"name\":\"dice-roller\"},\"targetCPUUtilizationPercentage\":50}}\n" + }, + "creationTimestamp": "2021-01-05T10:25:48Z", + "labels": { + "backstage.io/kubernetes-id": "dice-roller" + }, + "managedFields": [ + { + "apiVersion": "autoscaling/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:annotations": { + ".": {}, + "f:kubectl.kubernetes.io/last-applied-configuration": {} + }, + "f:labels": { + ".": {}, + "f:backstage.io/kubernetes-id": {} + } + }, + "f:spec": { + "f:maxReplicas": {}, + "f:minReplicas": {}, + "f:scaleTargetRef": { + "f:apiVersion": {}, + "f:kind": {}, + "f:name": {} + }, + "f:targetCPUUtilizationPercentage": {} + } + }, + "manager": "kubectl-client-side-apply", + "operation": "Update", + "time": "2021-01-05T10:25:48Z" + }, + { + "apiVersion": "autoscaling/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:annotations": { + "f:autoscaling.alpha.kubernetes.io/conditions": {} + } + }, + "f:status": { + "f:currentReplicas": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2021-01-05T10:26:04Z" + } + ], + "name": "dice-roller", + "namespace": "default", + "resourceVersion": "598", + "selfLink": "/apis/autoscaling/v1/namespaces/default/horizontalpodautoscalers/dice-roller", + "uid": "dd7c5329-567c-43c2-b159-756808d90a8e" + }, + "spec": { + "maxReplicas": 15, + "minReplicas": 10, + "scaleTargetRef": { + "apiVersion": "apps/v1", + "kind": "Deployment", + "name": "dice-roller" + }, + "targetCPUUtilizationPercentage": 50 + }, + "status": { + "currentReplicas": 10, + "desiredReplicas": 0, + "currentCPUUtilizationPercentage": 30 + } + } + ] +} diff --git a/plugins/kubernetes-react/src/__fixtures__/1-statefulsets.json b/plugins/kubernetes-react/src/__fixtures__/1-statefulsets.json new file mode 100644 index 0000000000..6c04774ff1 --- /dev/null +++ b/plugins/kubernetes-react/src/__fixtures__/1-statefulsets.json @@ -0,0 +1,2912 @@ +{ + "pods": [ + { + "metadata": { + "creationTimestamp": "2020-09-25T09:58:50.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.11\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T09:58:55.000Z" + } + ], + "name": "dice-roller-6c8646bfd-2m5hv", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "593216", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-2m5hv", + "uid": "aadb71c0-36fa-43e3-b38a-162f134d4359" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://aa4489297c34c48bb33c18474a8d2b33854a82ed42155680b259f635f556ce70", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T09:58:53.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.11", + "podIPs": [ + { + "ip": "172.17.0.11" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T09:58:50.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-25T09:58:50.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.7\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T09:58:55.000Z" + } + ], + "name": "dice-roller-6c8646bfd-4v6s8", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "593221", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-4v6s8", + "uid": "32e56490-6f20-4757-991f-a0c7fb407358" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://d91cc76c41249b8d3dfcf538d180b471b2a7966aae0d17a818307c8a9b4af897", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T09:58:53.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.7", + "podIPs": [ + { + "ip": "172.17.0.7" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T09:58:50.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-24T11:39:26.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-24T11:39:26.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.6\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-24T11:39:27.000Z" + } + ], + "name": "dice-roller-6c8646bfd-b9zt5", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "503886", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-b9zt5", + "uid": "8b6601b6-469e-4e89-8fd0-abb2f1a567e4" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-24T11:39:26.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-24T11:39:27.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-24T11:39:27.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-24T11:39:26.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://c50e0d0fa96f09a2ed5df7dd5a7f7de88e6b7c7addb8f002f299d6afc52d82ce", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-24T11:39:27.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.6", + "podIPs": [ + { + "ip": "172.17.0.6" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-24T11:39:26.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-25T09:58:50.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.13\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T09:58:55.000Z" + } + ], + "name": "dice-roller-6c8646bfd-cfxqc", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "593211", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-cfxqc", + "uid": "e87e1776-0ca7-41fb-aeea-e1f648387545" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:51.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://c1641d986aae424429b7c2c1117baeb17d3794f73206bd57292cdf8264f929b2", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T09:58:53.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.13", + "podIPs": [ + { + "ip": "172.17.0.13" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T09:58:51.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-25T09:58:50.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.15\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T09:58:54.000Z" + } + ], + "name": "dice-roller-6c8646bfd-dtv5z", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "593190", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-dtv5z", + "uid": "1638a41b-e47e-4c17-a1f7-7b447df248b6" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:51.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:53.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:53.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://e62c32db58dbfe0a74b2d2cba0e0a97b7f222693c68e930037ac8738c4758ca3", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T09:58:53.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.15", + "podIPs": [ + { + "ip": "172.17.0.15" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T09:58:51.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-25T09:58:50.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.12\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T09:58:53.000Z" + } + ], + "name": "dice-roller-6c8646bfd-hhts2", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "593186", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-hhts2", + "uid": "ea0b147a-c56a-46e6-9445-7a0b1b0ed3c0" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:53.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:53.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://bcdbc153630f90556d57ff0d62f04d847ca63a5f0a7e5d9230683623d33d4b8d", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T09:58:53.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.12", + "podIPs": [ + { + "ip": "172.17.0.12" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T09:58:50.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-25T09:58:50.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.14\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T09:58:55.000Z" + } + ], + "name": "dice-roller-6c8646bfd-j68lm", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "593226", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-j68lm", + "uid": "b230ff1d-7a13-479b-9c7b-77c26bd79f62" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://30fa8a3429f86ab8e9a4cec472b79d74266609082703f48950f4aae021e9d6a2", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T09:58:53.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.14", + "podIPs": [ + { + "ip": "172.17.0.14" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T09:58:50.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-25T09:58:50.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.9\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T09:58:53.000Z" + } + ], + "name": "dice-roller-6c8646bfd-m6f9w", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "593181", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-m6f9w", + "uid": "9b0079f6-ff29-4619-bf6e-71cc10199ac5" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:53.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:53.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://f78767ee90eedffe46ff64bfe76d7f69426800dd89f3df012daf0baf3a9c5bdd", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T09:58:53.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.9", + "podIPs": [ + { + "ip": "172.17.0.9" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T09:58:50.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-24T11:39:27.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-24T11:39:27.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.4\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-24T11:39:28.000Z" + } + ], + "name": "dice-roller-6c8646bfd-nv9pk", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "503918", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-nv9pk", + "uid": "acf7f77f-78c6-4d4b-bc73-637211770ffc" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-24T11:39:27.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-24T11:39:28.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-24T11:39:28.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-24T11:39:27.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://63dec9b32942c4b09ae43d09d6978261f674a3ee623823b8f1d20da8044c12ac", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-24T11:39:28.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.4", + "podIPs": [ + { + "ip": "172.17.0.4" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-24T11:39:27.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-25T09:58:50.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.10\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T09:58:55.000Z" + } + ], + "name": "dice-roller-6c8646bfd-pjhfj", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "593205", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-pjhfj", + "uid": "78775c3a-7af2-4ebe-a676-bc2e5dfa2bcc" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://cbb83dda250db74285dcbe0b81bd0896acf402bac9710af090311f7360f824aa", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T09:58:53.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.10", + "podIPs": [ + { + "ip": "172.17.0.10" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T09:58:50.000Z" + } + } + ], + "replicaSets": [ + { + "metadata": { + "annotations": { + "deployment.kubernetes.io/desired-replicas": "10", + "deployment.kubernetes.io/max-replicas": "13", + "deployment.kubernetes.io/revision": "2" + }, + "creationTimestamp": "2020-09-24T11:39:26.000Z", + "generation": 3, + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "apps/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:annotations": { + ".": {}, + "f:deployment.kubernetes.io/desired-replicas": {}, + "f:deployment.kubernetes.io/max-replicas": {}, + "f:deployment.kubernetes.io/revision": {} + }, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"7551e949-42d1-4061-83c5-9da107186e47\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:replicas": {}, + "f:selector": { + "f:matchLabels": { + ".": {}, + "f:app": {}, + "f:pod-template-hash": {} + } + }, + "f:template": { + "f:metadata": { + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + } + }, + "f:status": { + "f:availableReplicas": {}, + "f:fullyLabeledReplicas": {}, + "f:observedGeneration": {}, + "f:readyReplicas": {}, + "f:replicas": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:55.000Z" + } + ], + "name": "dice-roller-6c8646bfd", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "Deployment", + "name": "dice-roller", + "uid": "7551e949-42d1-4061-83c5-9da107186e47" + } + ], + "resourceVersion": "593228", + "selfLink": "/apis/apps/v1/namespaces/default/replicasets/dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + }, + "spec": { + "replicas": 10, + "selector": { + "matchLabels": { + "app": "dice-roller", + "pod-template-hash": "6c8646bfd" + } + }, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + } + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + } + ], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "terminationGracePeriodSeconds": 30 + } + } + }, + "status": { + "availableReplicas": 10, + "fullyLabeledReplicas": 10, + "observedGeneration": 3, + "readyReplicas": 10, + "replicas": 10 + } + } + ], + "statefulsets": [ + { + "metadata": { + "annotations": { + "deployment.kubernetes.io/revision": "2", + "kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"apps/v1\",\"kind\":\"StatefulSet\",\"metadata\":{\"annotations\":{},\"labels\":{\"backstage.io/kubernetes-id\":\"dice-roller\"},\"name\":\"dice-roller\",\"namespace\":\"default\"},\"spec\":{\"replicas\":10,\"selector\":{\"matchLabels\":{\"app\":\"dice-roller\"}},\"template\":{\"metadata\":{\"labels\":{\"app\":\"dice-roller\",\"backstage.io/kubernetes-id\":\"dice-roller\"}},\"spec\":{\"containers\":[{\"image\":\"nginx:1.14.2\",\"name\":\"nginx\",\"ports\":[{\"containerPort\":80}]}]}}}}\n" + }, + "creationTimestamp": "2020-09-23T12:00:55.000Z", + "generation": 3, + "labels": { + "backstage.io/kubernetes-id": "dice-roller" + }, + "managedFields": [ + { + "apiVersion": "apps/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:annotations": { + ".": {}, + "f:kubectl.kubernetes.io/last-applied-configuration": {} + }, + "f:labels": { + ".": {}, + "f:backstage.io/kubernetes-id": {} + } + }, + "f:spec": { + "f:progressDeadlineSeconds": {}, + "f:replicas": {}, + "f:revisionHistoryLimit": {}, + "f:selector": { + "f:matchLabels": { + ".": {}, + "f:app": {} + } + }, + "f:strategy": { + "f:rollingUpdate": { + ".": {}, + "f:maxSurge": {}, + "f:maxUnavailable": {} + }, + "f:type": {} + }, + "f:template": { + "f:metadata": { + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {} + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + } + } + }, + "manager": "kubectl", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "apps/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:annotations": { + "f:deployment.kubernetes.io/revision": {} + } + }, + "f:status": { + "f:availableReplicas": {}, + "f:conditions": { + ".": {}, + "k:{\"type\":\"Available\"}": { + ".": {}, + "f:lastTransitionTime": {}, + "f:lastUpdateTime": {}, + "f:message": {}, + "f:reason": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Progressing\"}": { + ".": {}, + "f:lastTransitionTime": {}, + "f:lastUpdateTime": {}, + "f:message": {}, + "f:reason": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:observedGeneration": {}, + "f:readyReplicas": {}, + "f:replicas": {}, + "f:updatedReplicas": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:55.000Z" + } + ], + "name": "dice-roller", + "namespace": "default", + "resourceVersion": "593230", + "selfLink": "/apis/apps/v1/namespaces/default/deployments/dice-roller", + "uid": "7551e949-42d1-4061-83c5-9da107186e47" + }, + "spec": { + "replicas": 10, + "revisionHistoryLimit": 10, + "selector": { + "matchLabels": { + "app": "dice-roller" + } + }, + "updateStrategy": { + "rollingUpdate": { + "maxSurge": "25%", + "maxUnavailable": "25%" + }, + "type": "RollingUpdate" + }, + "podManagementPolicy": "Parallel", + "serviceName": "dice-roller", + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller" + } + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + } + ], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "terminationGracePeriodSeconds": 30 + } + } + }, + "status": { + "availableReplicas": 10, + "conditions": [ + { + "lastTransitionTime": "2020-09-23T12:00:55.000Z", + "lastUpdateTime": "2020-09-24T11:39:28.000Z", + "message": "ReplicaSet \"dice-roller-6c8646bfd\" has successfully progressed.", + "reason": "NewReplicaSetAvailable", + "status": "True", + "type": "Progressing" + }, + { + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "lastUpdateTime": "2020-09-25T09:58:55.000Z", + "message": "Deployment has minimum availability.", + "reason": "MinimumReplicasAvailable", + "status": "True", + "type": "Available" + } + ], + "observedGeneration": 3, + "readyReplicas": 10, + "replicas": 10, + "updatedReplicas": 10 + } + } + ], + "horizontalPodAutoscalers": [ + { + "apiVersion": "autoscaling/v1", + "kind": "HorizontalPodAutoscaler", + "metadata": { + "annotations": { + "autoscaling.alpha.kubernetes.io/conditions": "[{\"type\":\"AbleToScale\",\"status\":\"True\",\"lastTransitionTime\":\"2021-01-05T10:26:04Z\",\"reason\":\"SucceededGetScale\",\"message\":\"the HPA controller was able to get the target's current scale\"},{\"type\":\"ScalingActive\",\"status\":\"False\",\"lastTransitionTime\":\"2021-01-05T10:26:04Z\",\"reason\":\"FailedGetResourceMetric\",\"message\":\"the HPA was unable to compute the replica count: unable to get metrics for resource cpu: no metrics returned from resource metrics API\"}]", + "kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"autoscaling/v1\",\"kind\":\"HorizontalPodAutoscaler\",\"metadata\":{\"annotations\":{},\"labels\":{\"backstage.io/kubernetes-id\":\"dice-roller\"},\"name\":\"dice-roller\",\"namespace\":\"default\"},\"spec\":{\"maxReplicas\":15,\"minReplicas\":10,\"scaleTargetRef\":{\"apiVersion\":\"apps/v1\",\"kind\":\"Deployment\",\"name\":\"dice-roller\"},\"targetCPUUtilizationPercentage\":50}}\n" + }, + "creationTimestamp": "2021-01-05T10:25:48Z", + "labels": { + "backstage.io/kubernetes-id": "dice-roller" + }, + "managedFields": [ + { + "apiVersion": "autoscaling/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:annotations": { + ".": {}, + "f:kubectl.kubernetes.io/last-applied-configuration": {} + }, + "f:labels": { + ".": {}, + "f:backstage.io/kubernetes-id": {} + } + }, + "f:spec": { + "f:maxReplicas": {}, + "f:minReplicas": {}, + "f:scaleTargetRef": { + "f:apiVersion": {}, + "f:kind": {}, + "f:name": {} + }, + "f:targetCPUUtilizationPercentage": {} + } + }, + "manager": "kubectl-client-side-apply", + "operation": "Update", + "time": "2021-01-05T10:25:48Z" + }, + { + "apiVersion": "autoscaling/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:annotations": { + "f:autoscaling.alpha.kubernetes.io/conditions": {} + } + }, + "f:status": { + "f:currentReplicas": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2021-01-05T10:26:04Z" + } + ], + "name": "dice-roller", + "namespace": "default", + "resourceVersion": "598", + "selfLink": "/apis/autoscaling/v1/namespaces/default/horizontalpodautoscalers/dice-roller", + "uid": "dd7c5329-567c-43c2-b159-756808d90a8e" + }, + "spec": { + "maxReplicas": 15, + "minReplicas": 10, + "scaleTargetRef": { + "apiVersion": "apps/v1", + "kind": "Deployment", + "name": "dice-roller" + }, + "targetCPUUtilizationPercentage": 50 + }, + "status": { + "currentReplicas": 10, + "desiredReplicas": 0, + "currentCPUUtilizationPercentage": 30 + } + } + ] +} diff --git a/plugins/kubernetes-react/src/__fixtures__/2-cronjobs.json b/plugins/kubernetes-react/src/__fixtures__/2-cronjobs.json new file mode 100644 index 0000000000..6c087023b7 --- /dev/null +++ b/plugins/kubernetes-react/src/__fixtures__/2-cronjobs.json @@ -0,0 +1,385 @@ +{ + "cronJobs": [ + { + "metadata": { + "name": "dice-roller-cronjob", + "namespace": "default", + "uid": "9ea073bc-7a4b-4b99-8321-0305bce85568", + "resourceVersion": "1362732552", + "creationTimestamp": "2021-07-16T22:39:58Z", + "labels": { + "backstage.io/kubernetes-id": "dice-roller" + }, + "annotations": {} + }, + "spec": { + "schedule": "* */2 * * *", + "startingDeadlineSeconds": 1800, + "concurrencyPolicy": "Forbid", + "suspend": true, + "jobTemplate": { + "metadata": { "creationTimestamp": null }, + "spec": { + "backoffLimit": 2, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "backstage.io/kubernetes-id": "dice-roller" + }, + "annotations": {} + }, + "spec": { + "containers": [ + { + "name": "busybox", + "image": "busybox", + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "imagePullPolicy": "IfNotPresent", + "command": ["/bin/sh", "-c", "date; echo Rolling a die!"] + } + ], + "restartPolicy": "Never", + "terminationGracePeriodSeconds": 30, + "dnsPolicy": "ClusterFirst", + "securityContext": {}, + "schedulerName": "default-scheduler" + } + } + } + }, + "successfulJobsHistoryLimit": 2, + "failedJobsHistoryLimit": 2 + }, + "status": { + "lastScheduleTime": "2021-11-16T02:10:00Z" + } + } + ], + "jobs": [ + { + "metadata": { + "name": "dice-roller-cronjob-1637025000", + "namespace": "default", + "uid": "69d5d242-a9a4-47b8-b9c7-c536ae8f151a", + "resourceVersion": "1361029181", + "creationTimestamp": "2021-11-16T01:10:24Z", + "labels": { + "backstage.io/kubernetes-id": "dice-roller" + }, + "ownerReferences": [ + { + "apiVersion": "batch/v1", + "kind": "CronJob", + "name": "dice-roller-cronjob", + "uid": "9ea073bc-7a4b-4b99-8321-0305bce85568", + "controller": true, + "blockOwnerDeletion": true + } + ] + }, + "spec": { + "parallelism": 1, + "completions": 1, + "backoffLimit": 2, + "selector": { + "matchLabels": { + "controller-uid": "69d5d242-a9a4-47b8-b9c7-c536ae8f151a" + } + }, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "backstage.io/kubernetes-id": "dice-roller", + "controller-uid": "69d5d242-a9a4-47b8-b9c7-c536ae8f151a", + "job-name": "dice-roller-cronjob-1637025000" + }, + "annotations": {} + }, + "spec": { + "containers": [ + { + "command": ["/bin/sh", "-c", "date; echo Rolling a die!"], + "image": "busybox", + "imagePullPolicy": "IfNotPresent", + "name": "busybox", + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + } + ], + "restartPolicy": "Never", + "terminationGracePeriodSeconds": 30, + "dnsPolicy": "ClusterFirst", + "securityContext": {}, + "schedulerName": "default-scheduler" + } + } + }, + "status": { + "conditions": [ + { + "type": "Failed", + "status": "True", + "reason": "BackoffLimitExceeded", + "lastProbeTime": "2021-11-16T01:11:31Z", + "lastTransitionTime": "2021-11-16T01:11:31Z" + } + ], + "startTime": "2021-11-16T01:10:24Z", + "failed": 2 + } + } + ], + "pods": [ + { + "metadata": { + "name": "dice-roller-cronjob-1637025000-gstc4", + "generateName": "dice-roller-cronjob-1637025000-", + "namespace": "default", + "uid": "3b0f2b65-5ae2-441a-beda-bdc92bcafaf0", + "resourceVersion": "1361029179", + "creationTimestamp": "2021-11-16T01:10:24Z", + "labels": { + "backstage.io/kubernetes-id": "dice-roller", + "controller-uid": "69d5d242-a9a4-47b8-b9c7-c536ae8f151a", + "job-name": "dice-roller-cronjob-1637025000" + }, + "annotations": {}, + "ownerReferences": [ + { + "apiVersion": "batch/v1", + "kind": "Job", + "name": "dice-roller-cronjob-1637025000", + "uid": "69d5d242-a9a4-47b8-b9c7-c536ae8f151a", + "controller": true, + "blockOwnerDeletion": true + } + ] + }, + "spec": { + "volumes": [], + "containers": [ + { + "command": ["/bin/sh", "-c", "date; echo Rolling a die!"], + "image": "busybox", + "imagePullPolicy": "IfNotPresent", + "name": "busybox", + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + } + ], + "restartPolicy": "Never", + "terminationGracePeriodSeconds": 30, + "dnsPolicy": "ClusterFirst", + "serviceAccountName": "default", + "serviceAccount": "default", + "nodeName": "minikube", + "securityContext": {}, + "schedulerName": "default-scheduler", + "tolerations": [ + { + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "effect": "NoExecute", + "tolerationSeconds": 300 + }, + { + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "effect": "NoExecute", + "tolerationSeconds": 300 + } + ], + "priority": 0, + "enableServiceLinks": true + }, + "status": { + "phase": "Failed", + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2021-11-18T19:10:13Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2021-11-18T19:11:02Z", + "message": "containers with unready status: [busybox]", + "reason": "ContainersNotReady", + "status": "False", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2021-11-18T19:11:02Z", + "message": "containers with unready status: [busybox]", + "reason": "ContainersNotReady", + "status": "False", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2021-11-18T19:10:08Z", + "status": "True", + "type": "PodScheduled" + } + ], + "hostIP": "192.168.49.2", + "podIP": "172.17.0.25", + "podIPs": [{ "ip": "172.17.0.25" }], + "startTime": "2021-11-18T19:10:08Z", + "containerStatuses": [ + { + "name": "busybox", + "state": { + "terminated": { + "exitCode": 1, + "finishedAt": "2021-11-18T19:11:01Z", + "reason": "Error", + "startedAt": "2021-11-18T19:10:17Z", + "containerID": "docker://1062343e1bb3625e36717bc15617c1bbca976366c3c9dd87035c71f33d015615" + } + }, + "lastState": {}, + "ready": false, + "restartCount": 0, + "image": "busybox:latest", + "imageID": "docker-pullable://busybox@sha256:e7157b6d7ebbe2cce5eaa8cfe8aa4fa82d173999b9f90a9ec42e57323546c353", + "containerID": "docker://1062343e1bb3625e36717bc15617c1bbca976366c3c9dd87035c71f33d015615", + "started": false + } + ], + "qosClass": "Burstable" + } + }, + { + "metadata": { + "name": "dice-roller-cronjob-1637025000-p4mlc", + "generateName": "dice-roller-cronjob-1637025000-", + "namespace": "default", + "uid": "acddd5d2-ac7f-473b-a9d8-17a89f99ac39", + "resourceVersion": "1361174579", + "creationTimestamp": "2021-11-16T02:10:22Z", + "labels": { + "backstage.io/kubernetes-id": "dice-roller", + "controller-uid": "69d5d242-a9a4-47b8-b9c7-c536ae8f151a", + "job-name": "dice-roller-cronjob-1637025000" + }, + "annotations": {}, + "ownerReferences": [ + { + "apiVersion": "batch/v1", + "kind": "Job", + "name": "dice-roller-cronjob-1637025000", + "uid": "69d5d242-a9a4-47b8-b9c7-c536ae8f151a", + "controller": true, + "blockOwnerDeletion": true + } + ] + }, + "spec": { + "volumes": [], + "containers": [ + { + "command": ["/bin/sh", "-c", "date; echo Rolling a die!"], + "image": "busybox", + "imagePullPolicy": "IfNotPresent", + "name": "busybox", + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + } + ], + "restartPolicy": "Never", + "terminationGracePeriodSeconds": 30, + "dnsPolicy": "ClusterFirst", + "serviceAccountName": "default", + "serviceAccount": "default", + "nodeName": "minikube", + "securityContext": {}, + "schedulerName": "default-scheduler", + "tolerations": [ + { + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "effect": "NoExecute", + "tolerationSeconds": 300 + }, + { + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "effect": "NoExecute", + "tolerationSeconds": 300 + } + ], + "priority": 0, + "enableServiceLinks": true + }, + "status": { + "phase": "Failed", + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2021-11-18T19:10:13Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2021-11-18T19:11:02Z", + "message": "containers with unready status: [busybox]", + "reason": "ContainersNotReady", + "status": "False", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2021-11-18T19:11:02Z", + "message": "containers with unready status: [busybox]", + "reason": "ContainersNotReady", + "status": "False", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2021-11-18T19:10:08Z", + "status": "True", + "type": "PodScheduled" + } + ], + "hostIP": "192.168.49.2", + "podIP": "172.17.0.25", + "podIPs": [{ "ip": "172.17.0.25" }], + "startTime": "2021-11-16T02:10:22Z", + "containerStatuses": [ + { + "name": "busybox", + "state": { + "terminated": { + "exitCode": 1, + "finishedAt": "2021-11-18T19:11:01Z", + "reason": "Error", + "startedAt": "2021-11-18T19:10:17Z", + "containerID": "docker://2659c4d0f8a68f2b49863c18738322f1686d5b87275428e5e641fd9fd9e06739" + } + }, + "lastState": {}, + "ready": true, + "restartCount": 0, + "image": "busybox:latest", + "imageID": "docker-pullable://busybox@sha256:e7157b6d7ebbe2cce5eaa8cfe8aa4fa82d173999b9f90a9ec42e57323546c353", + "containerID": "docker://2659c4d0f8a68f2b49863c18738322f1686d5b87275428e5e641fd9fd9e06739", + "started": true + } + ], + "qosClass": "Burstable" + } + } + ] +} diff --git a/plugins/kubernetes-react/src/__fixtures__/2-deployments.json b/plugins/kubernetes-react/src/__fixtures__/2-deployments.json new file mode 100644 index 0000000000..f5efdbf1cb --- /dev/null +++ b/plugins/kubernetes-react/src/__fixtures__/2-deployments.json @@ -0,0 +1,4519 @@ +{ + "pods": [ + { + "metadata": { + "creationTimestamp": "2020-09-25T09:58:50.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.11\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T09:58:55.000Z" + } + ], + "name": "dice-roller-6c8646bfd-2m5hv", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "593216", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-2m5hv", + "uid": "aadb71c0-36fa-43e3-b38a-162f134d4359" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://aa4489297c34c48bb33c18474a8d2b33854a82ed42155680b259f635f556ce70", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T09:58:53.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.11", + "podIPs": [ + { + "ip": "172.17.0.11" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T09:58:50.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-25T09:58:50.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.7\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T09:58:55.000Z" + } + ], + "name": "dice-roller-6c8646bfd-4v6s8", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "593221", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-4v6s8", + "uid": "32e56490-6f20-4757-991f-a0c7fb407358" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://d91cc76c41249b8d3dfcf538d180b471b2a7966aae0d17a818307c8a9b4af897", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T09:58:53.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.7", + "podIPs": [ + { + "ip": "172.17.0.7" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T09:58:50.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-24T11:39:26.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-24T11:39:26.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.6\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-24T11:39:27.000Z" + } + ], + "name": "dice-roller-6c8646bfd-b9zt5", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "503886", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-b9zt5", + "uid": "8b6601b6-469e-4e89-8fd0-abb2f1a567e4" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-24T11:39:26.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-24T11:39:27.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-24T11:39:27.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-24T11:39:26.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://c50e0d0fa96f09a2ed5df7dd5a7f7de88e6b7c7addb8f002f299d6afc52d82ce", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-24T11:39:27.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.6", + "podIPs": [ + { + "ip": "172.17.0.6" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-24T11:39:26.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-25T09:58:50.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.13\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T09:58:55.000Z" + } + ], + "name": "dice-roller-6c8646bfd-cfxqc", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "593211", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-cfxqc", + "uid": "e87e1776-0ca7-41fb-aeea-e1f648387545" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:51.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://c1641d986aae424429b7c2c1117baeb17d3794f73206bd57292cdf8264f929b2", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T09:58:53.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.13", + "podIPs": [ + { + "ip": "172.17.0.13" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T09:58:51.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-25T09:58:50.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.15\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T09:58:54.000Z" + } + ], + "name": "dice-roller-6c8646bfd-dtv5z", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "593190", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-dtv5z", + "uid": "1638a41b-e47e-4c17-a1f7-7b447df248b6" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:51.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:53.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:53.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://e62c32db58dbfe0a74b2d2cba0e0a97b7f222693c68e930037ac8738c4758ca3", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T09:58:53.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.15", + "podIPs": [ + { + "ip": "172.17.0.15" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T09:58:51.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-25T09:58:50.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.12\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T09:58:53.000Z" + } + ], + "name": "dice-roller-6c8646bfd-hhts2", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "593186", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-hhts2", + "uid": "ea0b147a-c56a-46e6-9445-7a0b1b0ed3c0" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:53.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:53.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://bcdbc153630f90556d57ff0d62f04d847ca63a5f0a7e5d9230683623d33d4b8d", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T09:58:53.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.12", + "podIPs": [ + { + "ip": "172.17.0.12" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T09:58:50.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-25T09:58:50.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.14\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T09:58:55.000Z" + } + ], + "name": "dice-roller-6c8646bfd-j68lm", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "593226", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-j68lm", + "uid": "b230ff1d-7a13-479b-9c7b-77c26bd79f62" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://30fa8a3429f86ab8e9a4cec472b79d74266609082703f48950f4aae021e9d6a2", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T09:58:53.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.14", + "podIPs": [ + { + "ip": "172.17.0.14" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T09:58:50.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-25T09:58:50.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.9\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T09:58:53.000Z" + } + ], + "name": "dice-roller-6c8646bfd-m6f9w", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "593181", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-m6f9w", + "uid": "9b0079f6-ff29-4619-bf6e-71cc10199ac5" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:53.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:53.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://f78767ee90eedffe46ff64bfe76d7f69426800dd89f3df012daf0baf3a9c5bdd", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T09:58:53.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.9", + "podIPs": [ + { + "ip": "172.17.0.9" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T09:58:50.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-24T11:39:27.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-24T11:39:27.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.4\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-24T11:39:28.000Z" + } + ], + "name": "dice-roller-6c8646bfd-nv9pk", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "503918", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-nv9pk", + "uid": "acf7f77f-78c6-4d4b-bc73-637211770ffc" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-24T11:39:27.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-24T11:39:28.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-24T11:39:28.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-24T11:39:27.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://63dec9b32942c4b09ae43d09d6978261f674a3ee623823b8f1d20da8044c12ac", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-24T11:39:28.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.4", + "podIPs": [ + { + "ip": "172.17.0.4" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-24T11:39:27.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-25T09:58:50.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.10\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T09:58:55.000Z" + } + ], + "name": "dice-roller-6c8646bfd-pjhfj", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "593205", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-pjhfj", + "uid": "78775c3a-7af2-4ebe-a676-bc2e5dfa2bcc" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://cbb83dda250db74285dcbe0b81bd0896acf402bac9710af090311f7360f824aa", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T09:58:53.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.10", + "podIPs": [ + { + "ip": "172.17.0.10" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T09:58:50.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-25T10:34:01.000Z", + "generateName": "dice-roller-canary-7d64cd756c-", + "labels": { + "app": "dice-roller-canary", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "7d64cd756c" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"9208395b-a9a7-4e46-b881-6a189f7fbdb0\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + }, + "k:{\"name\":\"other-side-car\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":82,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + }, + "k:{\"name\":\"side-car\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":81,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T10:34:01.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:message": {}, + "f:reason": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:message": {}, + "f:reason": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.16\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T14:18:54.000Z" + } + ], + "name": "dice-roller-canary-7d64cd756c-55rfq", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-canary-7d64cd756c", + "uid": "9208395b-a9a7-4e46-b881-6a189f7fbdb0" + } + ], + "resourceVersion": "620452", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-canary-7d64cd756c-55rfq", + "uid": "65ad28e3-5d51-4b4b-9bf8-4cb069803034" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + }, + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "side-car", + "ports": [ + { + "containerPort": 81, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + }, + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "other-side-car", + "ports": [ + { + "containerPort": 82, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T10:34:01.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T14:18:53.000Z", + "message": "containers with unready status: [side-car other-side-car]", + "reason": "ContainersNotReady", + "status": "False", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T14:18:53.000Z", + "message": "containers with unready status: [side-car other-side-car]", + "reason": "ContainersNotReady", + "status": "False", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T10:34:01.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://6ce15178d114a85f3d2e832de45c3355ab5b71ed5f4d4d225ee1c83bf07f69d9", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T10:34:01.000Z" + } + } + }, + { + "containerID": "docker://b3ce93d7f90bfe22558c61d2505b8473580574accdebb5fa4e51c0729c3511f4", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": { + "terminated": { + "containerID": "docker://b3ce93d7f90bfe22558c61d2505b8473580574accdebb5fa4e51c0729c3511f4", + "exitCode": 1, + "finishedAt": "2020-09-25T14:18:52.000Z", + "reason": "Error", + "startedAt": "2020-09-25T14:18:50.000Z" + } + }, + "name": "other-side-car", + "ready": false, + "restartCount": 38, + "started": false, + "state": { + "waiting": { + "message": "back-off 5m0s restarting failed container=other-side-car pod=dice-roller-canary-7d64cd756c-55rfq_default(65ad28e3-5d51-4b4b-9bf8-4cb069803034)", + "reason": "CrashLoopBackOff" + } + } + }, + { + "containerID": "docker://b7f0e65a2b8ab48c5f234616cfe8286aa96b55c3ef09c5cfbc4cdbe67a96f8cb", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": { + "terminated": { + "containerID": "docker://b7f0e65a2b8ab48c5f234616cfe8286aa96b55c3ef09c5cfbc4cdbe67a96f8cb", + "exitCode": 1, + "finishedAt": "2020-09-25T14:18:52.000Z", + "reason": "Error", + "startedAt": "2020-09-25T14:18:50.000Z" + } + }, + "name": "side-car", + "ready": false, + "restartCount": 38, + "started": false, + "state": { + "waiting": { + "message": "back-off 5m0s restarting failed container=side-car pod=dice-roller-canary-7d64cd756c-55rfq_default(65ad28e3-5d51-4b4b-9bf8-4cb069803034)", + "reason": "CrashLoopBackOff" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.16", + "podIPs": [ + { + "ip": "172.17.0.16" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T10:34:01.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-25T10:34:02.000Z", + "generateName": "dice-roller-canary-7d64cd756c-", + "labels": { + "app": "dice-roller-canary", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "7d64cd756c" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"9208395b-a9a7-4e46-b881-6a189f7fbdb0\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + }, + "k:{\"name\":\"other-side-car\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":82,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + }, + "k:{\"name\":\"side-car\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":81,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T10:34:02.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:message": {}, + "f:reason": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:message": {}, + "f:reason": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.5\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T14:19:05.000Z" + } + ], + "name": "dice-roller-canary-7d64cd756c-vtbdx", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-canary-7d64cd756c", + "uid": "9208395b-a9a7-4e46-b881-6a189f7fbdb0" + } + ], + "resourceVersion": "620481", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-canary-7d64cd756c-vtbdx", + "uid": "0b8d9d79-b43d-4339-be57-ad5c63add77e" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + }, + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "side-car", + "ports": [ + { + "containerPort": 81, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + }, + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "other-side-car", + "ports": [ + { + "containerPort": 82, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T10:34:02.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T14:19:04.000Z", + "message": "containers with unready status: [side-car other-side-car]", + "reason": "ContainersNotReady", + "status": "False", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T14:19:04.000Z", + "message": "containers with unready status: [side-car other-side-car]", + "reason": "ContainersNotReady", + "status": "False", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T10:34:02.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://3f9cadc6f135247eb2df9aaca8f25ea05dcf42be86d58fb833c8acf192da0d66", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T10:34:03.000Z" + } + } + }, + { + "containerID": "docker://5e3a9f9129e5ce74fea249c013afcc056ee95a940fed24495ef9b58df67771f3", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": { + "terminated": { + "containerID": "docker://5e3a9f9129e5ce74fea249c013afcc056ee95a940fed24495ef9b58df67771f3", + "exitCode": 1, + "finishedAt": "2020-09-25T14:19:03.000Z", + "reason": "Error", + "startedAt": "2020-09-25T14:19:01.000Z" + } + }, + "name": "other-side-car", + "ready": false, + "restartCount": 38, + "started": false, + "state": { + "waiting": { + "message": "back-off 5m0s restarting failed container=other-side-car pod=dice-roller-canary-7d64cd756c-vtbdx_default(0b8d9d79-b43d-4339-be57-ad5c63add77e)", + "reason": "CrashLoopBackOff" + } + } + }, + { + "containerID": "docker://21b42cae298c0ed7f90373974d8c88b0941d17733f35398144a17ece32e03210", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": { + "terminated": { + "containerID": "docker://21b42cae298c0ed7f90373974d8c88b0941d17733f35398144a17ece32e03210", + "exitCode": 1, + "finishedAt": "2020-09-25T14:19:03.000Z", + "reason": "Error", + "startedAt": "2020-09-25T14:19:01.000Z" + } + }, + "name": "side-car", + "ready": false, + "restartCount": 38, + "started": false, + "state": { + "waiting": { + "message": "back-off 5m0s restarting failed container=side-car pod=dice-roller-canary-7d64cd756c-vtbdx_default(0b8d9d79-b43d-4339-be57-ad5c63add77e)", + "reason": "CrashLoopBackOff" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.5", + "podIPs": [ + { + "ip": "172.17.0.5" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T10:34:02.000Z" + } + } + ], + "replicaSets": [ + { + "metadata": { + "annotations": { + "deployment.kubernetes.io/desired-replicas": "10", + "deployment.kubernetes.io/max-replicas": "13", + "deployment.kubernetes.io/revision": "2" + }, + "creationTimestamp": "2020-09-24T11:39:26.000Z", + "generation": 3, + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "apps/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:annotations": { + ".": {}, + "f:deployment.kubernetes.io/desired-replicas": {}, + "f:deployment.kubernetes.io/max-replicas": {}, + "f:deployment.kubernetes.io/revision": {} + }, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"7551e949-42d1-4061-83c5-9da107186e47\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:replicas": {}, + "f:selector": { + "f:matchLabels": { + ".": {}, + "f:app": {}, + "f:pod-template-hash": {} + } + }, + "f:template": { + "f:metadata": { + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + } + }, + "f:status": { + "f:availableReplicas": {}, + "f:fullyLabeledReplicas": {}, + "f:observedGeneration": {}, + "f:readyReplicas": {}, + "f:replicas": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:55.000Z" + } + ], + "name": "dice-roller-6c8646bfd", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "Deployment", + "name": "dice-roller", + "uid": "7551e949-42d1-4061-83c5-9da107186e47" + } + ], + "resourceVersion": "593228", + "selfLink": "/apis/apps/v1/namespaces/default/replicasets/dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + }, + "spec": { + "replicas": 10, + "selector": { + "matchLabels": { + "app": "dice-roller", + "pod-template-hash": "6c8646bfd" + } + }, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + } + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + } + ], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "terminationGracePeriodSeconds": 30 + } + } + }, + "status": { + "availableReplicas": 10, + "fullyLabeledReplicas": 10, + "observedGeneration": 3, + "readyReplicas": 10, + "replicas": 10 + } + }, + { + "metadata": { + "annotations": { + "deployment.kubernetes.io/desired-replicas": "2", + "deployment.kubernetes.io/max-replicas": "3", + "deployment.kubernetes.io/revision": "3" + }, + "creationTimestamp": "2020-09-25T10:34:01.000Z", + "generation": 2, + "labels": { + "app": "dice-roller-canary", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "7d64cd756c" + }, + "managedFields": [ + { + "apiVersion": "apps/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:annotations": { + ".": {}, + "f:deployment.kubernetes.io/desired-replicas": {}, + "f:deployment.kubernetes.io/max-replicas": {}, + "f:deployment.kubernetes.io/revision": {} + }, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"0b6ae80f-999b-40e9-b116-ea925f0ed07b\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:replicas": {}, + "f:selector": { + "f:matchLabels": { + ".": {}, + "f:app": {}, + "f:pod-template-hash": {} + } + }, + "f:template": { + "f:metadata": { + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + }, + "k:{\"name\":\"other-side-car\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":82,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + }, + "k:{\"name\":\"side-car\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":81,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + } + }, + "f:status": { + "f:fullyLabeledReplicas": {}, + "f:observedGeneration": {}, + "f:replicas": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T14:19:01.000Z" + } + ], + "name": "dice-roller-canary-7d64cd756c", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "Deployment", + "name": "dice-roller-canary", + "uid": "0b6ae80f-999b-40e9-b116-ea925f0ed07b" + } + ], + "resourceVersion": "620479", + "selfLink": "/apis/apps/v1/namespaces/default/replicasets/dice-roller-canary-7d64cd756c", + "uid": "9208395b-a9a7-4e46-b881-6a189f7fbdb0" + }, + "spec": { + "replicas": 2, + "selector": { + "matchLabels": { + "app": "dice-roller-canary", + "pod-template-hash": "7d64cd756c" + } + }, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "app": "dice-roller-canary", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "7d64cd756c" + } + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + }, + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "side-car", + "ports": [ + { + "containerPort": 81, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + }, + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "other-side-car", + "ports": [ + { + "containerPort": 82, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + } + ], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "terminationGracePeriodSeconds": 30 + } + } + }, + "status": { + "fullyLabeledReplicas": 2, + "observedGeneration": 2, + "replicas": 2 + } + }, + { + "metadata": { + "annotations": { + "deployment.kubernetes.io/desired-replicas": "2", + "deployment.kubernetes.io/max-replicas": "3", + "deployment.kubernetes.io/revision": "2" + }, + "creationTimestamp": "2020-09-25T09:25:16.000Z", + "generation": 4, + "labels": { + "app": "dice-roller-canary", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "bcb8d54dd" + }, + "managedFields": [ + { + "apiVersion": "apps/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:annotations": { + ".": {}, + "f:deployment.kubernetes.io/desired-replicas": {}, + "f:deployment.kubernetes.io/max-replicas": {}, + "f:deployment.kubernetes.io/revision": {} + }, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"0b6ae80f-999b-40e9-b116-ea925f0ed07b\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:replicas": {}, + "f:selector": { + "f:matchLabels": { + ".": {}, + "f:app": {}, + "f:pod-template-hash": {} + } + }, + "f:template": { + "f:metadata": { + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + }, + "k:{\"name\":\"side-car\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":81,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + } + }, + "f:status": { + "f:observedGeneration": {}, + "f:replicas": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T10:34:04.000Z" + } + ], + "name": "dice-roller-canary-bcb8d54dd", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "Deployment", + "name": "dice-roller-canary", + "uid": "0b6ae80f-999b-40e9-b116-ea925f0ed07b" + } + ], + "resourceVersion": "598025", + "selfLink": "/apis/apps/v1/namespaces/default/replicasets/dice-roller-canary-bcb8d54dd", + "uid": "51942585-d599-42aa-bf23-9cf1acad4006" + }, + "spec": { + "replicas": 0, + "selector": { + "matchLabels": { + "app": "dice-roller-canary", + "pod-template-hash": "bcb8d54dd" + } + }, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "app": "dice-roller-canary", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "bcb8d54dd" + } + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + }, + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "side-car", + "ports": [ + { + "containerPort": 81, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + } + ], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "terminationGracePeriodSeconds": 30 + } + } + }, + "status": { + "observedGeneration": 4, + "replicas": 0 + } + }, + { + "metadata": { + "annotations": { + "deployment.kubernetes.io/desired-replicas": "2", + "deployment.kubernetes.io/max-replicas": "3", + "deployment.kubernetes.io/revision": "1" + }, + "creationTimestamp": "2020-09-25T09:02:53.000Z", + "generation": 3, + "labels": { + "app": "dice-roller-canary", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "c866fbf67" + }, + "managedFields": [ + { + "apiVersion": "apps/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:annotations": { + ".": {}, + "f:deployment.kubernetes.io/desired-replicas": {}, + "f:deployment.kubernetes.io/max-replicas": {}, + "f:deployment.kubernetes.io/revision": {} + }, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"0b6ae80f-999b-40e9-b116-ea925f0ed07b\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:replicas": {}, + "f:selector": { + "f:matchLabels": { + ".": {}, + "f:app": {}, + "f:pod-template-hash": {} + } + }, + "f:template": { + "f:metadata": { + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + } + }, + "f:status": { + "f:observedGeneration": {}, + "f:replicas": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:25:20.000Z" + } + ], + "name": "dice-roller-canary-c866fbf67", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "Deployment", + "name": "dice-roller-canary", + "uid": "0b6ae80f-999b-40e9-b116-ea925f0ed07b" + } + ], + "resourceVersion": "588501", + "selfLink": "/apis/apps/v1/namespaces/default/replicasets/dice-roller-canary-c866fbf67", + "uid": "4d2dfe13-978f-4504-9036-ca585acdea6c" + }, + "spec": { + "replicas": 0, + "selector": { + "matchLabels": { + "app": "dice-roller-canary", + "pod-template-hash": "c866fbf67" + } + }, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "app": "dice-roller-canary", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "c866fbf67" + } + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + } + ], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "terminationGracePeriodSeconds": 30 + } + } + }, + "status": { + "observedGeneration": 3, + "replicas": 0 + } + } + ], + "deployments": [ + { + "metadata": { + "annotations": { + "deployment.kubernetes.io/revision": "2", + "kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"apps/v1\",\"kind\":\"Deployment\",\"metadata\":{\"annotations\":{},\"labels\":{\"backstage.io/kubernetes-id\":\"dice-roller\"},\"name\":\"dice-roller\",\"namespace\":\"default\"},\"spec\":{\"replicas\":10,\"selector\":{\"matchLabels\":{\"app\":\"dice-roller\"}},\"template\":{\"metadata\":{\"labels\":{\"app\":\"dice-roller\",\"backstage.io/kubernetes-id\":\"dice-roller\"}},\"spec\":{\"containers\":[{\"image\":\"nginx:1.14.2\",\"name\":\"nginx\",\"ports\":[{\"containerPort\":80}]}]}}}}\n" + }, + "creationTimestamp": "2020-09-23T12:00:55.000Z", + "generation": 3, + "labels": { + "backstage.io/kubernetes-id": "dice-roller" + }, + "managedFields": [ + { + "apiVersion": "apps/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:annotations": { + ".": {}, + "f:kubectl.kubernetes.io/last-applied-configuration": {} + }, + "f:labels": { + ".": {}, + "f:backstage.io/kubernetes-id": {} + } + }, + "f:spec": { + "f:progressDeadlineSeconds": {}, + "f:replicas": {}, + "f:revisionHistoryLimit": {}, + "f:selector": { + "f:matchLabels": { + ".": {}, + "f:app": {} + } + }, + "f:strategy": { + "f:rollingUpdate": { + ".": {}, + "f:maxSurge": {}, + "f:maxUnavailable": {} + }, + "f:type": {} + }, + "f:template": { + "f:metadata": { + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {} + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + } + } + }, + "manager": "kubectl", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "apps/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:annotations": { + "f:deployment.kubernetes.io/revision": {} + } + }, + "f:status": { + "f:availableReplicas": {}, + "f:conditions": { + ".": {}, + "k:{\"type\":\"Available\"}": { + ".": {}, + "f:lastTransitionTime": {}, + "f:lastUpdateTime": {}, + "f:message": {}, + "f:reason": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Progressing\"}": { + ".": {}, + "f:lastTransitionTime": {}, + "f:lastUpdateTime": {}, + "f:message": {}, + "f:reason": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:observedGeneration": {}, + "f:readyReplicas": {}, + "f:replicas": {}, + "f:updatedReplicas": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:55.000Z" + } + ], + "name": "dice-roller", + "namespace": "default", + "resourceVersion": "593230", + "selfLink": "/apis/apps/v1/namespaces/default/deployments/dice-roller", + "uid": "7551e949-42d1-4061-83c5-9da107186e47" + }, + "spec": { + "progressDeadlineSeconds": 600, + "replicas": 10, + "revisionHistoryLimit": 10, + "selector": { + "matchLabels": { + "app": "dice-roller" + } + }, + "strategy": { + "rollingUpdate": { + "maxSurge": "25%", + "maxUnavailable": "25%" + }, + "type": "RollingUpdate" + }, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller" + } + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + } + ], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "terminationGracePeriodSeconds": 30 + } + } + }, + "status": { + "availableReplicas": 10, + "conditions": [ + { + "lastTransitionTime": "2020-09-23T12:00:55.000Z", + "lastUpdateTime": "2020-09-24T11:39:28.000Z", + "message": "ReplicaSet \"dice-roller-6c8646bfd\" has successfully progressed.", + "reason": "NewReplicaSetAvailable", + "status": "True", + "type": "Progressing" + }, + { + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "lastUpdateTime": "2020-09-25T09:58:55.000Z", + "message": "Deployment has minimum availability.", + "reason": "MinimumReplicasAvailable", + "status": "True", + "type": "Available" + } + ], + "observedGeneration": 3, + "readyReplicas": 10, + "replicas": 10, + "updatedReplicas": 10 + } + }, + { + "metadata": { + "annotations": { + "deployment.kubernetes.io/revision": "3", + "kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"apps/v1\",\"kind\":\"Deployment\",\"metadata\":{\"annotations\":{},\"labels\":{\"backstage.io/kubernetes-id\":\"dice-roller\"},\"name\":\"dice-roller-canary\",\"namespace\":\"default\"},\"spec\":{\"replicas\":2,\"selector\":{\"matchLabels\":{\"app\":\"dice-roller-canary\"}},\"template\":{\"metadata\":{\"labels\":{\"app\":\"dice-roller-canary\",\"backstage.io/kubernetes-id\":\"dice-roller\"}},\"spec\":{\"containers\":[{\"image\":\"nginx:1.14.2\",\"name\":\"nginx\",\"ports\":[{\"containerPort\":80}]},{\"image\":\"nginx:1.14.2\",\"name\":\"side-car\",\"ports\":[{\"containerPort\":81}]},{\"image\":\"nginx:1.14.2\",\"name\":\"other-side-car\",\"ports\":[{\"containerPort\":82}]}]}}}}\n" + }, + "creationTimestamp": "2020-09-25T09:02:53.000Z", + "generation": 3, + "labels": { + "backstage.io/kubernetes-id": "dice-roller" + }, + "managedFields": [ + { + "apiVersion": "apps/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:annotations": { + ".": {}, + "f:kubectl.kubernetes.io/last-applied-configuration": {} + }, + "f:labels": { + ".": {}, + "f:backstage.io/kubernetes-id": {} + } + }, + "f:spec": { + "f:progressDeadlineSeconds": {}, + "f:replicas": {}, + "f:revisionHistoryLimit": {}, + "f:selector": { + "f:matchLabels": { + ".": {}, + "f:app": {} + } + }, + "f:strategy": { + "f:rollingUpdate": { + ".": {}, + "f:maxSurge": {}, + "f:maxUnavailable": {} + }, + "f:type": {} + }, + "f:template": { + "f:metadata": { + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {} + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + }, + "k:{\"name\":\"other-side-car\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":82,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + }, + "k:{\"name\":\"side-car\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":81,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + } + } + }, + "manager": "kubectl", + "operation": "Update", + "time": "2020-09-25T10:34:01.000Z" + }, + { + "apiVersion": "apps/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:annotations": { + "f:deployment.kubernetes.io/revision": {} + } + }, + "f:status": { + "f:conditions": { + ".": {}, + "k:{\"type\":\"Available\"}": { + ".": {}, + "f:lastTransitionTime": {}, + "f:lastUpdateTime": {}, + "f:message": {}, + "f:reason": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Progressing\"}": { + ".": {}, + "f:lastTransitionTime": {}, + "f:lastUpdateTime": {}, + "f:message": {}, + "f:reason": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:observedGeneration": {}, + "f:replicas": {}, + "f:unavailableReplicas": {}, + "f:updatedReplicas": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T14:19:04.000Z" + } + ], + "name": "dice-roller-canary", + "namespace": "default", + "resourceVersion": "620480", + "selfLink": "/apis/apps/v1/namespaces/default/deployments/dice-roller-canary", + "uid": "0b6ae80f-999b-40e9-b116-ea925f0ed07b" + }, + "spec": { + "progressDeadlineSeconds": 600, + "replicas": 2, + "revisionHistoryLimit": 10, + "selector": { + "matchLabels": { + "app": "dice-roller-canary" + } + }, + "strategy": { + "rollingUpdate": { + "maxSurge": "25%", + "maxUnavailable": "25%" + }, + "type": "RollingUpdate" + }, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "app": "dice-roller-canary", + "backstage.io/kubernetes-id": "dice-roller" + } + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + }, + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "side-car", + "ports": [ + { + "containerPort": 81, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + }, + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "other-side-car", + "ports": [ + { + "containerPort": 82, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + } + ], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "terminationGracePeriodSeconds": 30 + } + } + }, + "status": { + "conditions": [ + { + "lastTransitionTime": "2020-09-25T09:02:53.000Z", + "lastUpdateTime": "2020-09-25T10:34:04.000Z", + "message": "ReplicaSet \"dice-roller-canary-7d64cd756c\" has successfully progressed.", + "reason": "NewReplicaSetAvailable", + "status": "True", + "type": "Progressing" + }, + { + "lastTransitionTime": "2020-09-25T13:48:06.000Z", + "lastUpdateTime": "2020-09-25T13:48:06.000Z", + "message": "Deployment does not have minimum availability.", + "reason": "MinimumReplicasUnavailable", + "status": "False", + "type": "Available" + } + ], + "observedGeneration": 3, + "replicas": 2, + "unavailableReplicas": 2, + "updatedReplicas": 2 + } + } + ], + "horizontalPodAutoscalers": [ + { + "apiVersion": "autoscaling/v1", + "kind": "HorizontalPodAutoscaler", + "metadata": { + "annotations": { + "autoscaling.alpha.kubernetes.io/conditions": "[{\"type\":\"AbleToScale\",\"status\":\"True\",\"lastTransitionTime\":\"2021-01-05T10:26:04Z\",\"reason\":\"SucceededGetScale\",\"message\":\"the HPA controller was able to get the target's current scale\"},{\"type\":\"ScalingActive\",\"status\":\"False\",\"lastTransitionTime\":\"2021-01-05T10:26:04Z\",\"reason\":\"FailedGetResourceMetric\",\"message\":\"the HPA was unable to compute the replica count: unable to get metrics for resource cpu: no metrics returned from resource metrics API\"}]", + "kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"autoscaling/v1\",\"kind\":\"HorizontalPodAutoscaler\",\"metadata\":{\"annotations\":{},\"labels\":{\"backstage.io/kubernetes-id\":\"dice-roller\"},\"name\":\"dice-roller\",\"namespace\":\"default\"},\"spec\":{\"maxReplicas\":15,\"minReplicas\":10,\"scaleTargetRef\":{\"apiVersion\":\"apps/v1\",\"kind\":\"Deployment\",\"name\":\"dice-roller\"},\"targetCPUUtilizationPercentage\":50}}\n" + }, + "creationTimestamp": "2021-01-05T10:25:48Z", + "labels": { + "backstage.io/kubernetes-id": "dice-roller" + }, + "managedFields": [ + { + "apiVersion": "autoscaling/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:annotations": { + ".": {}, + "f:kubectl.kubernetes.io/last-applied-configuration": {} + }, + "f:labels": { + ".": {}, + "f:backstage.io/kubernetes-id": {} + } + }, + "f:spec": { + "f:maxReplicas": {}, + "f:minReplicas": {}, + "f:scaleTargetRef": { + "f:apiVersion": {}, + "f:kind": {}, + "f:name": {} + }, + "f:targetCPUUtilizationPercentage": {} + } + }, + "manager": "kubectl-client-side-apply", + "operation": "Update", + "time": "2021-01-05T10:25:48Z" + }, + { + "apiVersion": "autoscaling/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:annotations": { + "f:autoscaling.alpha.kubernetes.io/conditions": {} + } + }, + "f:status": { + "f:currentReplicas": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2021-01-05T10:26:04Z" + } + ], + "name": "dice-roller", + "namespace": "default", + "resourceVersion": "598", + "selfLink": "/apis/autoscaling/v1/namespaces/default/horizontalpodautoscalers/dice-roller", + "uid": "dd7c5329-567c-43c2-b159-756808d90a8e" + }, + "spec": { + "maxReplicas": 15, + "minReplicas": 10, + "scaleTargetRef": { + "apiVersion": "apps/v1", + "kind": "Deployment", + "name": "dice-roller" + }, + "targetCPUUtilizationPercentage": 50 + }, + "status": { + "currentReplicas": 10, + "desiredReplicas": 0, + "currentCPUUtilizationPercentage": 30 + } + } + ] +} diff --git a/plugins/kubernetes-react/src/__fixtures__/2-statefulsets.json b/plugins/kubernetes-react/src/__fixtures__/2-statefulsets.json new file mode 100644 index 0000000000..0a8c26c198 --- /dev/null +++ b/plugins/kubernetes-react/src/__fixtures__/2-statefulsets.json @@ -0,0 +1,4521 @@ +{ + "pods": [ + { + "metadata": { + "creationTimestamp": "2020-09-25T09:58:50.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.11\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T09:58:55.000Z" + } + ], + "name": "dice-roller-6c8646bfd-2m5hv", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "StatefulSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "593216", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-2m5hv", + "uid": "aadb71c0-36fa-43e3-b38a-162f134d4359" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://aa4489297c34c48bb33c18474a8d2b33854a82ed42155680b259f635f556ce70", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T09:58:53.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.11", + "podIPs": [ + { + "ip": "172.17.0.11" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T09:58:50.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-25T09:58:50.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.7\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T09:58:55.000Z" + } + ], + "name": "dice-roller-6c8646bfd-4v6s8", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "593221", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-4v6s8", + "uid": "32e56490-6f20-4757-991f-a0c7fb407358" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://d91cc76c41249b8d3dfcf538d180b471b2a7966aae0d17a818307c8a9b4af897", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T09:58:53.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.7", + "podIPs": [ + { + "ip": "172.17.0.7" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T09:58:50.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-24T11:39:26.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-24T11:39:26.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.6\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-24T11:39:27.000Z" + } + ], + "name": "dice-roller-6c8646bfd-b9zt5", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "503886", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-b9zt5", + "uid": "8b6601b6-469e-4e89-8fd0-abb2f1a567e4" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-24T11:39:26.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-24T11:39:27.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-24T11:39:27.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-24T11:39:26.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://c50e0d0fa96f09a2ed5df7dd5a7f7de88e6b7c7addb8f002f299d6afc52d82ce", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-24T11:39:27.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.6", + "podIPs": [ + { + "ip": "172.17.0.6" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-24T11:39:26.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-25T09:58:50.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.13\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T09:58:55.000Z" + } + ], + "name": "dice-roller-6c8646bfd-cfxqc", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "593211", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-cfxqc", + "uid": "e87e1776-0ca7-41fb-aeea-e1f648387545" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:51.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://c1641d986aae424429b7c2c1117baeb17d3794f73206bd57292cdf8264f929b2", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T09:58:53.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.13", + "podIPs": [ + { + "ip": "172.17.0.13" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T09:58:51.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-25T09:58:50.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.15\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T09:58:54.000Z" + } + ], + "name": "dice-roller-6c8646bfd-dtv5z", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "593190", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-dtv5z", + "uid": "1638a41b-e47e-4c17-a1f7-7b447df248b6" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:51.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:53.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:53.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://e62c32db58dbfe0a74b2d2cba0e0a97b7f222693c68e930037ac8738c4758ca3", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T09:58:53.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.15", + "podIPs": [ + { + "ip": "172.17.0.15" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T09:58:51.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-25T09:58:50.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.12\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T09:58:53.000Z" + } + ], + "name": "dice-roller-6c8646bfd-hhts2", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "593186", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-hhts2", + "uid": "ea0b147a-c56a-46e6-9445-7a0b1b0ed3c0" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:53.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:53.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://bcdbc153630f90556d57ff0d62f04d847ca63a5f0a7e5d9230683623d33d4b8d", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T09:58:53.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.12", + "podIPs": [ + { + "ip": "172.17.0.12" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T09:58:50.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-25T09:58:50.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.14\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T09:58:55.000Z" + } + ], + "name": "dice-roller-6c8646bfd-j68lm", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "593226", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-j68lm", + "uid": "b230ff1d-7a13-479b-9c7b-77c26bd79f62" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://30fa8a3429f86ab8e9a4cec472b79d74266609082703f48950f4aae021e9d6a2", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T09:58:53.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.14", + "podIPs": [ + { + "ip": "172.17.0.14" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T09:58:50.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-25T09:58:50.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.9\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T09:58:53.000Z" + } + ], + "name": "dice-roller-6c8646bfd-m6f9w", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "593181", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-m6f9w", + "uid": "9b0079f6-ff29-4619-bf6e-71cc10199ac5" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:53.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:53.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://f78767ee90eedffe46ff64bfe76d7f69426800dd89f3df012daf0baf3a9c5bdd", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T09:58:53.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.9", + "podIPs": [ + { + "ip": "172.17.0.9" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T09:58:50.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-24T11:39:27.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-24T11:39:27.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.4\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-24T11:39:28.000Z" + } + ], + "name": "dice-roller-6c8646bfd-nv9pk", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "503918", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-nv9pk", + "uid": "acf7f77f-78c6-4d4b-bc73-637211770ffc" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-24T11:39:27.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-24T11:39:28.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-24T11:39:28.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-24T11:39:27.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://63dec9b32942c4b09ae43d09d6978261f674a3ee623823b8f1d20da8044c12ac", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-24T11:39:28.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.4", + "podIPs": [ + { + "ip": "172.17.0.4" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-24T11:39:27.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-25T09:58:50.000Z", + "generateName": "dice-roller-6c8646bfd-", + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"5126c354-4310-4e23-a9e4-c9b87cb69792\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.10\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T09:58:55.000Z" + } + ], + "name": "dice-roller-6c8646bfd-pjhfj", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + } + ], + "resourceVersion": "593205", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-6c8646bfd-pjhfj", + "uid": "78775c3a-7af2-4ebe-a676-bc2e5dfa2bcc" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "status": "True", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T09:58:50.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://cbb83dda250db74285dcbe0b81bd0896acf402bac9710af090311f7360f824aa", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T09:58:53.000Z" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.10", + "podIPs": [ + { + "ip": "172.17.0.10" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T09:58:50.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-25T10:34:01.000Z", + "generateName": "dice-roller-canary-7d64cd756c-", + "labels": { + "app": "dice-roller-canary", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "7d64cd756c" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"9208395b-a9a7-4e46-b881-6a189f7fbdb0\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + }, + "k:{\"name\":\"other-side-car\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":82,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + }, + "k:{\"name\":\"side-car\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":81,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T10:34:01.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:message": {}, + "f:reason": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:message": {}, + "f:reason": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.16\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T14:18:54.000Z" + } + ], + "name": "dice-roller-canary-7d64cd756c-55rfq", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-canary-7d64cd756c", + "uid": "9208395b-a9a7-4e46-b881-6a189f7fbdb0" + } + ], + "resourceVersion": "620452", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-canary-7d64cd756c-55rfq", + "uid": "65ad28e3-5d51-4b4b-9bf8-4cb069803034" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + }, + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "side-car", + "ports": [ + { + "containerPort": 81, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + }, + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "other-side-car", + "ports": [ + { + "containerPort": 82, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T10:34:01.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T14:18:53.000Z", + "message": "containers with unready status: [side-car other-side-car]", + "reason": "ContainersNotReady", + "status": "False", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T14:18:53.000Z", + "message": "containers with unready status: [side-car other-side-car]", + "reason": "ContainersNotReady", + "status": "False", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T10:34:01.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://6ce15178d114a85f3d2e832de45c3355ab5b71ed5f4d4d225ee1c83bf07f69d9", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T10:34:01.000Z" + } + } + }, + { + "containerID": "docker://b3ce93d7f90bfe22558c61d2505b8473580574accdebb5fa4e51c0729c3511f4", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": { + "terminated": { + "containerID": "docker://b3ce93d7f90bfe22558c61d2505b8473580574accdebb5fa4e51c0729c3511f4", + "exitCode": 1, + "finishedAt": "2020-09-25T14:18:52.000Z", + "reason": "Error", + "startedAt": "2020-09-25T14:18:50.000Z" + } + }, + "name": "other-side-car", + "ready": false, + "restartCount": 38, + "started": false, + "state": { + "waiting": { + "message": "back-off 5m0s restarting failed container=other-side-car pod=dice-roller-canary-7d64cd756c-55rfq_default(65ad28e3-5d51-4b4b-9bf8-4cb069803034)", + "reason": "CrashLoopBackOff" + } + } + }, + { + "containerID": "docker://b7f0e65a2b8ab48c5f234616cfe8286aa96b55c3ef09c5cfbc4cdbe67a96f8cb", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": { + "terminated": { + "containerID": "docker://b7f0e65a2b8ab48c5f234616cfe8286aa96b55c3ef09c5cfbc4cdbe67a96f8cb", + "exitCode": 1, + "finishedAt": "2020-09-25T14:18:52.000Z", + "reason": "Error", + "startedAt": "2020-09-25T14:18:50.000Z" + } + }, + "name": "side-car", + "ready": false, + "restartCount": 38, + "started": false, + "state": { + "waiting": { + "message": "back-off 5m0s restarting failed container=side-car pod=dice-roller-canary-7d64cd756c-55rfq_default(65ad28e3-5d51-4b4b-9bf8-4cb069803034)", + "reason": "CrashLoopBackOff" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.16", + "podIPs": [ + { + "ip": "172.17.0.16" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T10:34:01.000Z" + } + }, + { + "metadata": { + "creationTimestamp": "2020-09-25T10:34:02.000Z", + "generateName": "dice-roller-canary-7d64cd756c-", + "labels": { + "app": "dice-roller-canary", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "7d64cd756c" + }, + "managedFields": [ + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:generateName": {}, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"9208395b-a9a7-4e46-b881-6a189f7fbdb0\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + }, + "k:{\"name\":\"other-side-car\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":82,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + }, + "k:{\"name\":\"side-car\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":81,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:enableServiceLinks": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T10:34:02.000Z" + }, + { + "apiVersion": "v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:status": { + "f:conditions": { + "k:{\"type\":\"ContainersReady\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:message": {}, + "f:reason": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Initialized\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Ready\"}": { + ".": {}, + "f:lastProbeTime": {}, + "f:lastTransitionTime": {}, + "f:message": {}, + "f:reason": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:containerStatuses": {}, + "f:hostIP": {}, + "f:phase": {}, + "f:podIP": {}, + "f:podIPs": { + ".": {}, + "k:{\"ip\":\"172.17.0.5\"}": { + ".": {}, + "f:ip": {} + } + }, + "f:startTime": {} + } + }, + "manager": "kubelet", + "operation": "Update", + "time": "2020-09-25T14:19:05.000Z" + } + ], + "name": "dice-roller-canary-7d64cd756c-vtbdx", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "ReplicaSet", + "name": "dice-roller-canary-7d64cd756c", + "uid": "9208395b-a9a7-4e46-b881-6a189f7fbdb0" + } + ], + "resourceVersion": "620481", + "selfLink": "/api/v1/namespaces/default/pods/dice-roller-canary-7d64cd756c-vtbdx", + "uid": "0b8d9d79-b43d-4339-be57-ad5c63add77e" + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + }, + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "side-car", + "ports": [ + { + "containerPort": 81, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + }, + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "other-side-car", + "ports": [ + { + "containerPort": 82, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File", + "volumeMounts": [ + { + "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", + "name": "default-token-5gctn", + "readOnly": true + } + ] + } + ], + "dnsPolicy": "ClusterFirst", + "enableServiceLinks": true, + "nodeName": "minikube", + "priority": 0, + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "serviceAccount": "default", + "serviceAccountName": "default", + "terminationGracePeriodSeconds": 30, + "tolerations": [ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 300 + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 300 + } + ], + "volumes": [ + { + "name": "default-token-5gctn", + "secret": { + "defaultMode": 420, + "secretName": "default-token-5gctn" + } + } + ] + }, + "status": { + "conditions": [ + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T10:34:02.000Z", + "status": "True", + "type": "Initialized" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T14:19:04.000Z", + "message": "containers with unready status: [side-car other-side-car]", + "reason": "ContainersNotReady", + "status": "False", + "type": "Ready" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T14:19:04.000Z", + "message": "containers with unready status: [side-car other-side-car]", + "reason": "ContainersNotReady", + "status": "False", + "type": "ContainersReady" + }, + { + "lastProbeTime": null, + "lastTransitionTime": "2020-09-25T10:34:02.000Z", + "status": "True", + "type": "PodScheduled" + } + ], + "containerStatuses": [ + { + "containerID": "docker://3f9cadc6f135247eb2df9aaca8f25ea05dcf42be86d58fb833c8acf192da0d66", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": {}, + "name": "nginx", + "ready": true, + "restartCount": 0, + "started": true, + "state": { + "running": { + "startedAt": "2020-09-25T10:34:03.000Z" + } + } + }, + { + "containerID": "docker://5e3a9f9129e5ce74fea249c013afcc056ee95a940fed24495ef9b58df67771f3", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": { + "terminated": { + "containerID": "docker://5e3a9f9129e5ce74fea249c013afcc056ee95a940fed24495ef9b58df67771f3", + "exitCode": 1, + "finishedAt": "2020-09-25T14:19:03.000Z", + "reason": "Error", + "startedAt": "2020-09-25T14:19:01.000Z" + } + }, + "name": "other-side-car", + "ready": false, + "restartCount": 38, + "started": false, + "state": { + "waiting": { + "message": "back-off 5m0s restarting failed container=other-side-car pod=dice-roller-canary-7d64cd756c-vtbdx_default(0b8d9d79-b43d-4339-be57-ad5c63add77e)", + "reason": "CrashLoopBackOff" + } + } + }, + { + "containerID": "docker://21b42cae298c0ed7f90373974d8c88b0941d17733f35398144a17ece32e03210", + "image": "nginx:1.14.2", + "imageID": "docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d", + "lastState": { + "terminated": { + "containerID": "docker://21b42cae298c0ed7f90373974d8c88b0941d17733f35398144a17ece32e03210", + "exitCode": 1, + "finishedAt": "2020-09-25T14:19:03.000Z", + "reason": "Error", + "startedAt": "2020-09-25T14:19:01.000Z" + } + }, + "name": "side-car", + "ready": false, + "restartCount": 38, + "started": false, + "state": { + "waiting": { + "message": "back-off 5m0s restarting failed container=side-car pod=dice-roller-canary-7d64cd756c-vtbdx_default(0b8d9d79-b43d-4339-be57-ad5c63add77e)", + "reason": "CrashLoopBackOff" + } + } + } + ], + "hostIP": "192.168.64.2", + "phase": "Running", + "podIP": "172.17.0.5", + "podIPs": [ + { + "ip": "172.17.0.5" + } + ], + "qosClass": "BestEffort", + "startTime": "2020-09-25T10:34:02.000Z" + } + } + ], + "replicaSets": [ + { + "metadata": { + "annotations": { + "deployment.kubernetes.io/desired-replicas": "10", + "deployment.kubernetes.io/max-replicas": "13", + "deployment.kubernetes.io/revision": "2" + }, + "creationTimestamp": "2020-09-24T11:39:26.000Z", + "generation": 3, + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + }, + "managedFields": [ + { + "apiVersion": "apps/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:annotations": { + ".": {}, + "f:deployment.kubernetes.io/desired-replicas": {}, + "f:deployment.kubernetes.io/max-replicas": {}, + "f:deployment.kubernetes.io/revision": {} + }, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"7551e949-42d1-4061-83c5-9da107186e47\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:replicas": {}, + "f:selector": { + "f:matchLabels": { + ".": {}, + "f:app": {}, + "f:pod-template-hash": {} + } + }, + "f:template": { + "f:metadata": { + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + } + }, + "f:status": { + "f:availableReplicas": {}, + "f:fullyLabeledReplicas": {}, + "f:observedGeneration": {}, + "f:readyReplicas": {}, + "f:replicas": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:55.000Z" + } + ], + "name": "dice-roller-6c8646bfd", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "Deployment", + "name": "dice-roller", + "uid": "7551e949-42d1-4061-83c5-9da107186e47" + } + ], + "resourceVersion": "593228", + "selfLink": "/apis/apps/v1/namespaces/default/replicasets/dice-roller-6c8646bfd", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + }, + "spec": { + "replicas": 10, + "selector": { + "matchLabels": { + "app": "dice-roller", + "pod-template-hash": "6c8646bfd" + } + }, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "6c8646bfd" + } + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + } + ], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "terminationGracePeriodSeconds": 30 + } + } + }, + "status": { + "availableReplicas": 10, + "fullyLabeledReplicas": 10, + "observedGeneration": 3, + "readyReplicas": 10, + "replicas": 10 + } + }, + { + "metadata": { + "annotations": { + "deployment.kubernetes.io/desired-replicas": "2", + "deployment.kubernetes.io/max-replicas": "3", + "deployment.kubernetes.io/revision": "3" + }, + "creationTimestamp": "2020-09-25T10:34:01.000Z", + "generation": 2, + "labels": { + "app": "dice-roller-canary", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "7d64cd756c" + }, + "managedFields": [ + { + "apiVersion": "apps/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:annotations": { + ".": {}, + "f:deployment.kubernetes.io/desired-replicas": {}, + "f:deployment.kubernetes.io/max-replicas": {}, + "f:deployment.kubernetes.io/revision": {} + }, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"0b6ae80f-999b-40e9-b116-ea925f0ed07b\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:replicas": {}, + "f:selector": { + "f:matchLabels": { + ".": {}, + "f:app": {}, + "f:pod-template-hash": {} + } + }, + "f:template": { + "f:metadata": { + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + }, + "k:{\"name\":\"other-side-car\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":82,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + }, + "k:{\"name\":\"side-car\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":81,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + } + }, + "f:status": { + "f:fullyLabeledReplicas": {}, + "f:observedGeneration": {}, + "f:replicas": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T14:19:01.000Z" + } + ], + "name": "dice-roller-canary-7d64cd756c", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "Deployment", + "name": "dice-roller-canary", + "uid": "0b6ae80f-999b-40e9-b116-ea925f0ed07b" + } + ], + "resourceVersion": "620479", + "selfLink": "/apis/apps/v1/namespaces/default/replicasets/dice-roller-canary-7d64cd756c", + "uid": "9208395b-a9a7-4e46-b881-6a189f7fbdb0" + }, + "spec": { + "replicas": 2, + "selector": { + "matchLabels": { + "app": "dice-roller-canary", + "pod-template-hash": "7d64cd756c" + } + }, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "app": "dice-roller-canary", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "7d64cd756c" + } + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + }, + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "side-car", + "ports": [ + { + "containerPort": 81, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + }, + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "other-side-car", + "ports": [ + { + "containerPort": 82, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + } + ], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "terminationGracePeriodSeconds": 30 + } + } + }, + "status": { + "fullyLabeledReplicas": 2, + "observedGeneration": 2, + "replicas": 2 + } + }, + { + "metadata": { + "annotations": { + "deployment.kubernetes.io/desired-replicas": "2", + "deployment.kubernetes.io/max-replicas": "3", + "deployment.kubernetes.io/revision": "2" + }, + "creationTimestamp": "2020-09-25T09:25:16.000Z", + "generation": 4, + "labels": { + "app": "dice-roller-canary", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "bcb8d54dd" + }, + "managedFields": [ + { + "apiVersion": "apps/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:annotations": { + ".": {}, + "f:deployment.kubernetes.io/desired-replicas": {}, + "f:deployment.kubernetes.io/max-replicas": {}, + "f:deployment.kubernetes.io/revision": {} + }, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"0b6ae80f-999b-40e9-b116-ea925f0ed07b\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:replicas": {}, + "f:selector": { + "f:matchLabels": { + ".": {}, + "f:app": {}, + "f:pod-template-hash": {} + } + }, + "f:template": { + "f:metadata": { + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + }, + "k:{\"name\":\"side-car\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":81,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + } + }, + "f:status": { + "f:observedGeneration": {}, + "f:replicas": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T10:34:04.000Z" + } + ], + "name": "dice-roller-canary-bcb8d54dd", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "Deployment", + "name": "dice-roller-canary", + "uid": "0b6ae80f-999b-40e9-b116-ea925f0ed07b" + } + ], + "resourceVersion": "598025", + "selfLink": "/apis/apps/v1/namespaces/default/replicasets/dice-roller-canary-bcb8d54dd", + "uid": "51942585-d599-42aa-bf23-9cf1acad4006" + }, + "spec": { + "replicas": 0, + "selector": { + "matchLabels": { + "app": "dice-roller-canary", + "pod-template-hash": "bcb8d54dd" + } + }, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "app": "dice-roller-canary", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "bcb8d54dd" + } + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + }, + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "side-car", + "ports": [ + { + "containerPort": 81, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + } + ], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "terminationGracePeriodSeconds": 30 + } + } + }, + "status": { + "observedGeneration": 4, + "replicas": 0 + } + }, + { + "metadata": { + "annotations": { + "deployment.kubernetes.io/desired-replicas": "2", + "deployment.kubernetes.io/max-replicas": "3", + "deployment.kubernetes.io/revision": "1" + }, + "creationTimestamp": "2020-09-25T09:02:53.000Z", + "generation": 3, + "labels": { + "app": "dice-roller-canary", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "c866fbf67" + }, + "managedFields": [ + { + "apiVersion": "apps/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:annotations": { + ".": {}, + "f:deployment.kubernetes.io/desired-replicas": {}, + "f:deployment.kubernetes.io/max-replicas": {}, + "f:deployment.kubernetes.io/revision": {} + }, + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"0b6ae80f-999b-40e9-b116-ea925f0ed07b\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:spec": { + "f:replicas": {}, + "f:selector": { + "f:matchLabels": { + ".": {}, + "f:app": {}, + "f:pod-template-hash": {} + } + }, + "f:template": { + "f:metadata": { + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {}, + "f:pod-template-hash": {} + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + } + }, + "f:status": { + "f:observedGeneration": {}, + "f:replicas": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:25:20.000Z" + } + ], + "name": "dice-roller-canary-c866fbf67", + "namespace": "default", + "ownerReferences": [ + { + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "Deployment", + "name": "dice-roller-canary", + "uid": "0b6ae80f-999b-40e9-b116-ea925f0ed07b" + } + ], + "resourceVersion": "588501", + "selfLink": "/apis/apps/v1/namespaces/default/replicasets/dice-roller-canary-c866fbf67", + "uid": "4d2dfe13-978f-4504-9036-ca585acdea6c" + }, + "spec": { + "replicas": 0, + "selector": { + "matchLabels": { + "app": "dice-roller-canary", + "pod-template-hash": "c866fbf67" + } + }, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "app": "dice-roller-canary", + "backstage.io/kubernetes-id": "dice-roller", + "pod-template-hash": "c866fbf67" + } + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + } + ], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "terminationGracePeriodSeconds": 30 + } + } + }, + "status": { + "observedGeneration": 3, + "replicas": 0 + } + } + ], + "statefulsets": [ + { + "metadata": { + "annotations": { + "deployment.kubernetes.io/revision": "2", + "kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"apps/v1\",\"kind\":\"StatefulSet\",\"metadata\":{\"annotations\":{},\"labels\":{\"backstage.io/kubernetes-id\":\"dice-roller\"},\"name\":\"dice-roller\",\"namespace\":\"default\"},\"spec\":{\"replicas\":10,\"selector\":{\"matchLabels\":{\"app\":\"dice-roller\"}},\"template\":{\"metadata\":{\"labels\":{\"app\":\"dice-roller\",\"backstage.io/kubernetes-id\":\"dice-roller\"}},\"spec\":{\"containers\":[{\"image\":\"nginx:1.14.2\",\"name\":\"nginx\",\"ports\":[{\"containerPort\":80}]}]}}}}\n" + }, + "creationTimestamp": "2020-09-23T12:00:55.000Z", + "generation": 3, + "labels": { + "backstage.io/kubernetes-id": "dice-roller" + }, + "managedFields": [ + { + "apiVersion": "apps/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:annotations": { + ".": {}, + "f:kubectl.kubernetes.io/last-applied-configuration": {} + }, + "f:labels": { + ".": {}, + "f:backstage.io/kubernetes-id": {} + } + }, + "f:spec": { + "f:progressDeadlineSeconds": {}, + "f:replicas": {}, + "f:revisionHistoryLimit": {}, + "f:selector": { + "f:matchLabels": { + ".": {}, + "f:app": {} + } + }, + "f:strategy": { + "f:rollingUpdate": { + ".": {}, + "f:maxSurge": {}, + "f:maxUnavailable": {} + }, + "f:type": {} + }, + "f:template": { + "f:metadata": { + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {} + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + } + } + }, + "manager": "kubectl", + "operation": "Update", + "time": "2020-09-25T09:58:50.000Z" + }, + { + "apiVersion": "apps/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:annotations": { + "f:deployment.kubernetes.io/revision": {} + } + }, + "f:status": { + "f:availableReplicas": {}, + "f:conditions": { + ".": {}, + "k:{\"type\":\"Available\"}": { + ".": {}, + "f:lastTransitionTime": {}, + "f:lastUpdateTime": {}, + "f:message": {}, + "f:reason": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Progressing\"}": { + ".": {}, + "f:lastTransitionTime": {}, + "f:lastUpdateTime": {}, + "f:message": {}, + "f:reason": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:observedGeneration": {}, + "f:readyReplicas": {}, + "f:replicas": {}, + "f:updatedReplicas": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T09:58:55.000Z" + } + ], + "name": "dice-roller", + "namespace": "default", + "resourceVersion": "593230", + "selfLink": "/apis/apps/v1/namespaces/default/statefulsets/dice-roller", + "uid": "5126c354-4310-4e23-a9e4-c9b87cb69792" + }, + "spec": { + "replicas": 10, + "revisionHistoryLimit": 10, + "selector": { + "matchLabels": { + "app": "dice-roller" + } + }, + "updateStrategy": { + "rollingUpdate": { + "maxSurge": "25%", + "maxUnavailable": "25%" + }, + "type": "RollingUpdate" + }, + "podManagementPolicy": "Parallel", + "serviceName": "dice-roller", + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "app": "dice-roller", + "backstage.io/kubernetes-id": "dice-roller" + } + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + } + ], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "terminationGracePeriodSeconds": 30 + } + } + }, + "status": { + "availableReplicas": 10, + "conditions": [ + { + "lastTransitionTime": "2020-09-23T12:00:55.000Z", + "lastUpdateTime": "2020-09-24T11:39:28.000Z", + "message": "ReplicaSet \"dice-roller-6c8646bfd\" has successfully progressed.", + "reason": "NewReplicaSetAvailable", + "status": "True", + "type": "Progressing" + }, + { + "lastTransitionTime": "2020-09-25T09:58:55.000Z", + "lastUpdateTime": "2020-09-25T09:58:55.000Z", + "message": "Deployment has minimum availability.", + "reason": "MinimumReplicasAvailable", + "status": "True", + "type": "Available" + } + ], + "observedGeneration": 3, + "readyReplicas": 10, + "replicas": 10, + "updatedReplicas": 10 + } + }, + { + "metadata": { + "annotations": { + "deployment.kubernetes.io/revision": "3", + "kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"apps/v1\",\"kind\":\"StatefulSet\",\"metadata\":{\"annotations\":{},\"labels\":{\"backstage.io/kubernetes-id\":\"dice-roller\"},\"name\":\"dice-roller-canary\",\"namespace\":\"default\"},\"spec\":{\"replicas\":2,\"selector\":{\"matchLabels\":{\"app\":\"dice-roller-canary\"}},\"template\":{\"metadata\":{\"labels\":{\"app\":\"dice-roller-canary\",\"backstage.io/kubernetes-id\":\"dice-roller\"}},\"spec\":{\"containers\":[{\"image\":\"nginx:1.14.2\",\"name\":\"nginx\",\"ports\":[{\"containerPort\":80}]},{\"image\":\"nginx:1.14.2\",\"name\":\"side-car\",\"ports\":[{\"containerPort\":81}]},{\"image\":\"nginx:1.14.2\",\"name\":\"other-side-car\",\"ports\":[{\"containerPort\":82}]}]}}}}\n" + }, + "creationTimestamp": "2020-09-25T09:02:53.000Z", + "generation": 3, + "labels": { + "backstage.io/kubernetes-id": "dice-roller" + }, + "managedFields": [ + { + "apiVersion": "apps/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:annotations": { + ".": {}, + "f:kubectl.kubernetes.io/last-applied-configuration": {} + }, + "f:labels": { + ".": {}, + "f:backstage.io/kubernetes-id": {} + } + }, + "f:spec": { + "f:progressDeadlineSeconds": {}, + "f:replicas": {}, + "f:revisionHistoryLimit": {}, + "f:selector": { + "f:matchLabels": { + ".": {}, + "f:app": {} + } + }, + "f:strategy": { + "f:rollingUpdate": { + ".": {}, + "f:maxSurge": {}, + "f:maxUnavailable": {} + }, + "f:type": {} + }, + "f:template": { + "f:metadata": { + "f:labels": { + ".": {}, + "f:app": {}, + "f:backstage.io/kubernetes-id": {} + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"nginx\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":80,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + }, + "k:{\"name\":\"other-side-car\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":82,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + }, + "k:{\"name\":\"side-car\"}": { + ".": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:ports": { + ".": {}, + "k:{\"containerPort\":81,\"protocol\":\"TCP\"}": { + ".": {}, + "f:containerPort": {}, + "f:protocol": {} + } + }, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + } + } + }, + "manager": "kubectl", + "operation": "Update", + "time": "2020-09-25T10:34:01.000Z" + }, + { + "apiVersion": "apps/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:annotations": { + "f:deployment.kubernetes.io/revision": {} + } + }, + "f:status": { + "f:conditions": { + ".": {}, + "k:{\"type\":\"Available\"}": { + ".": {}, + "f:lastTransitionTime": {}, + "f:lastUpdateTime": {}, + "f:message": {}, + "f:reason": {}, + "f:status": {}, + "f:type": {} + }, + "k:{\"type\":\"Progressing\"}": { + ".": {}, + "f:lastTransitionTime": {}, + "f:lastUpdateTime": {}, + "f:message": {}, + "f:reason": {}, + "f:status": {}, + "f:type": {} + } + }, + "f:observedGeneration": {}, + "f:replicas": {}, + "f:unavailableReplicas": {}, + "f:updatedReplicas": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2020-09-25T14:19:04.000Z" + } + ], + "name": "dice-roller-canary", + "namespace": "default", + "resourceVersion": "620480", + "selfLink": "/apis/apps/v1/namespaces/default/statefulsets/dice-roller-canary", + "uid": "9208395b-a9a7-4e46-b881-6a189f7fbdb0" + }, + "spec": { + "replicas": 2, + "revisionHistoryLimit": 10, + "selector": { + "matchLabels": { + "app": "dice-roller-canary" + } + }, + "updateStrategy": { + "rollingUpdate": { + "maxSurge": "25%", + "maxUnavailable": "25%" + }, + "type": "RollingUpdate" + }, + "podManagementPolicy": "Parallel", + "serviceName": "dice-roller", + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "app": "dice-roller-canary", + "backstage.io/kubernetes-id": "dice-roller" + } + }, + "spec": { + "containers": [ + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "nginx", + "ports": [ + { + "containerPort": 80, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + }, + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "side-car", + "ports": [ + { + "containerPort": 81, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + }, + { + "image": "nginx:1.14.2", + "imagePullPolicy": "IfNotPresent", + "name": "other-side-car", + "ports": [ + { + "containerPort": 82, + "protocol": "TCP" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + } + ], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "terminationGracePeriodSeconds": 30 + } + } + }, + "status": { + "conditions": [ + { + "lastTransitionTime": "2020-09-25T09:02:53.000Z", + "lastUpdateTime": "2020-09-25T10:34:04.000Z", + "message": "ReplicaSet \"dice-roller-canary-7d64cd756c\" has successfully progressed.", + "reason": "NewReplicaSetAvailable", + "status": "True", + "type": "Progressing" + }, + { + "lastTransitionTime": "2020-09-25T13:48:06.000Z", + "lastUpdateTime": "2020-09-25T13:48:06.000Z", + "message": "Deployment does not have minimum availability.", + "reason": "MinimumReplicasUnavailable", + "status": "False", + "type": "Available" + } + ], + "observedGeneration": 3, + "replicas": 2, + "unavailableReplicas": 2, + "updatedReplicas": 2 + } + } + ], + "horizontalPodAutoscalers": [ + { + "apiVersion": "autoscaling/v1", + "kind": "HorizontalPodAutoscaler", + "metadata": { + "annotations": { + "autoscaling.alpha.kubernetes.io/conditions": "[{\"type\":\"AbleToScale\",\"status\":\"True\",\"lastTransitionTime\":\"2021-01-05T10:26:04Z\",\"reason\":\"SucceededGetScale\",\"message\":\"the HPA controller was able to get the target's current scale\"},{\"type\":\"ScalingActive\",\"status\":\"False\",\"lastTransitionTime\":\"2021-01-05T10:26:04Z\",\"reason\":\"FailedGetResourceMetric\",\"message\":\"the HPA was unable to compute the replica count: unable to get metrics for resource cpu: no metrics returned from resource metrics API\"}]", + "kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"autoscaling/v1\",\"kind\":\"HorizontalPodAutoscaler\",\"metadata\":{\"annotations\":{},\"labels\":{\"backstage.io/kubernetes-id\":\"dice-roller\"},\"name\":\"dice-roller\",\"namespace\":\"default\"},\"spec\":{\"maxReplicas\":15,\"minReplicas\":10,\"scaleTargetRef\":{\"apiVersion\":\"apps/v1\",\"kind\":\"Deployment\",\"name\":\"dice-roller\"},\"targetCPUUtilizationPercentage\":50}}\n" + }, + "creationTimestamp": "2021-01-05T10:25:48Z", + "labels": { + "backstage.io/kubernetes-id": "dice-roller" + }, + "managedFields": [ + { + "apiVersion": "autoscaling/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:annotations": { + ".": {}, + "f:kubectl.kubernetes.io/last-applied-configuration": {} + }, + "f:labels": { + ".": {}, + "f:backstage.io/kubernetes-id": {} + } + }, + "f:spec": { + "f:maxReplicas": {}, + "f:minReplicas": {}, + "f:scaleTargetRef": { + "f:apiVersion": {}, + "f:kind": {}, + "f:name": {} + }, + "f:targetCPUUtilizationPercentage": {} + } + }, + "manager": "kubectl-client-side-apply", + "operation": "Update", + "time": "2021-01-05T10:25:48Z" + }, + { + "apiVersion": "autoscaling/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:annotations": { + "f:autoscaling.alpha.kubernetes.io/conditions": {} + } + }, + "f:status": { + "f:currentReplicas": {} + } + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2021-01-05T10:26:04Z" + } + ], + "name": "dice-roller", + "namespace": "default", + "resourceVersion": "598", + "selfLink": "/apis/autoscaling/v1/namespaces/default/horizontalpodautoscalers/dice-roller", + "uid": "dd7c5329-567c-43c2-b159-756808d90a8e" + }, + "spec": { + "maxReplicas": 15, + "minReplicas": 10, + "scaleTargetRef": { + "apiVersion": "apps/v1", + "kind": "Deployment", + "name": "dice-roller" + }, + "targetCPUUtilizationPercentage": 50 + }, + "status": { + "currentReplicas": 10, + "desiredReplicas": 0, + "currentCPUUtilizationPercentage": 30 + } + } + ] +} diff --git a/plugins/kubernetes/src/api/KubernetesBackendClient.test.ts b/plugins/kubernetes-react/src/api/KubernetesBackendClient.test.ts similarity index 89% rename from plugins/kubernetes/src/api/KubernetesBackendClient.test.ts rename to plugins/kubernetes-react/src/api/KubernetesBackendClient.test.ts index 7d2ef36602..fd999ab335 100644 --- a/plugins/kubernetes/src/api/KubernetesBackendClient.test.ts +++ b/plugins/kubernetes-react/src/api/KubernetesBackendClient.test.ts @@ -398,9 +398,26 @@ describe('KubernetesBackendClient', () => { identityApi.getCredentials.mockResolvedValue({ token: 'idToken' }); }); - it('hits the /proxy API', async () => { + it('hits the /proxy API with oidc as protocol and okta as auth provider', async () => { + worker.use( + rest.get( + 'http://localhost:1234/api/kubernetes/clusters', + (_, res, ctx) => + res( + ctx.json({ + items: [ + { + name: 'cluster-a', + authProvider: 'oidc', + oidcTokenProvider: 'okta', + }, + ], + }), + ), + ), + ); kubernetesAuthProvidersApi.getCredentials.mockResolvedValue({ - token: 'k8-token', + token: 'k8-token3', }); const nsResponse = { kind: 'Namespace', @@ -414,8 +431,56 @@ describe('KubernetesBackendClient', () => { 'http://localhost:1234/api/kubernetes/proxy/api/v1/namespaces', (req, res, ctx) => res( - req.headers.get('Backstage-Kubernetes-Authorization') === - 'Bearer k8-token' + req.headers.get( + 'Backstage-Kubernetes-Authorization-oidc-okta', + ) === 'k8-token3' + ? ctx.json(nsResponse) + : ctx.status(403), + ), + ), + ); + + const request = { + clusterName: 'cluster-a', + path: '/api/v1/namespaces', + }; + + const response = await backendClient.proxy(request); + + await expect(response.json()).resolves.toStrictEqual(nsResponse); + }); + + it('hits the /proxy API with serviceAccount as auth provider', async () => { + worker.use( + rest.get( + 'http://localhost:1234/api/kubernetes/clusters', + (_, res, ctx) => + res( + ctx.json({ + items: [ + { + name: 'cluster-a', + authProvider: 'serviceAccount', + }, + ], + }), + ), + ), + ); + + const nsResponse = { + kind: 'Namespace', + apiVersion: 'v1', + metadata: { + name: 'new-ns', + }, + }; + worker.use( + rest.get( + 'http://localhost:1234/api/kubernetes/proxy/api/v1/namespaces', + (req, res, ctx) => + res( + req.headers.get('Authorization') === 'Bearer idToken' ? ctx.json(nsResponse) : ctx.status(403), ), @@ -450,8 +515,8 @@ describe('KubernetesBackendClient', () => { 'http://localhost:1234/api/kubernetes/proxy/api/v1/namespaces', (req, res, ctx) => res( - req.headers.get('Backstage-Kubernetes-Authorization') === - 'Bearer k8-token' + req.headers.get('Backstage-Kubernetes-Authorization-aws') === + 'k8-token' ? ctx.json(nsResponse) : ctx.status(403), ), diff --git a/plugins/kubernetes/src/api/KubernetesBackendClient.ts b/plugins/kubernetes-react/src/api/KubernetesBackendClient.ts similarity index 78% rename from plugins/kubernetes/src/api/KubernetesBackendClient.ts rename to plugins/kubernetes-react/src/api/KubernetesBackendClient.ts index 681daa0ac0..a769eb088d 100644 --- a/plugins/kubernetes/src/api/KubernetesBackendClient.ts +++ b/plugins/kubernetes-react/src/api/KubernetesBackendClient.ts @@ -26,6 +26,7 @@ import { stringifyEntityRef } from '@backstage/catalog-model'; import { KubernetesAuthProvidersApi } from '../kubernetes-auth-provider'; import { NotFoundError } from '@backstage/errors'; +/** @public */ export class KubernetesBackendClient implements KubernetesApi { private readonly discoveryApi: DiscoveryApi; private readonly identityApi: IdentityApi; @@ -74,9 +75,11 @@ export class KubernetesBackendClient implements KubernetesApi { return this.handleResponse(response); } - private async getCluster( - clusterName: string, - ): Promise<{ name: string; authProvider: string }> { + public async getCluster(clusterName: string): Promise<{ + name: string; + authProvider: string; + oidcTokenProvider?: string; + }> { const cluster = await this.getClusters().then(clusters => clusters.find(c => c.name === clusterName), ); @@ -139,23 +142,62 @@ export class KubernetesBackendClient implements KubernetesApi { path: string; init?: RequestInit; }): Promise<Response> { - const { authProvider } = await this.getCluster(options.clusterName); - const { token: k8sToken } = await this.getCredentials(authProvider); + const { authProvider, oidcTokenProvider } = await this.getCluster( + options.clusterName, + ); + const kubernetesCredentials = await this.getCredentials(authProvider); const url = `${await this.discoveryApi.getBaseUrl('kubernetes')}/proxy${ options.path }`; const identityResponse = await this.identityApi.getCredentials(); - const headers = { + const headers = KubernetesBackendClient.getKubernetesHeaders( + options, + kubernetesCredentials?.token, + identityResponse, + authProvider, + oidcTokenProvider, + ); + return await fetch(url, { ...options.init, headers }); + } + + private static getKubernetesHeaders( + options: { + clusterName: string; + path: string; + init?: RequestInit; + }, + k8sToken: string | undefined, + identityResponse: { token?: string }, + authProvider: string, + oidcTokenProvider: string | undefined, + ) { + const kubernetesAuthHeader = + KubernetesBackendClient.getKubernetesAuthHeaderByAuthProvider( + authProvider, + oidcTokenProvider, + ); + return { ...options.init?.headers, [`Backstage-Kubernetes-Cluster`]: options.clusterName, ...(k8sToken && { - [`Backstage-Kubernetes-Authorization`]: `Bearer ${k8sToken}`, + [kubernetesAuthHeader]: k8sToken, }), ...(identityResponse.token && { Authorization: `Bearer ${identityResponse.token}`, }), }; + } - return await fetch(url, { ...options.init, headers }); + private static getKubernetesAuthHeaderByAuthProvider( + authProvider: string, + oidcTokenProvider: string | undefined, + ): string { + let header: string = 'Backstage-Kubernetes-Authorization'; + + header = header.concat('-', authProvider); + + if (oidcTokenProvider) header = header.concat('-', oidcTokenProvider); + + return header; } } diff --git a/plugins/kubernetes/src/api/KubernetesProxyClient.test.ts b/plugins/kubernetes-react/src/api/KubernetesProxyClient.test.ts similarity index 100% rename from plugins/kubernetes/src/api/KubernetesProxyClient.test.ts rename to plugins/kubernetes-react/src/api/KubernetesProxyClient.test.ts diff --git a/plugins/kubernetes/src/api/KubernetesProxyClient.ts b/plugins/kubernetes-react/src/api/KubernetesProxyClient.ts similarity index 100% rename from plugins/kubernetes/src/api/KubernetesProxyClient.ts rename to plugins/kubernetes-react/src/api/KubernetesProxyClient.ts diff --git a/plugins/kubernetes/src/api/index.ts b/plugins/kubernetes-react/src/api/index.ts similarity index 100% rename from plugins/kubernetes/src/api/index.ts rename to plugins/kubernetes-react/src/api/index.ts diff --git a/plugins/kubernetes/src/api/types.ts b/plugins/kubernetes-react/src/api/types.ts similarity index 87% rename from plugins/kubernetes/src/api/types.ts rename to plugins/kubernetes-react/src/api/types.ts index 6065e47169..28cf2dde55 100644 --- a/plugins/kubernetes/src/api/types.ts +++ b/plugins/kubernetes-react/src/api/types.ts @@ -23,14 +23,17 @@ import { import { createApiRef } from '@backstage/core-plugin-api'; import { Event } from 'kubernetes-models/v1'; +/** @public */ export const kubernetesApiRef = createApiRef<KubernetesApi>({ id: 'plugin.kubernetes.service', }); +/** @public */ export const kubernetesProxyApiRef = createApiRef<KubernetesProxyApi>({ id: 'plugin.kubernetes.proxy-service', }); +/** @public */ export interface KubernetesApi { getObjectsByEntity( requestBody: KubernetesRequestBody, @@ -39,9 +42,18 @@ export interface KubernetesApi { { name: string; authProvider: string; - oidcTokenProvider?: string | undefined; + oidcTokenProvider?: string; }[] >; + getCluster(clusterName: string): Promise< + | { + name: string; + authProvider: string; + oidcTokenProvider?: string; + dashboardUrl?: string; + } + | undefined + >; getWorkloadsByEntity( request: WorkloadsByEntityRequest, ): Promise<ObjectsByEntityResponse>; @@ -55,6 +67,7 @@ export interface KubernetesApi { }): Promise<Response>; } +/** @public */ export interface KubernetesProxyApi { getPodLogs(request: { podName: string; diff --git a/plugins/kubernetes/src/components/Cluster/Cluster.test.tsx b/plugins/kubernetes-react/src/components/Cluster/Cluster.test.tsx similarity index 100% rename from plugins/kubernetes/src/components/Cluster/Cluster.test.tsx rename to plugins/kubernetes-react/src/components/Cluster/Cluster.test.tsx diff --git a/plugins/kubernetes/src/components/Cluster/Cluster.tsx b/plugins/kubernetes-react/src/components/Cluster/Cluster.tsx similarity index 96% rename from plugins/kubernetes/src/components/Cluster/Cluster.tsx rename to plugins/kubernetes-react/src/components/Cluster/Cluster.tsx index bea7a46d37..42f1aca3a0 100644 --- a/plugins/kubernetes/src/components/Cluster/Cluster.tsx +++ b/plugins/kubernetes-react/src/components/Cluster/Cluster.tsx @@ -25,11 +25,11 @@ import { import { ClientPodStatus, ClusterObjects, + groupResponses, } from '@backstage/plugin-kubernetes-common'; import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import { DeploymentsAccordions } from '../DeploymentsAccordions'; import { StatefulSetsAccordions } from '../StatefulSetsAccordions'; -import { groupResponses } from '../../utils/response'; import { IngressesAccordions } from '../IngressesAccordions'; import { ServicesAccordions } from '../ServicesAccordions'; import { CronJobsAccordions } from '../CronJobsAccordions'; @@ -103,12 +103,22 @@ const ClusterSummary = ({ ); }; -type ClusterProps = { +/** + * Props for Cluster + * + * @public + */ +export type ClusterProps = { clusterObjects: ClusterObjects; podsWithErrors: Set<string>; children?: React.ReactNode; }; +/** + * Component for rendering Kubernetes resources in a cluster + * + * @public + */ export const Cluster = ({ clusterObjects, podsWithErrors }: ClusterProps) => { const groupedResponses = groupResponses(clusterObjects.resources); diff --git a/plugins/kubernetes/src/components/ErrorPanel/index.ts b/plugins/kubernetes-react/src/components/Cluster/index.ts similarity index 93% rename from plugins/kubernetes/src/components/ErrorPanel/index.ts rename to plugins/kubernetes-react/src/components/Cluster/index.ts index 2d3778e2c2..eac1e358b6 100644 --- a/plugins/kubernetes/src/components/ErrorPanel/index.ts +++ b/plugins/kubernetes-react/src/components/Cluster/index.ts @@ -13,4 +13,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export { ErrorPanel } from './ErrorPanel'; +export * from './Cluster'; diff --git a/plugins/kubernetes/src/components/CronJobsAccordions/CronJobsAccordions.test.tsx b/plugins/kubernetes-react/src/components/CronJobsAccordions/CronJobsAccordions.test.tsx similarity index 100% rename from plugins/kubernetes/src/components/CronJobsAccordions/CronJobsAccordions.test.tsx rename to plugins/kubernetes-react/src/components/CronJobsAccordions/CronJobsAccordions.test.tsx diff --git a/plugins/kubernetes/src/components/CronJobsAccordions/CronJobsAccordions.tsx b/plugins/kubernetes-react/src/components/CronJobsAccordions/CronJobsAccordions.tsx similarity index 97% rename from plugins/kubernetes/src/components/CronJobsAccordions/CronJobsAccordions.tsx rename to plugins/kubernetes-react/src/components/CronJobsAccordions/CronJobsAccordions.tsx index c5babe67fc..e724c14fdf 100644 --- a/plugins/kubernetes/src/components/CronJobsAccordions/CronJobsAccordions.tsx +++ b/plugins/kubernetes-react/src/components/CronJobsAccordions/CronJobsAccordions.tsx @@ -30,7 +30,12 @@ import { GroupedResponsesContext } from '../../hooks'; import { StatusError, StatusOK } from '@backstage/core-components'; import { humanizeCron } from '../../utils/crons'; -type CronJobsAccordionsProps = { +/** + * + * + * @public + */ +export type CronJobsAccordionsProps = { children?: React.ReactNode; }; @@ -101,6 +106,11 @@ const CronJobAccordion = ({ cronJob, ownedJobs }: CronJobAccordionProps) => { ); }; +/** + * + * + * @public + */ export const CronJobsAccordions = ({}: CronJobsAccordionsProps) => { const groupedResponses = useContext(GroupedResponsesContext); diff --git a/plugins/kubernetes/src/components/CronJobsAccordions/CronJobsDrawer.test.tsx b/plugins/kubernetes-react/src/components/CronJobsAccordions/CronJobsDrawer.test.tsx similarity index 100% rename from plugins/kubernetes/src/components/CronJobsAccordions/CronJobsDrawer.test.tsx rename to plugins/kubernetes-react/src/components/CronJobsAccordions/CronJobsDrawer.test.tsx diff --git a/plugins/kubernetes/src/components/CronJobsAccordions/CronJobsDrawer.tsx b/plugins/kubernetes-react/src/components/CronJobsAccordions/CronJobsDrawer.tsx similarity index 100% rename from plugins/kubernetes/src/components/CronJobsAccordions/CronJobsDrawer.tsx rename to plugins/kubernetes-react/src/components/CronJobsAccordions/CronJobsDrawer.tsx diff --git a/plugins/kubernetes/src/components/JobsAccordions/index.ts b/plugins/kubernetes-react/src/components/CronJobsAccordions/index.ts similarity index 92% rename from plugins/kubernetes/src/components/JobsAccordions/index.ts rename to plugins/kubernetes-react/src/components/CronJobsAccordions/index.ts index 392309de79..ecc7172523 100644 --- a/plugins/kubernetes/src/components/JobsAccordions/index.ts +++ b/plugins/kubernetes-react/src/components/CronJobsAccordions/index.ts @@ -13,4 +13,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export { JobsAccordions } from './JobsAccordions'; +export * from './CronJobsAccordions'; diff --git a/plugins/kubernetes/src/components/CustomResources/ArgoRollouts/Rollout.test.tsx b/plugins/kubernetes-react/src/components/CustomResources/ArgoRollouts/Rollout.test.tsx similarity index 100% rename from plugins/kubernetes/src/components/CustomResources/ArgoRollouts/Rollout.test.tsx rename to plugins/kubernetes-react/src/components/CustomResources/ArgoRollouts/Rollout.test.tsx diff --git a/plugins/kubernetes/src/components/CustomResources/ArgoRollouts/Rollout.tsx b/plugins/kubernetes-react/src/components/CustomResources/ArgoRollouts/Rollout.tsx similarity index 100% rename from plugins/kubernetes/src/components/CustomResources/ArgoRollouts/Rollout.tsx rename to plugins/kubernetes-react/src/components/CustomResources/ArgoRollouts/Rollout.tsx diff --git a/plugins/kubernetes/src/components/CustomResources/ArgoRollouts/RolloutDrawer.tsx b/plugins/kubernetes-react/src/components/CustomResources/ArgoRollouts/RolloutDrawer.tsx similarity index 100% rename from plugins/kubernetes/src/components/CustomResources/ArgoRollouts/RolloutDrawer.tsx rename to plugins/kubernetes-react/src/components/CustomResources/ArgoRollouts/RolloutDrawer.tsx diff --git a/plugins/kubernetes/src/components/CustomResources/ArgoRollouts/StepsProgress.test.tsx b/plugins/kubernetes-react/src/components/CustomResources/ArgoRollouts/StepsProgress.test.tsx similarity index 100% rename from plugins/kubernetes/src/components/CustomResources/ArgoRollouts/StepsProgress.test.tsx rename to plugins/kubernetes-react/src/components/CustomResources/ArgoRollouts/StepsProgress.test.tsx diff --git a/plugins/kubernetes/src/components/CustomResources/ArgoRollouts/StepsProgress.tsx b/plugins/kubernetes-react/src/components/CustomResources/ArgoRollouts/StepsProgress.tsx similarity index 100% rename from plugins/kubernetes/src/components/CustomResources/ArgoRollouts/StepsProgress.tsx rename to plugins/kubernetes-react/src/components/CustomResources/ArgoRollouts/StepsProgress.tsx diff --git a/plugins/kubernetes/src/components/CustomResources/ArgoRollouts/__fixtures__/aborted-rollout.json b/plugins/kubernetes-react/src/components/CustomResources/ArgoRollouts/__fixtures__/aborted-rollout.json similarity index 100% rename from plugins/kubernetes/src/components/CustomResources/ArgoRollouts/__fixtures__/aborted-rollout.json rename to plugins/kubernetes-react/src/components/CustomResources/ArgoRollouts/__fixtures__/aborted-rollout.json diff --git a/plugins/kubernetes/src/components/CustomResources/ArgoRollouts/__fixtures__/analysis-steps.ts b/plugins/kubernetes-react/src/components/CustomResources/ArgoRollouts/__fixtures__/analysis-steps.ts similarity index 100% rename from plugins/kubernetes/src/components/CustomResources/ArgoRollouts/__fixtures__/analysis-steps.ts rename to plugins/kubernetes-react/src/components/CustomResources/ArgoRollouts/__fixtures__/analysis-steps.ts diff --git a/plugins/kubernetes/src/components/CustomResources/ArgoRollouts/__fixtures__/grouped-resources.json b/plugins/kubernetes-react/src/components/CustomResources/ArgoRollouts/__fixtures__/grouped-resources.json similarity index 100% rename from plugins/kubernetes/src/components/CustomResources/ArgoRollouts/__fixtures__/grouped-resources.json rename to plugins/kubernetes-react/src/components/CustomResources/ArgoRollouts/__fixtures__/grouped-resources.json diff --git a/plugins/kubernetes/src/components/CustomResources/ArgoRollouts/__fixtures__/pause-steps.ts b/plugins/kubernetes-react/src/components/CustomResources/ArgoRollouts/__fixtures__/pause-steps.ts similarity index 100% rename from plugins/kubernetes/src/components/CustomResources/ArgoRollouts/__fixtures__/pause-steps.ts rename to plugins/kubernetes-react/src/components/CustomResources/ArgoRollouts/__fixtures__/pause-steps.ts diff --git a/plugins/kubernetes/src/components/CustomResources/ArgoRollouts/__fixtures__/paused-rollout.json b/plugins/kubernetes-react/src/components/CustomResources/ArgoRollouts/__fixtures__/paused-rollout.json similarity index 100% rename from plugins/kubernetes/src/components/CustomResources/ArgoRollouts/__fixtures__/paused-rollout.json rename to plugins/kubernetes-react/src/components/CustomResources/ArgoRollouts/__fixtures__/paused-rollout.json diff --git a/plugins/kubernetes/src/components/CustomResources/ArgoRollouts/__fixtures__/rollout.json b/plugins/kubernetes-react/src/components/CustomResources/ArgoRollouts/__fixtures__/rollout.json similarity index 100% rename from plugins/kubernetes/src/components/CustomResources/ArgoRollouts/__fixtures__/rollout.json rename to plugins/kubernetes-react/src/components/CustomResources/ArgoRollouts/__fixtures__/rollout.json diff --git a/plugins/kubernetes/src/components/CustomResources/ArgoRollouts/__fixtures__/setweight-steps.ts b/plugins/kubernetes-react/src/components/CustomResources/ArgoRollouts/__fixtures__/setweight-steps.ts similarity index 100% rename from plugins/kubernetes/src/components/CustomResources/ArgoRollouts/__fixtures__/setweight-steps.ts rename to plugins/kubernetes-react/src/components/CustomResources/ArgoRollouts/__fixtures__/setweight-steps.ts diff --git a/plugins/kubernetes/src/components/CustomResources/ArgoRollouts/index.ts b/plugins/kubernetes-react/src/components/CustomResources/ArgoRollouts/index.ts similarity index 100% rename from plugins/kubernetes/src/components/CustomResources/ArgoRollouts/index.ts rename to plugins/kubernetes-react/src/components/CustomResources/ArgoRollouts/index.ts diff --git a/plugins/kubernetes/src/components/CustomResources/ArgoRollouts/types.ts b/plugins/kubernetes-react/src/components/CustomResources/ArgoRollouts/types.ts similarity index 100% rename from plugins/kubernetes/src/components/CustomResources/ArgoRollouts/types.ts rename to plugins/kubernetes-react/src/components/CustomResources/ArgoRollouts/types.ts diff --git a/plugins/kubernetes/src/components/CustomResources/CustomResources.tsx b/plugins/kubernetes-react/src/components/CustomResources/CustomResources.tsx similarity index 95% rename from plugins/kubernetes/src/components/CustomResources/CustomResources.tsx rename to plugins/kubernetes-react/src/components/CustomResources/CustomResources.tsx index 436e97fce8..f204f5fdd1 100644 --- a/plugins/kubernetes/src/components/CustomResources/CustomResources.tsx +++ b/plugins/kubernetes-react/src/components/CustomResources/CustomResources.tsx @@ -20,7 +20,12 @@ import { RolloutAccordions } from './ArgoRollouts'; import { DefaultCustomResourceAccordions } from './DefaultCustomResource'; import { GroupedResponsesContext } from '../../hooks'; -interface CustomResourcesProps { +/** + * + * + * @public + */ +export interface CustomResourcesProps { children?: React.ReactNode; } @@ -30,6 +35,11 @@ const kindToResource = (customResources: any[]): Dictionary<any[]> => { }); }; +/** + * + * + * @public + */ export const CustomResources = ({}: CustomResourcesProps) => { const groupedResponses = useContext(GroupedResponsesContext); const kindToResourceMap = kindToResource(groupedResponses.customResources); diff --git a/plugins/kubernetes/src/components/CustomResources/DefaultCustomResource.test.tsx b/plugins/kubernetes-react/src/components/CustomResources/DefaultCustomResource.test.tsx similarity index 100% rename from plugins/kubernetes/src/components/CustomResources/DefaultCustomResource.test.tsx rename to plugins/kubernetes-react/src/components/CustomResources/DefaultCustomResource.test.tsx diff --git a/plugins/kubernetes/src/components/CustomResources/DefaultCustomResource.tsx b/plugins/kubernetes-react/src/components/CustomResources/DefaultCustomResource.tsx similarity index 100% rename from plugins/kubernetes/src/components/CustomResources/DefaultCustomResource.tsx rename to plugins/kubernetes-react/src/components/CustomResources/DefaultCustomResource.tsx diff --git a/plugins/kubernetes/src/components/CustomResources/DefaultCustomResourceDrawer.tsx b/plugins/kubernetes-react/src/components/CustomResources/DefaultCustomResourceDrawer.tsx similarity index 100% rename from plugins/kubernetes/src/components/CustomResources/DefaultCustomResourceDrawer.tsx rename to plugins/kubernetes-react/src/components/CustomResources/DefaultCustomResourceDrawer.tsx diff --git a/plugins/kubernetes/src/components/CustomResources/__fixtures__/analysis-run.json b/plugins/kubernetes-react/src/components/CustomResources/__fixtures__/analysis-run.json similarity index 100% rename from plugins/kubernetes/src/components/CustomResources/__fixtures__/analysis-run.json rename to plugins/kubernetes-react/src/components/CustomResources/__fixtures__/analysis-run.json diff --git a/plugins/kubernetes/src/components/ErrorReporting/index.ts b/plugins/kubernetes-react/src/components/CustomResources/index.ts similarity index 92% rename from plugins/kubernetes/src/components/ErrorReporting/index.ts rename to plugins/kubernetes-react/src/components/CustomResources/index.ts index 451d08ec76..0c5e0ce7a0 100644 --- a/plugins/kubernetes/src/components/ErrorReporting/index.ts +++ b/plugins/kubernetes-react/src/components/CustomResources/index.ts @@ -13,4 +13,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export { ErrorReporting } from './ErrorReporting'; +export * from './CustomResources'; diff --git a/plugins/kubernetes/src/components/DeploymentsAccordions/DeploymentDrawer.test.tsx b/plugins/kubernetes-react/src/components/DeploymentsAccordions/DeploymentDrawer.test.tsx similarity index 100% rename from plugins/kubernetes/src/components/DeploymentsAccordions/DeploymentDrawer.test.tsx rename to plugins/kubernetes-react/src/components/DeploymentsAccordions/DeploymentDrawer.test.tsx diff --git a/plugins/kubernetes/src/components/DeploymentsAccordions/DeploymentDrawer.tsx b/plugins/kubernetes-react/src/components/DeploymentsAccordions/DeploymentDrawer.tsx similarity index 100% rename from plugins/kubernetes/src/components/DeploymentsAccordions/DeploymentDrawer.tsx rename to plugins/kubernetes-react/src/components/DeploymentsAccordions/DeploymentDrawer.tsx diff --git a/plugins/kubernetes/src/components/DeploymentsAccordions/DeploymentsAccordions.test.tsx b/plugins/kubernetes-react/src/components/DeploymentsAccordions/DeploymentsAccordions.test.tsx similarity index 100% rename from plugins/kubernetes/src/components/DeploymentsAccordions/DeploymentsAccordions.test.tsx rename to plugins/kubernetes-react/src/components/DeploymentsAccordions/DeploymentsAccordions.test.tsx diff --git a/plugins/kubernetes/src/components/DeploymentsAccordions/DeploymentsAccordions.tsx b/plugins/kubernetes-react/src/components/DeploymentsAccordions/DeploymentsAccordions.tsx similarity index 100% rename from plugins/kubernetes/src/components/DeploymentsAccordions/DeploymentsAccordions.tsx rename to plugins/kubernetes-react/src/components/DeploymentsAccordions/DeploymentsAccordions.tsx diff --git a/plugins/kubernetes/src/components/DeploymentsAccordions/index.ts b/plugins/kubernetes-react/src/components/DeploymentsAccordions/index.ts similarity index 100% rename from plugins/kubernetes/src/components/DeploymentsAccordions/index.ts rename to plugins/kubernetes-react/src/components/DeploymentsAccordions/index.ts diff --git a/plugins/kubernetes/src/components/ErrorPanel/ErrorPanel.test.tsx b/plugins/kubernetes-react/src/components/ErrorPanel/ErrorPanel.test.tsx similarity index 100% rename from plugins/kubernetes/src/components/ErrorPanel/ErrorPanel.test.tsx rename to plugins/kubernetes-react/src/components/ErrorPanel/ErrorPanel.test.tsx diff --git a/plugins/kubernetes/src/components/ErrorPanel/ErrorPanel.tsx b/plugins/kubernetes-react/src/components/ErrorPanel/ErrorPanel.tsx similarity index 96% rename from plugins/kubernetes/src/components/ErrorPanel/ErrorPanel.tsx rename to plugins/kubernetes-react/src/components/ErrorPanel/ErrorPanel.tsx index d2cb88b9ca..b02f4c18dc 100644 --- a/plugins/kubernetes/src/components/ErrorPanel/ErrorPanel.tsx +++ b/plugins/kubernetes-react/src/components/ErrorPanel/ErrorPanel.tsx @@ -41,13 +41,23 @@ const clustersWithErrorsToErrorMessage = ( }); }; -type ErrorPanelProps = { +/** + * + * + * @public + */ +export type ErrorPanelProps = { entityName: string; errorMessage?: string; clustersWithErrors?: ClusterObjects[]; children?: React.ReactNode; }; +/** + * + * + * @public + */ export const ErrorPanel = ({ entityName, errorMessage, diff --git a/plugins/kubernetes/src/components/CustomResources/index.ts b/plugins/kubernetes-react/src/components/ErrorPanel/index.ts similarity index 91% rename from plugins/kubernetes/src/components/CustomResources/index.ts rename to plugins/kubernetes-react/src/components/ErrorPanel/index.ts index 9297fd8ac1..94d6e5b028 100644 --- a/plugins/kubernetes/src/components/CustomResources/index.ts +++ b/plugins/kubernetes-react/src/components/ErrorPanel/index.ts @@ -13,4 +13,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export { CustomResources } from './CustomResources'; +export * from './ErrorPanel'; diff --git a/plugins/kubernetes/src/components/ErrorReporting/ErrorReporting.tsx b/plugins/kubernetes-react/src/components/ErrorReporting/ErrorReporting.tsx similarity index 92% rename from plugins/kubernetes/src/components/ErrorReporting/ErrorReporting.tsx rename to plugins/kubernetes-react/src/components/ErrorReporting/ErrorReporting.tsx index 367e791067..64345662ed 100644 --- a/plugins/kubernetes/src/components/ErrorReporting/ErrorReporting.tsx +++ b/plugins/kubernetes-react/src/components/ErrorReporting/ErrorReporting.tsx @@ -14,10 +14,18 @@ * limitations under the License. */ import * as React from 'react'; -import { DetectedError, DetectedErrorsByCluster } from '../../error-detection'; +import { + DetectedError, + DetectedErrorsByCluster, +} from '@backstage/plugin-kubernetes-common'; import { Table, TableColumn } from '@backstage/core-components'; -type ErrorReportingProps = { +/** + * + * + * @public + */ +export type ErrorReportingProps = { detectedErrors: DetectedErrorsByCluster; }; @@ -65,6 +73,11 @@ const sortBySeverity = (a: Row, b: Row) => { return 0; }; +/** + * + * + * @public + */ export const ErrorReporting = ({ detectedErrors }: ErrorReportingProps) => { const errors = Array.from(detectedErrors.entries()) .flatMap(([clusterName, resourceErrors]) => { diff --git a/plugins/kubernetes-react/src/components/ErrorReporting/index.ts b/plugins/kubernetes-react/src/components/ErrorReporting/index.ts new file mode 100644 index 0000000000..3382849229 --- /dev/null +++ b/plugins/kubernetes-react/src/components/ErrorReporting/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 './ErrorReporting'; diff --git a/plugins/kubernetes/src/components/HorizontalPodAutoscalers/HorizontalPodAutoscalerDrawer.test.tsx b/plugins/kubernetes-react/src/components/HorizontalPodAutoscalers/HorizontalPodAutoscalerDrawer.test.tsx similarity index 100% rename from plugins/kubernetes/src/components/HorizontalPodAutoscalers/HorizontalPodAutoscalerDrawer.test.tsx rename to plugins/kubernetes-react/src/components/HorizontalPodAutoscalers/HorizontalPodAutoscalerDrawer.test.tsx diff --git a/plugins/kubernetes/src/components/HorizontalPodAutoscalers/HorizontalPodAutoscalerDrawer.tsx b/plugins/kubernetes-react/src/components/HorizontalPodAutoscalers/HorizontalPodAutoscalerDrawer.tsx similarity index 100% rename from plugins/kubernetes/src/components/HorizontalPodAutoscalers/HorizontalPodAutoscalerDrawer.tsx rename to plugins/kubernetes-react/src/components/HorizontalPodAutoscalers/HorizontalPodAutoscalerDrawer.tsx diff --git a/plugins/kubernetes/src/components/HorizontalPodAutoscalers/__fixtures__/horizontalpodautoscalers.json b/plugins/kubernetes-react/src/components/HorizontalPodAutoscalers/__fixtures__/horizontalpodautoscalers.json similarity index 100% rename from plugins/kubernetes/src/components/HorizontalPodAutoscalers/__fixtures__/horizontalpodautoscalers.json rename to plugins/kubernetes-react/src/components/HorizontalPodAutoscalers/__fixtures__/horizontalpodautoscalers.json diff --git a/plugins/kubernetes/src/components/HorizontalPodAutoscalers/index.ts b/plugins/kubernetes-react/src/components/HorizontalPodAutoscalers/index.ts similarity index 100% rename from plugins/kubernetes/src/components/HorizontalPodAutoscalers/index.ts rename to plugins/kubernetes-react/src/components/HorizontalPodAutoscalers/index.ts diff --git a/plugins/kubernetes/src/components/IngressesAccordions/IngressDrawer.test.tsx b/plugins/kubernetes-react/src/components/IngressesAccordions/IngressDrawer.test.tsx similarity index 100% rename from plugins/kubernetes/src/components/IngressesAccordions/IngressDrawer.test.tsx rename to plugins/kubernetes-react/src/components/IngressesAccordions/IngressDrawer.test.tsx diff --git a/plugins/kubernetes/src/components/IngressesAccordions/IngressDrawer.tsx b/plugins/kubernetes-react/src/components/IngressesAccordions/IngressDrawer.tsx similarity index 100% rename from plugins/kubernetes/src/components/IngressesAccordions/IngressDrawer.tsx rename to plugins/kubernetes-react/src/components/IngressesAccordions/IngressDrawer.tsx diff --git a/plugins/kubernetes/src/components/IngressesAccordions/IngressesAccordions.test.tsx b/plugins/kubernetes-react/src/components/IngressesAccordions/IngressesAccordions.test.tsx similarity index 100% rename from plugins/kubernetes/src/components/IngressesAccordions/IngressesAccordions.test.tsx rename to plugins/kubernetes-react/src/components/IngressesAccordions/IngressesAccordions.test.tsx diff --git a/plugins/kubernetes/src/components/IngressesAccordions/IngressesAccordions.tsx b/plugins/kubernetes-react/src/components/IngressesAccordions/IngressesAccordions.tsx similarity index 96% rename from plugins/kubernetes/src/components/IngressesAccordions/IngressesAccordions.tsx rename to plugins/kubernetes-react/src/components/IngressesAccordions/IngressesAccordions.tsx index 6e12c033ba..28aa5d42e4 100644 --- a/plugins/kubernetes/src/components/IngressesAccordions/IngressesAccordions.tsx +++ b/plugins/kubernetes-react/src/components/IngressesAccordions/IngressesAccordions.tsx @@ -27,7 +27,12 @@ import { IngressDrawer } from './IngressDrawer'; import { GroupedResponsesContext } from '../../hooks'; import { StructuredMetadataTable } from '@backstage/core-components'; -type IngressesAccordionsProps = {}; +/** + * + * + * @public + */ +export type IngressesAccordionsProps = {}; type IngressAccordionProps = { ingress: V1Ingress; @@ -78,6 +83,12 @@ const IngressAccordion = ({ ingress }: IngressAccordionProps) => { </Accordion> ); }; + +/** + * + * + * @public + */ export const IngressesAccordions = ({}: IngressesAccordionsProps) => { const groupedResponses = useContext(GroupedResponsesContext); return ( diff --git a/plugins/kubernetes/src/components/IngressesAccordions/__fixtures__/2-ingresses.json b/plugins/kubernetes-react/src/components/IngressesAccordions/__fixtures__/2-ingresses.json similarity index 100% rename from plugins/kubernetes/src/components/IngressesAccordions/__fixtures__/2-ingresses.json rename to plugins/kubernetes-react/src/components/IngressesAccordions/__fixtures__/2-ingresses.json diff --git a/plugins/kubernetes-react/src/components/IngressesAccordions/index.ts b/plugins/kubernetes-react/src/components/IngressesAccordions/index.ts new file mode 100644 index 0000000000..ece35ab17a --- /dev/null +++ b/plugins/kubernetes-react/src/components/IngressesAccordions/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 './IngressesAccordions'; diff --git a/plugins/kubernetes/src/components/JobsAccordions/JobsAccordions.test.tsx b/plugins/kubernetes-react/src/components/JobsAccordions/JobsAccordions.test.tsx similarity index 100% rename from plugins/kubernetes/src/components/JobsAccordions/JobsAccordions.test.tsx rename to plugins/kubernetes-react/src/components/JobsAccordions/JobsAccordions.test.tsx diff --git a/plugins/kubernetes/src/components/JobsAccordions/JobsAccordions.tsx b/plugins/kubernetes-react/src/components/JobsAccordions/JobsAccordions.tsx similarity index 97% rename from plugins/kubernetes/src/components/JobsAccordions/JobsAccordions.tsx rename to plugins/kubernetes-react/src/components/JobsAccordions/JobsAccordions.tsx index e805e3664b..460d0b80c0 100644 --- a/plugins/kubernetes/src/components/JobsAccordions/JobsAccordions.tsx +++ b/plugins/kubernetes-react/src/components/JobsAccordions/JobsAccordions.tsx @@ -32,7 +32,12 @@ import { StatusPending, } from '@backstage/core-components'; -type JobsAccordionsProps = { +/** + * + * + * @public + */ +export type JobsAccordionsProps = { jobs: V1Job[]; children?: React.ReactNode; }; @@ -98,6 +103,11 @@ const JobAccordion = ({ job, ownedPods }: JobAccordionProps) => { ); }; +/** + * + * + * @public + */ export const JobsAccordions = ({ jobs }: JobsAccordionsProps) => { const groupedResponses = useContext(GroupedResponsesContext); diff --git a/plugins/kubernetes/src/components/JobsAccordions/JobsDrawer.test.tsx b/plugins/kubernetes-react/src/components/JobsAccordions/JobsDrawer.test.tsx similarity index 100% rename from plugins/kubernetes/src/components/JobsAccordions/JobsDrawer.test.tsx rename to plugins/kubernetes-react/src/components/JobsAccordions/JobsDrawer.test.tsx diff --git a/plugins/kubernetes/src/components/JobsAccordions/JobsDrawer.tsx b/plugins/kubernetes-react/src/components/JobsAccordions/JobsDrawer.tsx similarity index 100% rename from plugins/kubernetes/src/components/JobsAccordions/JobsDrawer.tsx rename to plugins/kubernetes-react/src/components/JobsAccordions/JobsDrawer.tsx diff --git a/cypress/src/plugins/index.ts b/plugins/kubernetes-react/src/components/JobsAccordions/index.ts similarity index 94% rename from cypress/src/plugins/index.ts rename to plugins/kubernetes-react/src/components/JobsAccordions/index.ts index 4c8a35f0d1..c69c493dc8 100644 --- a/cypress/src/plugins/index.ts +++ b/plugins/kubernetes-react/src/components/JobsAccordions/index.ts @@ -13,4 +13,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export default () => {}; +export * from './JobsAccordions'; diff --git a/plugins/kubernetes/src/components/KubernetesDrawer/KubernetesDrawer.tsx b/plugins/kubernetes-react/src/components/KubernetesDrawer/KubernetesDrawer.tsx similarity index 93% rename from plugins/kubernetes/src/components/KubernetesDrawer/KubernetesDrawer.tsx rename to plugins/kubernetes-react/src/components/KubernetesDrawer/KubernetesDrawer.tsx index 18ef5d9505..598dac4fe8 100644 --- a/plugins/kubernetes/src/components/KubernetesDrawer/KubernetesDrawer.tsx +++ b/plugins/kubernetes-react/src/components/KubernetesDrawer/KubernetesDrawer.tsx @@ -48,7 +48,12 @@ const useDrawerContentStyles = makeStyles((_theme: Theme) => }), ); -interface KubernetesObject { +/** + * The type of object that can be represented by the Drawer + * + * @public + */ +export interface KubernetesObject { kind: string; metadata?: IObjectMeta; } @@ -60,7 +65,7 @@ interface KubernetesDrawerContentProps { children?: React.ReactNode; } -export const KubernetesDrawerContent = ({ +const KubernetesDrawerContent = ({ children, header, kubernetesObject, @@ -115,7 +120,12 @@ export const KubernetesDrawerContent = ({ ); }; -interface KubernetesDrawerProps { +/** + * Props of KubernetesDrawer + * + * @public + */ +export interface KubernetesDrawerProps { open?: boolean; kubernetesObject: KubernetesObject; label: React.ReactNode; @@ -142,6 +152,11 @@ const DrawerButton = withStyles({ }, })(Button); +/** + * Button/Drawer component for Kubernetes Objects + * + * @public + */ export const KubernetesDrawer = ({ open, label, diff --git a/plugins/kubernetes/src/components/KubernetesDrawer/KubernetesStructuredMetadataTableDrawer.tsx b/plugins/kubernetes-react/src/components/KubernetesDrawer/KubernetesStructuredMetadataTableDrawer.tsx similarity index 95% rename from plugins/kubernetes/src/components/KubernetesDrawer/KubernetesStructuredMetadataTableDrawer.tsx rename to plugins/kubernetes-react/src/components/KubernetesDrawer/KubernetesStructuredMetadataTableDrawer.tsx index 8f28549f83..65001c658e 100644 --- a/plugins/kubernetes/src/components/KubernetesDrawer/KubernetesStructuredMetadataTableDrawer.tsx +++ b/plugins/kubernetes-react/src/components/KubernetesDrawer/KubernetesStructuredMetadataTableDrawer.tsx @@ -86,13 +86,26 @@ const PodDrawerButton = withStyles({ }, })(Button); -type ErrorPanelProps = { +/** + * + * + * @public + */ +export type LinkErrorPanelProps = { cluster: ClusterAttributes; errorMessage?: string; children?: React.ReactNode; }; -export const LinkErrorPanel = ({ cluster, errorMessage }: ErrorPanelProps) => ( +/** + * + * + * @public + */ +export const LinkErrorPanel = ({ + cluster, + errorMessage, +}: LinkErrorPanelProps) => ( <WarningPanel title="There was a problem formatting the link to the Kubernetes dashboard" message={`Could not format the link to the dashboard of your cluster named '${ @@ -107,7 +120,12 @@ export const LinkErrorPanel = ({ cluster, errorMessage }: ErrorPanelProps) => ( </WarningPanel> ); -interface KubernetesDrawerable { +/** + * + * + * @public + */ +export interface KubernetesDrawerable { metadata?: V1ObjectMeta; } @@ -234,7 +252,12 @@ const KubernetesStructuredMetadataTableDrawerContent = < </> ); }; -interface KubernetesStructuredMetadataTableDrawerProps< + +/** + * + * @public + */ +export interface KubernetesStructuredMetadataTableDrawerProps< T extends KubernetesDrawerable, > { object: T; @@ -245,6 +268,10 @@ interface KubernetesStructuredMetadataTableDrawerProps< children?: React.ReactNode; } +/** + * + * @public + */ export const KubernetesStructuredMetadataTableDrawer = < T extends KubernetesDrawerable, >({ diff --git a/plugins/kubernetes/src/components/KubernetesDrawer/ManifestYaml.tsx b/plugins/kubernetes-react/src/components/KubernetesDrawer/ManifestYaml.tsx similarity index 94% rename from plugins/kubernetes/src/components/KubernetesDrawer/ManifestYaml.tsx rename to plugins/kubernetes-react/src/components/KubernetesDrawer/ManifestYaml.tsx index 8f0c38afde..246477b53b 100644 --- a/plugins/kubernetes/src/components/KubernetesDrawer/ManifestYaml.tsx +++ b/plugins/kubernetes-react/src/components/KubernetesDrawer/ManifestYaml.tsx @@ -18,10 +18,20 @@ import { FormControlLabel, Switch } from '@material-ui/core'; import jsyaml from 'js-yaml'; import React, { useState } from 'react'; +/** + * Props of ManifestYaml + * + * @public + */ export interface ManifestYamlProps { object: object; } +/** + * Renders a Kubernetes object as a YAML code snippet + * + * @public + */ export const ManifestYaml = ({ object }: ManifestYamlProps) => { // Toggle whether the Kubernetes resource managed fields should be shown in // the YAML display. This toggle is only available when the YAML is being diff --git a/plugins/kubernetes/src/components/KubernetesDrawer/index.ts b/plugins/kubernetes-react/src/components/KubernetesDrawer/index.ts similarity index 95% rename from plugins/kubernetes/src/components/KubernetesDrawer/index.ts rename to plugins/kubernetes-react/src/components/KubernetesDrawer/index.ts index a0108cbda6..cc5337544b 100644 --- a/plugins/kubernetes/src/components/KubernetesDrawer/index.ts +++ b/plugins/kubernetes-react/src/components/KubernetesDrawer/index.ts @@ -16,3 +16,4 @@ export * from './KubernetesStructuredMetadataTableDrawer'; export * from './KubernetesDrawer'; +export * from './ManifestYaml'; diff --git a/plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminal.test.tsx b/plugins/kubernetes-react/src/components/PodExecTerminal/PodExecTerminal.test.tsx similarity index 100% rename from plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminal.test.tsx rename to plugins/kubernetes-react/src/components/PodExecTerminal/PodExecTerminal.test.tsx diff --git a/plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminal.tsx b/plugins/kubernetes-react/src/components/PodExecTerminal/PodExecTerminal.tsx similarity index 99% rename from plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminal.tsx rename to plugins/kubernetes-react/src/components/PodExecTerminal/PodExecTerminal.tsx index a741f4e189..f8106bd011 100644 --- a/plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminal.tsx +++ b/plugins/kubernetes-react/src/components/PodExecTerminal/PodExecTerminal.tsx @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import 'xterm/css/xterm.css'; +import 'xterm'; import { discoveryApiRef, useApi } from '@backstage/core-plugin-api'; import React, { useEffect, useMemo, useState } from 'react'; diff --git a/plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminalAttachAddon.ts b/plugins/kubernetes-react/src/components/PodExecTerminal/PodExecTerminalAttachAddon.ts similarity index 100% rename from plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminalAttachAddon.ts rename to plugins/kubernetes-react/src/components/PodExecTerminal/PodExecTerminalAttachAddon.ts diff --git a/plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminalDialog.tsx b/plugins/kubernetes-react/src/components/PodExecTerminal/PodExecTerminalDialog.tsx similarity index 100% rename from plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminalDialog.tsx rename to plugins/kubernetes-react/src/components/PodExecTerminal/PodExecTerminalDialog.tsx diff --git a/plugins/kubernetes/src/components/PodExecTerminal/index.ts b/plugins/kubernetes-react/src/components/PodExecTerminal/index.ts similarity index 100% rename from plugins/kubernetes/src/components/PodExecTerminal/index.ts rename to plugins/kubernetes-react/src/components/PodExecTerminal/index.ts diff --git a/plugins/kubernetes/src/components/PodExecTerminal/matchMedia.mock.ts b/plugins/kubernetes-react/src/components/PodExecTerminal/matchMedia.mock.ts similarity index 100% rename from plugins/kubernetes/src/components/PodExecTerminal/matchMedia.mock.ts rename to plugins/kubernetes-react/src/components/PodExecTerminal/matchMedia.mock.ts diff --git a/plugins/kubernetes/src/components/Pods/ErrorList/ErrorList.test.tsx b/plugins/kubernetes-react/src/components/Pods/ErrorList/ErrorList.test.tsx similarity index 97% rename from plugins/kubernetes/src/components/Pods/ErrorList/ErrorList.test.tsx rename to plugins/kubernetes-react/src/components/Pods/ErrorList/ErrorList.test.tsx index b05b4d2d9e..2423654cc3 100644 --- a/plugins/kubernetes/src/components/Pods/ErrorList/ErrorList.test.tsx +++ b/plugins/kubernetes-react/src/components/Pods/ErrorList/ErrorList.test.tsx @@ -18,7 +18,7 @@ import React from 'react'; import { render } from '@testing-library/react'; import { ErrorList } from './ErrorList'; -import { Pod } from 'kubernetes-models/v1/Pod'; +import { Pod } from 'kubernetes-models/v1'; describe('ErrorList', () => { it('error highlight should render', () => { diff --git a/plugins/kubernetes/src/components/Pods/ErrorList/ErrorList.tsx b/plugins/kubernetes-react/src/components/Pods/ErrorList/ErrorList.tsx similarity index 100% rename from plugins/kubernetes/src/components/Pods/ErrorList/ErrorList.tsx rename to plugins/kubernetes-react/src/components/Pods/ErrorList/ErrorList.tsx diff --git a/plugins/kubernetes/src/components/Pods/ErrorList/index.ts b/plugins/kubernetes-react/src/components/Pods/ErrorList/index.ts similarity index 100% rename from plugins/kubernetes/src/components/Pods/ErrorList/index.ts rename to plugins/kubernetes-react/src/components/Pods/ErrorList/index.ts diff --git a/plugins/kubernetes/src/components/Pods/Events/Events.test.tsx b/plugins/kubernetes-react/src/components/Pods/Events/Events.test.tsx similarity index 100% rename from plugins/kubernetes/src/components/Pods/Events/Events.test.tsx rename to plugins/kubernetes-react/src/components/Pods/Events/Events.test.tsx diff --git a/plugins/kubernetes/src/components/Pods/Events/Events.tsx b/plugins/kubernetes-react/src/components/Pods/Events/Events.tsx similarity index 100% rename from plugins/kubernetes/src/components/Pods/Events/Events.tsx rename to plugins/kubernetes-react/src/components/Pods/Events/Events.tsx diff --git a/plugins/kubernetes/src/components/Pods/Events/index.ts b/plugins/kubernetes-react/src/components/Pods/Events/index.ts similarity index 100% rename from plugins/kubernetes/src/components/Pods/Events/index.ts rename to plugins/kubernetes-react/src/components/Pods/Events/index.ts diff --git a/plugins/kubernetes/src/components/Pods/Events/useEvents.test.tsx b/plugins/kubernetes-react/src/components/Pods/Events/useEvents.test.tsx similarity index 100% rename from plugins/kubernetes/src/components/Pods/Events/useEvents.test.tsx rename to plugins/kubernetes-react/src/components/Pods/Events/useEvents.test.tsx diff --git a/plugins/kubernetes/src/components/Pods/Events/useEvents.ts b/plugins/kubernetes-react/src/components/Pods/Events/useEvents.ts similarity index 95% rename from plugins/kubernetes/src/components/Pods/Events/useEvents.ts rename to plugins/kubernetes-react/src/components/Pods/Events/useEvents.ts index 441937507d..e31a4ee859 100644 --- a/plugins/kubernetes/src/components/Pods/Events/useEvents.ts +++ b/plugins/kubernetes-react/src/components/Pods/Events/useEvents.ts @@ -15,7 +15,7 @@ */ import { useApi } from '@backstage/core-plugin-api'; import useAsync from 'react-use/lib/useAsync'; -import { kubernetesProxyApiRef } from '../../../api'; +import { kubernetesProxyApiRef } from '../../../api/types'; /** * Arguments for useEvents diff --git a/plugins/kubernetes/src/components/Pods/FixDialog/FixDialog.test.tsx b/plugins/kubernetes-react/src/components/Pods/FixDialog/FixDialog.test.tsx similarity index 100% rename from plugins/kubernetes/src/components/Pods/FixDialog/FixDialog.test.tsx rename to plugins/kubernetes-react/src/components/Pods/FixDialog/FixDialog.test.tsx diff --git a/plugins/kubernetes/src/components/Pods/FixDialog/FixDialog.tsx b/plugins/kubernetes-react/src/components/Pods/FixDialog/FixDialog.tsx similarity index 98% rename from plugins/kubernetes/src/components/Pods/FixDialog/FixDialog.tsx rename to plugins/kubernetes-react/src/components/Pods/FixDialog/FixDialog.tsx index 63ce4af03b..c691cc67fd 100644 --- a/plugins/kubernetes/src/components/Pods/FixDialog/FixDialog.tsx +++ b/plugins/kubernetes-react/src/components/Pods/FixDialog/FixDialog.tsx @@ -28,7 +28,7 @@ import HelpIcon from '@material-ui/icons/Help'; import OpenInNewIcon from '@material-ui/icons/OpenInNew'; import { Pod } from 'kubernetes-models/v1/Pod'; -import { DetectedError } from '../../../error-detection'; +import { DetectedError } from '@backstage/plugin-kubernetes-common'; import { PodLogs } from '../PodLogs'; import { Events } from '../Events'; import { LinkButton } from '@backstage/core-components'; diff --git a/plugins/kubernetes/src/components/Pods/FixDialog/index.ts b/plugins/kubernetes-react/src/components/Pods/FixDialog/index.ts similarity index 100% rename from plugins/kubernetes/src/components/Pods/FixDialog/index.ts rename to plugins/kubernetes-react/src/components/Pods/FixDialog/index.ts diff --git a/plugins/kubernetes/src/components/Pods/PodDrawer/ContainerCard.test.tsx b/plugins/kubernetes-react/src/components/Pods/PodDrawer/ContainerCard.test.tsx similarity index 100% rename from plugins/kubernetes/src/components/Pods/PodDrawer/ContainerCard.test.tsx rename to plugins/kubernetes-react/src/components/Pods/PodDrawer/ContainerCard.test.tsx diff --git a/plugins/kubernetes/src/components/Pods/PodDrawer/ContainerCard.tsx b/plugins/kubernetes-react/src/components/Pods/PodDrawer/ContainerCard.tsx similarity index 100% rename from plugins/kubernetes/src/components/Pods/PodDrawer/ContainerCard.tsx rename to plugins/kubernetes-react/src/components/Pods/PodDrawer/ContainerCard.tsx diff --git a/plugins/kubernetes/src/components/Pods/PodDrawer/PendingPodContent.test.tsx b/plugins/kubernetes-react/src/components/Pods/PodDrawer/PendingPodContent.test.tsx similarity index 100% rename from plugins/kubernetes/src/components/Pods/PodDrawer/PendingPodContent.test.tsx rename to plugins/kubernetes-react/src/components/Pods/PodDrawer/PendingPodContent.test.tsx diff --git a/plugins/kubernetes/src/components/Pods/PodDrawer/PendingPodContent.tsx b/plugins/kubernetes-react/src/components/Pods/PodDrawer/PendingPodContent.tsx similarity index 100% rename from plugins/kubernetes/src/components/Pods/PodDrawer/PendingPodContent.tsx rename to plugins/kubernetes-react/src/components/Pods/PodDrawer/PendingPodContent.tsx diff --git a/plugins/kubernetes/src/components/Pods/PodDrawer/PodDrawer.test.tsx b/plugins/kubernetes-react/src/components/Pods/PodDrawer/PodDrawer.test.tsx similarity index 100% rename from plugins/kubernetes/src/components/Pods/PodDrawer/PodDrawer.test.tsx rename to plugins/kubernetes-react/src/components/Pods/PodDrawer/PodDrawer.test.tsx diff --git a/plugins/kubernetes/src/components/Pods/PodDrawer/PodDrawer.tsx b/plugins/kubernetes-react/src/components/Pods/PodDrawer/PodDrawer.tsx similarity index 99% rename from plugins/kubernetes/src/components/Pods/PodDrawer/PodDrawer.tsx rename to plugins/kubernetes-react/src/components/Pods/PodDrawer/PodDrawer.tsx index 30588cd347..1b98237d5a 100644 --- a/plugins/kubernetes/src/components/Pods/PodDrawer/PodDrawer.tsx +++ b/plugins/kubernetes-react/src/components/Pods/PodDrawer/PodDrawer.tsx @@ -67,7 +67,7 @@ function getContainerSpecByName(pod: Pod, containerName: string) { * * @public */ -interface PodDrawerProps { +export interface PodDrawerProps { open?: boolean; podAndErrors: PodAndErrors; } diff --git a/plugins/kubernetes/src/components/Pods/PodDrawer/index.ts b/plugins/kubernetes-react/src/components/Pods/PodDrawer/index.ts similarity index 100% rename from plugins/kubernetes/src/components/Pods/PodDrawer/index.ts rename to plugins/kubernetes-react/src/components/Pods/PodDrawer/index.ts diff --git a/plugins/kubernetes/src/components/Pods/PodLogs/PodLogs.tsx b/plugins/kubernetes-react/src/components/Pods/PodLogs/PodLogs.tsx similarity index 100% rename from plugins/kubernetes/src/components/Pods/PodLogs/PodLogs.tsx rename to plugins/kubernetes-react/src/components/Pods/PodLogs/PodLogs.tsx diff --git a/plugins/kubernetes/src/components/Pods/PodLogs/PodLogsDialog.tsx b/plugins/kubernetes-react/src/components/Pods/PodLogs/PodLogsDialog.tsx similarity index 100% rename from plugins/kubernetes/src/components/Pods/PodLogs/PodLogsDialog.tsx rename to plugins/kubernetes-react/src/components/Pods/PodLogs/PodLogsDialog.tsx diff --git a/plugins/kubernetes/src/components/Pods/PodLogs/index.ts b/plugins/kubernetes-react/src/components/Pods/PodLogs/index.ts similarity index 100% rename from plugins/kubernetes/src/components/Pods/PodLogs/index.ts rename to plugins/kubernetes-react/src/components/Pods/PodLogs/index.ts diff --git a/plugins/kubernetes/src/components/Pods/PodLogs/types.ts b/plugins/kubernetes-react/src/components/Pods/PodLogs/types.ts similarity index 100% rename from plugins/kubernetes/src/components/Pods/PodLogs/types.ts rename to plugins/kubernetes-react/src/components/Pods/PodLogs/types.ts diff --git a/plugins/kubernetes/src/components/Pods/PodLogs/usePodLogs.ts b/plugins/kubernetes-react/src/components/Pods/PodLogs/usePodLogs.ts similarity index 95% rename from plugins/kubernetes/src/components/Pods/PodLogs/usePodLogs.ts rename to plugins/kubernetes-react/src/components/Pods/PodLogs/usePodLogs.ts index 495bb1dc71..26764fc64c 100644 --- a/plugins/kubernetes/src/components/Pods/PodLogs/usePodLogs.ts +++ b/plugins/kubernetes-react/src/components/Pods/PodLogs/usePodLogs.ts @@ -17,7 +17,7 @@ import useAsync from 'react-use/lib/useAsync'; import { ContainerScope } from './types'; import { useApi } from '@backstage/core-plugin-api'; -import { kubernetesProxyApiRef } from '../../../api'; +import { kubernetesProxyApiRef } from '../../../api/types'; /** * Arguments for usePodLogs diff --git a/plugins/kubernetes/src/components/Pods/PodsTable.test.tsx b/plugins/kubernetes-react/src/components/Pods/PodsTable.test.tsx similarity index 100% rename from plugins/kubernetes/src/components/Pods/PodsTable.test.tsx rename to plugins/kubernetes-react/src/components/Pods/PodsTable.test.tsx diff --git a/plugins/kubernetes/src/components/Pods/PodsTable.tsx b/plugins/kubernetes-react/src/components/Pods/PodsTable.tsx similarity index 96% rename from plugins/kubernetes/src/components/Pods/PodsTable.tsx rename to plugins/kubernetes-react/src/components/Pods/PodsTable.tsx index bebfbd0b5d..f7c2660c84 100644 --- a/plugins/kubernetes/src/components/Pods/PodsTable.tsx +++ b/plugins/kubernetes-react/src/components/Pods/PodsTable.tsx @@ -31,11 +31,33 @@ import { V1Pod } from '@kubernetes/client-node'; import { usePodMetrics } from '../../hooks/usePodMetrics'; import { Typography } from '@material-ui/core'; +/** + * + * + * @public + */ export const READY_COLUMNS: PodColumns = 'READY'; + +/** + * + * + * @public + */ export const RESOURCE_COLUMNS: PodColumns = 'RESOURCE'; + +/** + * + * + * @public + */ export type PodColumns = 'READY' | 'RESOURCE'; -type PodsTablesProps = { +/** + * + * + * @public + */ +export type PodsTablesProps = { pods: Pod | V1Pod[]; extraColumns?: PodColumns[]; children?: React.ReactNode; @@ -95,6 +117,11 @@ const Memory = ({ clusterName, pod }: { clusterName: string; pod: Pod }) => { return <>{podStatusToMemoryUtil(metrics)}</>; }; +/** + * + * + * @public + */ export const PodsTable = ({ pods, extraColumns = [] }: PodsTablesProps) => { const cluster = useContext(ClusterContext); const defaultColumns: TableColumn<Pod>[] = [ diff --git a/plugins/kubernetes/src/components/Pods/__fixtures__/crashing-pod.json b/plugins/kubernetes-react/src/components/Pods/__fixtures__/crashing-pod.json similarity index 100% rename from plugins/kubernetes/src/components/Pods/__fixtures__/crashing-pod.json rename to plugins/kubernetes-react/src/components/Pods/__fixtures__/crashing-pod.json diff --git a/plugins/kubernetes/src/error-detection/__fixtures__/pod.json b/plugins/kubernetes-react/src/components/Pods/__fixtures__/pod.json similarity index 100% rename from plugins/kubernetes/src/error-detection/__fixtures__/pod.json rename to plugins/kubernetes-react/src/components/Pods/__fixtures__/pod.json diff --git a/plugins/kubernetes/src/components/Pods/index.ts b/plugins/kubernetes-react/src/components/Pods/index.ts similarity index 94% rename from plugins/kubernetes/src/components/Pods/index.ts rename to plugins/kubernetes-react/src/components/Pods/index.ts index c4282de53a..6297a0abce 100644 --- a/plugins/kubernetes/src/components/Pods/index.ts +++ b/plugins/kubernetes-react/src/components/Pods/index.ts @@ -18,5 +18,5 @@ export * from './PodLogs'; export * from './FixDialog'; export * from './Events'; export * from './ErrorList'; -export { PodsTable } from './PodsTable'; +export * from './PodsTable'; export * from './types'; diff --git a/plugins/kubernetes/src/components/Pods/types.ts b/plugins/kubernetes-react/src/components/Pods/types.ts similarity index 92% rename from plugins/kubernetes/src/components/Pods/types.ts rename to plugins/kubernetes-react/src/components/Pods/types.ts index 877df39c24..847e6d63bc 100644 --- a/plugins/kubernetes/src/components/Pods/types.ts +++ b/plugins/kubernetes-react/src/components/Pods/types.ts @@ -14,7 +14,7 @@ * limitations under the License. */ import { Pod } from 'kubernetes-models/v1'; -import { DetectedError } from '../../error-detection'; +import { DetectedError } from '@backstage/plugin-kubernetes-common'; /** * Wraps a pod with the associated detected errors and cluster name diff --git a/plugins/kubernetes/src/components/ResourceUtilization/ResourceUtilization.test.tsx b/plugins/kubernetes-react/src/components/ResourceUtilization/ResourceUtilization.test.tsx similarity index 100% rename from plugins/kubernetes/src/components/ResourceUtilization/ResourceUtilization.test.tsx rename to plugins/kubernetes-react/src/components/ResourceUtilization/ResourceUtilization.test.tsx diff --git a/plugins/kubernetes/src/components/ResourceUtilization/ResourceUtilization.tsx b/plugins/kubernetes-react/src/components/ResourceUtilization/ResourceUtilization.tsx similarity index 96% rename from plugins/kubernetes/src/components/ResourceUtilization/ResourceUtilization.tsx rename to plugins/kubernetes-react/src/components/ResourceUtilization/ResourceUtilization.tsx index 75927958e6..15f906e469 100644 --- a/plugins/kubernetes/src/components/ResourceUtilization/ResourceUtilization.tsx +++ b/plugins/kubernetes-react/src/components/ResourceUtilization/ResourceUtilization.tsx @@ -32,8 +32,7 @@ export interface ResourceUtilizationProps { totalFormatted: string; } -// Visible for testing -export const getProgressColor: GaugePropsGetColor = ({ +const getProgressColor: GaugePropsGetColor = ({ palette, value, inverse, diff --git a/plugins/kubernetes-react/src/components/ResourceUtilization/index.ts b/plugins/kubernetes-react/src/components/ResourceUtilization/index.ts new file mode 100644 index 0000000000..088d78a40b --- /dev/null +++ b/plugins/kubernetes-react/src/components/ResourceUtilization/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export * from './ResourceUtilization'; diff --git a/plugins/kubernetes/src/components/ServicesAccordions/ServiceDrawer.test.tsx b/plugins/kubernetes-react/src/components/ServicesAccordions/ServiceDrawer.test.tsx similarity index 100% rename from plugins/kubernetes/src/components/ServicesAccordions/ServiceDrawer.test.tsx rename to plugins/kubernetes-react/src/components/ServicesAccordions/ServiceDrawer.test.tsx diff --git a/plugins/kubernetes/src/components/ServicesAccordions/ServiceDrawer.tsx b/plugins/kubernetes-react/src/components/ServicesAccordions/ServiceDrawer.tsx similarity index 100% rename from plugins/kubernetes/src/components/ServicesAccordions/ServiceDrawer.tsx rename to plugins/kubernetes-react/src/components/ServicesAccordions/ServiceDrawer.tsx diff --git a/plugins/kubernetes/src/components/ServicesAccordions/ServicesAccordions.test.tsx b/plugins/kubernetes-react/src/components/ServicesAccordions/ServicesAccordions.test.tsx similarity index 100% rename from plugins/kubernetes/src/components/ServicesAccordions/ServicesAccordions.test.tsx rename to plugins/kubernetes-react/src/components/ServicesAccordions/ServicesAccordions.test.tsx diff --git a/plugins/kubernetes/src/components/ServicesAccordions/ServicesAccordions.tsx b/plugins/kubernetes-react/src/components/ServicesAccordions/ServicesAccordions.tsx similarity index 97% rename from plugins/kubernetes/src/components/ServicesAccordions/ServicesAccordions.tsx rename to plugins/kubernetes-react/src/components/ServicesAccordions/ServicesAccordions.tsx index f0cb99ec9c..50d6ec6f3e 100644 --- a/plugins/kubernetes/src/components/ServicesAccordions/ServicesAccordions.tsx +++ b/plugins/kubernetes-react/src/components/ServicesAccordions/ServicesAccordions.tsx @@ -83,7 +83,12 @@ const ServiceCard = ({ service }: ServiceCardProps) => { ); }; -type ServicesAccordionsProps = {}; +/** + * + * + * @public + */ +export type ServicesAccordionsProps = {}; type ServiceAccordionProps = { service: V1Service; @@ -102,6 +107,11 @@ const ServiceAccordion = ({ service }: ServiceAccordionProps) => { ); }; +/** + * + * + * @public + */ export const ServicesAccordions = ({}: ServicesAccordionsProps) => { const groupedResponses = useContext(GroupedResponsesContext); return ( diff --git a/plugins/kubernetes/src/components/ServicesAccordions/__fixtures__/2-services.json b/plugins/kubernetes-react/src/components/ServicesAccordions/__fixtures__/2-services.json similarity index 100% rename from plugins/kubernetes/src/components/ServicesAccordions/__fixtures__/2-services.json rename to plugins/kubernetes-react/src/components/ServicesAccordions/__fixtures__/2-services.json diff --git a/plugins/kubernetes-react/src/components/ServicesAccordions/index.ts b/plugins/kubernetes-react/src/components/ServicesAccordions/index.ts new file mode 100644 index 0000000000..db37d34b5f --- /dev/null +++ b/plugins/kubernetes-react/src/components/ServicesAccordions/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 './ServicesAccordions'; diff --git a/plugins/kubernetes/src/components/StatefulSetsAccordions/StatefulSetDrawer.test.tsx b/plugins/kubernetes-react/src/components/StatefulSetsAccordions/StatefulSetDrawer.test.tsx similarity index 100% rename from plugins/kubernetes/src/components/StatefulSetsAccordions/StatefulSetDrawer.test.tsx rename to plugins/kubernetes-react/src/components/StatefulSetsAccordions/StatefulSetDrawer.test.tsx diff --git a/plugins/kubernetes/src/components/StatefulSetsAccordions/StatefulSetDrawer.tsx b/plugins/kubernetes-react/src/components/StatefulSetsAccordions/StatefulSetDrawer.tsx similarity index 100% rename from plugins/kubernetes/src/components/StatefulSetsAccordions/StatefulSetDrawer.tsx rename to plugins/kubernetes-react/src/components/StatefulSetsAccordions/StatefulSetDrawer.tsx diff --git a/plugins/kubernetes/src/components/StatefulSetsAccordions/StatefulSetsAccordions.test.tsx b/plugins/kubernetes-react/src/components/StatefulSetsAccordions/StatefulSetsAccordions.test.tsx similarity index 100% rename from plugins/kubernetes/src/components/StatefulSetsAccordions/StatefulSetsAccordions.test.tsx rename to plugins/kubernetes-react/src/components/StatefulSetsAccordions/StatefulSetsAccordions.test.tsx diff --git a/plugins/kubernetes/src/components/StatefulSetsAccordions/StatefulSetsAccordions.tsx b/plugins/kubernetes-react/src/components/StatefulSetsAccordions/StatefulSetsAccordions.tsx similarity index 100% rename from plugins/kubernetes/src/components/StatefulSetsAccordions/StatefulSetsAccordions.tsx rename to plugins/kubernetes-react/src/components/StatefulSetsAccordions/StatefulSetsAccordions.tsx diff --git a/plugins/kubernetes/src/components/StatefulSetsAccordions/index.ts b/plugins/kubernetes-react/src/components/StatefulSetsAccordions/index.ts similarity index 100% rename from plugins/kubernetes/src/components/StatefulSetsAccordions/index.ts rename to plugins/kubernetes-react/src/components/StatefulSetsAccordions/index.ts diff --git a/plugins/kubernetes/src/components/index.ts b/plugins/kubernetes-react/src/components/index.ts similarity index 96% rename from plugins/kubernetes/src/components/index.ts rename to plugins/kubernetes-react/src/components/index.ts index 18b75247e5..d9cebe35a3 100644 --- a/plugins/kubernetes/src/components/index.ts +++ b/plugins/kubernetes-react/src/components/index.ts @@ -25,6 +25,5 @@ export * from './JobsAccordions'; export * from './KubernetesDrawer'; export * from './Pods'; export * from './ServicesAccordions'; -export * from './KubernetesContent'; export * from './ResourceUtilization'; export * from './PodExecTerminal'; diff --git a/plugins/kubernetes/src/hooks/Cluster.ts b/plugins/kubernetes-react/src/hooks/Cluster.ts similarity index 97% rename from plugins/kubernetes/src/hooks/Cluster.ts rename to plugins/kubernetes-react/src/hooks/Cluster.ts index e8d01c462c..ee950b7f4d 100644 --- a/plugins/kubernetes/src/hooks/Cluster.ts +++ b/plugins/kubernetes-react/src/hooks/Cluster.ts @@ -16,6 +16,9 @@ import React from 'react'; import { ClusterAttributes } from '@backstage/plugin-kubernetes-common'; +/** + * @public + */ export const ClusterContext = React.createContext<ClusterAttributes>({ name: '', }); diff --git a/plugins/kubernetes/src/hooks/GroupedResponses.ts b/plugins/kubernetes-react/src/hooks/GroupedResponses.ts similarity index 90% rename from plugins/kubernetes/src/hooks/GroupedResponses.ts rename to plugins/kubernetes-react/src/hooks/GroupedResponses.ts index 8383c9e1d9..7a81a74337 100644 --- a/plugins/kubernetes/src/hooks/GroupedResponses.ts +++ b/plugins/kubernetes-react/src/hooks/GroupedResponses.ts @@ -14,8 +14,13 @@ * limitations under the License. */ import React from 'react'; -import { GroupedResponses } from '../types/types'; +import { GroupedResponses } from '@backstage/plugin-kubernetes-common'; +/** + * + * + * @public + */ export const GroupedResponsesContext = React.createContext<GroupedResponses>({ pods: [], replicaSets: [], diff --git a/plugins/kubernetes/src/hooks/PodNamesWithErrors.ts b/plugins/kubernetes-react/src/hooks/PodNamesWithErrors.ts similarity index 97% rename from plugins/kubernetes/src/hooks/PodNamesWithErrors.ts rename to plugins/kubernetes-react/src/hooks/PodNamesWithErrors.ts index 7505da3fd2..001a40805f 100644 --- a/plugins/kubernetes/src/hooks/PodNamesWithErrors.ts +++ b/plugins/kubernetes-react/src/hooks/PodNamesWithErrors.ts @@ -15,6 +15,9 @@ */ import React from 'react'; +/** + * @public + */ export const PodNamesWithErrorsContext = React.createContext<Set<string>>( new Set<string>(), ); diff --git a/plugins/kubernetes/src/hooks/PodNamesWithMetrics.ts b/plugins/kubernetes-react/src/hooks/PodNamesWithMetrics.ts similarity index 97% rename from plugins/kubernetes/src/hooks/PodNamesWithMetrics.ts rename to plugins/kubernetes-react/src/hooks/PodNamesWithMetrics.ts index 0df42a8ab0..12da138cfb 100644 --- a/plugins/kubernetes/src/hooks/PodNamesWithMetrics.ts +++ b/plugins/kubernetes-react/src/hooks/PodNamesWithMetrics.ts @@ -16,8 +16,8 @@ import React from 'react'; import { ClientPodStatus } from '@backstage/plugin-kubernetes-common'; -/* - * @deprecated +/** + * @public */ export const PodNamesWithMetricsContext = React.createContext< Map<string, ClientPodStatus> diff --git a/plugins/kubernetes/src/hooks/__mocks__/useIsPodExecTerminalSupported.ts b/plugins/kubernetes-react/src/hooks/__mocks__/useIsPodExecTerminalSupported.ts similarity index 100% rename from plugins/kubernetes/src/hooks/__mocks__/useIsPodExecTerminalSupported.ts rename to plugins/kubernetes-react/src/hooks/__mocks__/useIsPodExecTerminalSupported.ts diff --git a/plugins/kubernetes/src/hooks/auth.test.ts b/plugins/kubernetes-react/src/hooks/auth.test.ts similarity index 100% rename from plugins/kubernetes/src/hooks/auth.test.ts rename to plugins/kubernetes-react/src/hooks/auth.test.ts diff --git a/plugins/kubernetes/src/hooks/auth.ts b/plugins/kubernetes-react/src/hooks/auth.ts similarity index 98% rename from plugins/kubernetes/src/hooks/auth.ts rename to plugins/kubernetes-react/src/hooks/auth.ts index cce0bc27d6..76e08f2783 100644 --- a/plugins/kubernetes/src/hooks/auth.ts +++ b/plugins/kubernetes-react/src/hooks/auth.ts @@ -15,9 +15,9 @@ */ import { Entity } from '@backstage/catalog-model'; -import { KubernetesApi } from '../api/types'; -import { KubernetesAuthProvidersApi } from '../kubernetes-auth-provider/types'; import { KubernetesRequestBody } from '@backstage/plugin-kubernetes-common'; +import { KubernetesAuthProvidersApi } from '../kubernetes-auth-provider'; +import { KubernetesApi } from '../api/types'; export const generateAuth = async ( entity: Entity, diff --git a/plugins/kubernetes/src/hooks/index.ts b/plugins/kubernetes-react/src/hooks/index.ts similarity index 100% rename from plugins/kubernetes/src/hooks/index.ts rename to plugins/kubernetes-react/src/hooks/index.ts diff --git a/plugins/kubernetes/src/hooks/test-utils.tsx b/plugins/kubernetes-react/src/hooks/test-utils.tsx similarity index 100% rename from plugins/kubernetes/src/hooks/test-utils.tsx rename to plugins/kubernetes-react/src/hooks/test-utils.tsx diff --git a/plugins/kubernetes/src/hooks/types.ts b/plugins/kubernetes-react/src/hooks/types.ts similarity index 100% rename from plugins/kubernetes/src/hooks/types.ts rename to plugins/kubernetes-react/src/hooks/types.ts diff --git a/plugins/kubernetes/src/hooks/useCustomResources.test.ts b/plugins/kubernetes-react/src/hooks/useCustomResources.test.ts similarity index 100% rename from plugins/kubernetes/src/hooks/useCustomResources.test.ts rename to plugins/kubernetes-react/src/hooks/useCustomResources.test.ts diff --git a/plugins/kubernetes/src/hooks/useCustomResources.ts b/plugins/kubernetes-react/src/hooks/useCustomResources.ts similarity index 99% rename from plugins/kubernetes/src/hooks/useCustomResources.ts rename to plugins/kubernetes-react/src/hooks/useCustomResources.ts index c53e00d81c..4faeb48894 100644 --- a/plugins/kubernetes/src/hooks/useCustomResources.ts +++ b/plugins/kubernetes-react/src/hooks/useCustomResources.ts @@ -15,8 +15,6 @@ */ import { Entity } from '@backstage/catalog-model'; -import { kubernetesApiRef } from '../api/types'; -import { kubernetesAuthProvidersApiRef } from '../kubernetes-auth-provider/types'; import { useCallback } from 'react'; import useInterval from 'react-use/lib/useInterval'; import { @@ -27,6 +25,8 @@ import { useApi } from '@backstage/core-plugin-api'; import { KubernetesObjects } from './useKubernetesObjects'; import { generateAuth } from './auth'; import useAsyncRetry from 'react-use/lib/useAsyncRetry'; +import { kubernetesAuthProvidersApiRef } from '../kubernetes-auth-provider'; +import { kubernetesApiRef } from '../api/types'; /** * Retrieves the provided custom resources related to the provided entity, refreshes at an interval. diff --git a/plugins/kubernetes/src/hooks/useIsPodExecTerminalSupported.test.ts b/plugins/kubernetes-react/src/hooks/useIsPodExecTerminalSupported.test.ts similarity index 100% rename from plugins/kubernetes/src/hooks/useIsPodExecTerminalSupported.test.ts rename to plugins/kubernetes-react/src/hooks/useIsPodExecTerminalSupported.test.ts diff --git a/plugins/kubernetes/src/hooks/useIsPodExecTerminalSupported.ts b/plugins/kubernetes-react/src/hooks/useIsPodExecTerminalSupported.ts similarity index 96% rename from plugins/kubernetes/src/hooks/useIsPodExecTerminalSupported.ts rename to plugins/kubernetes-react/src/hooks/useIsPodExecTerminalSupported.ts index 17f64bf0dd..e881951059 100644 --- a/plugins/kubernetes/src/hooks/useIsPodExecTerminalSupported.ts +++ b/plugins/kubernetes-react/src/hooks/useIsPodExecTerminalSupported.ts @@ -15,8 +15,7 @@ */ import { useApi } from '@backstage/core-plugin-api'; import useAsync, { AsyncState } from 'react-use/lib/useAsync'; - -import { kubernetesApiRef } from '../api'; +import { kubernetesApiRef } from '../api/types'; /** * Check if conditions for a pod exec call through the proxy endpoint are met diff --git a/plugins/kubernetes/src/hooks/useKubernetesObjects.test.ts b/plugins/kubernetes-react/src/hooks/useKubernetesObjects.test.ts similarity index 100% rename from plugins/kubernetes/src/hooks/useKubernetesObjects.test.ts rename to plugins/kubernetes-react/src/hooks/useKubernetesObjects.test.ts diff --git a/plugins/kubernetes/src/hooks/useKubernetesObjects.ts b/plugins/kubernetes-react/src/hooks/useKubernetesObjects.ts similarity index 97% rename from plugins/kubernetes/src/hooks/useKubernetesObjects.ts rename to plugins/kubernetes-react/src/hooks/useKubernetesObjects.ts index aad2f48fd3..f2b8de3cc6 100644 --- a/plugins/kubernetes/src/hooks/useKubernetesObjects.ts +++ b/plugins/kubernetes-react/src/hooks/useKubernetesObjects.ts @@ -15,21 +15,29 @@ */ import { Entity } from '@backstage/catalog-model'; -import { kubernetesApiRef } from '../api/types'; -import { kubernetesAuthProvidersApiRef } from '../kubernetes-auth-provider/types'; import { useCallback } from 'react'; import useInterval from 'react-use/lib/useInterval'; import { ObjectsByEntityResponse } from '@backstage/plugin-kubernetes-common'; import { useApi } from '@backstage/core-plugin-api'; import { generateAuth } from './auth'; import useAsyncRetry from 'react-use/lib/useAsyncRetry'; +import { kubernetesAuthProvidersApiRef } from '../kubernetes-auth-provider'; +import { kubernetesApiRef } from '../api/types'; +/** + * + * @public + */ export interface KubernetesObjects { kubernetesObjects?: ObjectsByEntityResponse; loading: boolean; error?: string; } +/** + * + * @public + */ export const useKubernetesObjects = ( entity: Entity, intervalMs: number = 10000, diff --git a/plugins/kubernetes/src/hooks/useMatchingErrors.test.tsx b/plugins/kubernetes-react/src/hooks/useMatchingErrors.test.tsx similarity index 95% rename from plugins/kubernetes/src/hooks/useMatchingErrors.test.tsx rename to plugins/kubernetes-react/src/hooks/useMatchingErrors.test.tsx index 4ed4dbd73c..4d817e838d 100644 --- a/plugins/kubernetes/src/hooks/useMatchingErrors.test.tsx +++ b/plugins/kubernetes-react/src/hooks/useMatchingErrors.test.tsx @@ -16,8 +16,10 @@ import React from 'react'; import { renderHook } from '@testing-library/react-hooks'; import { DetectedErrorsContext, useMatchingErrors } from './useMatchingErrors'; -import { DetectedError } from '../error-detection'; -import { ResourceRef } from '../error-detection/types'; +import { + DetectedError, + ResourceRef, +} from '@backstage/plugin-kubernetes-common'; const genericErrorWithRef = (resourceRef: ResourceRef): DetectedError => { return { diff --git a/plugins/kubernetes/src/hooks/useMatchingErrors.ts b/plugins/kubernetes-react/src/hooks/useMatchingErrors.ts similarity index 95% rename from plugins/kubernetes/src/hooks/useMatchingErrors.ts rename to plugins/kubernetes-react/src/hooks/useMatchingErrors.ts index aa90d52cbb..1975065b7b 100644 --- a/plugins/kubernetes/src/hooks/useMatchingErrors.ts +++ b/plugins/kubernetes-react/src/hooks/useMatchingErrors.ts @@ -14,7 +14,10 @@ * limitations under the License. */ import React, { useContext } from 'react'; -import { DetectedError, ResourceRef } from '../error-detection/types'; +import { + DetectedError, + ResourceRef, +} from '@backstage/plugin-kubernetes-common'; import { TypeMeta } from '@kubernetes-models/base'; import { IIoK8sApimachineryPkgApisMetaV1ObjectMeta as V1ObjectMeta } from '@kubernetes-models/apimachinery/apis/meta/v1/ObjectMeta'; diff --git a/plugins/kubernetes/src/hooks/usePodMetrics.test.tsx b/plugins/kubernetes-react/src/hooks/usePodMetrics.test.tsx similarity index 100% rename from plugins/kubernetes/src/hooks/usePodMetrics.test.tsx rename to plugins/kubernetes-react/src/hooks/usePodMetrics.test.tsx diff --git a/plugins/kubernetes/src/hooks/usePodMetrics.ts b/plugins/kubernetes-react/src/hooks/usePodMetrics.ts similarity index 99% rename from plugins/kubernetes/src/hooks/usePodMetrics.ts rename to plugins/kubernetes-react/src/hooks/usePodMetrics.ts index 4392487cac..6d3c52690f 100644 --- a/plugins/kubernetes/src/hooks/usePodMetrics.ts +++ b/plugins/kubernetes-react/src/hooks/usePodMetrics.ts @@ -26,8 +26,8 @@ export const PodMetricsContext = React.createContext< Map<string, ClientPodStatus[]> >(new Map()); -/* - * @alpha +/** + * @public */ export type PodMetricsMatcher = { metadata?: IObjectMeta; diff --git a/plugins/catalog/src/options.ts b/plugins/kubernetes-react/src/index.ts similarity index 61% rename from plugins/catalog/src/options.ts rename to plugins/kubernetes-react/src/index.ts index 4ea6449a4b..e5c84eab79 100644 --- a/plugins/catalog/src/options.ts +++ b/plugins/kubernetes-react/src/index.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Backstage Authors + * Copyright 2023 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,16 +14,16 @@ * limitations under the License. */ -import { usePluginOptions } from '@backstage/core-plugin-api/alpha'; +/** + * Web library for the kubernetes-react plugin. + * + * @packageDocumentation + */ -export type CatalogPluginOptions = { - createButtonTitle: string; -}; +// In this package you might for example export components or hooks +// that are useful to other plugins or modules. -/** @ignore */ -export type CatalogInputPluginOptions = { - createButtonTitle: string; -}; - -export const useCatalogPluginOptions = () => - usePluginOptions<CatalogPluginOptions>(); +export * from './hooks'; +export * from './api'; +export * from './kubernetes-auth-provider'; +export * from './components'; diff --git a/plugins/kubernetes/src/kubernetes-auth-provider/AksKubernetesAuthProvider.ts b/plugins/kubernetes-react/src/kubernetes-auth-provider/AksKubernetesAuthProvider.ts similarity index 98% rename from plugins/kubernetes/src/kubernetes-auth-provider/AksKubernetesAuthProvider.ts rename to plugins/kubernetes-react/src/kubernetes-auth-provider/AksKubernetesAuthProvider.ts index 401fc1e127..34a83dfed3 100644 --- a/plugins/kubernetes/src/kubernetes-auth-provider/AksKubernetesAuthProvider.ts +++ b/plugins/kubernetes-react/src/kubernetes-auth-provider/AksKubernetesAuthProvider.ts @@ -17,6 +17,7 @@ import { OAuthApi } from '@backstage/core-plugin-api'; import { KubernetesRequestBody } from '@backstage/plugin-kubernetes-common'; import { KubernetesAuthProvider } from './types'; +/** @public */ export class AksKubernetesAuthProvider implements KubernetesAuthProvider { constructor(private readonly microsoftAuthApi: OAuthApi) {} diff --git a/plugins/kubernetes/src/kubernetes-auth-provider/GoogleKubernetesAuthProvider.ts b/plugins/kubernetes-react/src/kubernetes-auth-provider/GoogleKubernetesAuthProvider.ts similarity index 99% rename from plugins/kubernetes/src/kubernetes-auth-provider/GoogleKubernetesAuthProvider.ts rename to plugins/kubernetes-react/src/kubernetes-auth-provider/GoogleKubernetesAuthProvider.ts index fbce644a89..9d7259b70e 100644 --- a/plugins/kubernetes/src/kubernetes-auth-provider/GoogleKubernetesAuthProvider.ts +++ b/plugins/kubernetes-react/src/kubernetes-auth-provider/GoogleKubernetesAuthProvider.ts @@ -18,6 +18,7 @@ import { KubernetesAuthProvider } from './types'; import { KubernetesRequestBody } from '@backstage/plugin-kubernetes-common'; import { OAuthApi } from '@backstage/core-plugin-api'; +/** @public */ export class GoogleKubernetesAuthProvider implements KubernetesAuthProvider { authProvider: OAuthApi; diff --git a/plugins/kubernetes/src/kubernetes-auth-provider/KubernetesAuthProviders.test.ts b/plugins/kubernetes-react/src/kubernetes-auth-provider/KubernetesAuthProviders.test.ts similarity index 100% rename from plugins/kubernetes/src/kubernetes-auth-provider/KubernetesAuthProviders.test.ts rename to plugins/kubernetes-react/src/kubernetes-auth-provider/KubernetesAuthProviders.test.ts diff --git a/plugins/kubernetes/src/kubernetes-auth-provider/KubernetesAuthProviders.ts b/plugins/kubernetes-react/src/kubernetes-auth-provider/KubernetesAuthProviders.ts similarity index 99% rename from plugins/kubernetes/src/kubernetes-auth-provider/KubernetesAuthProviders.ts rename to plugins/kubernetes-react/src/kubernetes-auth-provider/KubernetesAuthProviders.ts index 84154d5e96..77a7b156d7 100644 --- a/plugins/kubernetes/src/kubernetes-auth-provider/KubernetesAuthProviders.ts +++ b/plugins/kubernetes-react/src/kubernetes-auth-provider/KubernetesAuthProviders.ts @@ -22,6 +22,7 @@ import { OAuthApi, OpenIdConnectApi } from '@backstage/core-plugin-api'; import { OidcKubernetesAuthProvider } from './OidcKubernetesAuthProvider'; import { AksKubernetesAuthProvider } from './AksKubernetesAuthProvider'; +/** @public */ export class KubernetesAuthProviders implements KubernetesAuthProvidersApi { private readonly kubernetesAuthProviderMap: Map< string, diff --git a/plugins/kubernetes/src/kubernetes-auth-provider/OidcKubernetesAuthProvider.ts b/plugins/kubernetes-react/src/kubernetes-auth-provider/OidcKubernetesAuthProvider.ts similarity index 99% rename from plugins/kubernetes/src/kubernetes-auth-provider/OidcKubernetesAuthProvider.ts rename to plugins/kubernetes-react/src/kubernetes-auth-provider/OidcKubernetesAuthProvider.ts index b2e6c5cbc2..c117200f56 100644 --- a/plugins/kubernetes/src/kubernetes-auth-provider/OidcKubernetesAuthProvider.ts +++ b/plugins/kubernetes-react/src/kubernetes-auth-provider/OidcKubernetesAuthProvider.ts @@ -19,6 +19,7 @@ import { KubernetesRequestBody } from '@backstage/plugin-kubernetes-common'; import { OpenIdConnectApi } from '@backstage/core-plugin-api'; import { KubernetesAuthProvider } from './types'; +/** @public */ export class OidcKubernetesAuthProvider implements KubernetesAuthProvider { providerName: string; authProvider: OpenIdConnectApi; diff --git a/plugins/kubernetes/src/kubernetes-auth-provider/ServerSideAuthProvider.ts b/plugins/kubernetes-react/src/kubernetes-auth-provider/ServerSideAuthProvider.ts similarity index 100% rename from plugins/kubernetes/src/kubernetes-auth-provider/ServerSideAuthProvider.ts rename to plugins/kubernetes-react/src/kubernetes-auth-provider/ServerSideAuthProvider.ts diff --git a/plugins/kubernetes/src/error-detection/index.ts b/plugins/kubernetes-react/src/kubernetes-auth-provider/index.ts similarity index 70% rename from plugins/kubernetes/src/error-detection/index.ts rename to plugins/kubernetes-react/src/kubernetes-auth-provider/index.ts index 3a8789d79d..5ab8b0be43 100644 --- a/plugins/kubernetes/src/error-detection/index.ts +++ b/plugins/kubernetes-react/src/kubernetes-auth-provider/index.ts @@ -14,10 +14,9 @@ * limitations under the License. */ -export type { - DetectedError, - DetectedErrorsByCluster, - ErrorSeverity, - ResourceRef, -} from './types'; -export { detectErrors } from './error-detection'; +export * from './types'; +export * from './KubernetesAuthProviders'; +export * from './GoogleKubernetesAuthProvider'; +export * from './ServerSideAuthProvider'; +export * from './OidcKubernetesAuthProvider'; +export * from './AksKubernetesAuthProvider'; diff --git a/plugins/kubernetes/src/kubernetes-auth-provider/types.ts b/plugins/kubernetes-react/src/kubernetes-auth-provider/types.ts similarity index 96% rename from plugins/kubernetes/src/kubernetes-auth-provider/types.ts rename to plugins/kubernetes-react/src/kubernetes-auth-provider/types.ts index 418758dd31..adf323d1d8 100644 --- a/plugins/kubernetes/src/kubernetes-auth-provider/types.ts +++ b/plugins/kubernetes-react/src/kubernetes-auth-provider/types.ts @@ -17,6 +17,7 @@ import { KubernetesRequestBody } from '@backstage/plugin-kubernetes-common'; import { createApiRef } from '@backstage/core-plugin-api'; +/** @public */ export interface KubernetesAuthProvider { decorateRequestBodyForAuth( requestBody: KubernetesRequestBody, @@ -24,11 +25,13 @@ export interface KubernetesAuthProvider { getCredentials(): Promise<{ token?: string }>; } +/** @public */ export const kubernetesAuthProvidersApiRef = createApiRef<KubernetesAuthProvidersApi>({ id: 'plugin.kubernetes-auth-providers.service', }); +/** @public */ export interface KubernetesAuthProvidersApi { decorateRequestBodyForAuth( authProvider: string, diff --git a/plugins/kubernetes-react/src/setupTests.ts b/plugins/kubernetes-react/src/setupTests.ts new file mode 100644 index 0000000000..865308e634 --- /dev/null +++ b/plugins/kubernetes-react/src/setupTests.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import '@testing-library/jest-dom'; diff --git a/plugins/kubernetes/src/types/index.ts b/plugins/kubernetes-react/src/types/index.ts similarity index 100% rename from plugins/kubernetes/src/types/index.ts rename to plugins/kubernetes-react/src/types/index.ts diff --git a/packages/backend-common/src/discovery/types.ts b/plugins/kubernetes-react/src/types/types.ts similarity index 68% rename from packages/backend-common/src/discovery/types.ts rename to plugins/kubernetes-react/src/types/types.ts index 3ecdb7aa39..7efd1ef3ff 100644 --- a/packages/backend-common/src/discovery/types.ts +++ b/plugins/kubernetes-react/src/types/types.ts @@ -14,4 +14,15 @@ * limitations under the License. */ -export type { DiscoveryService as PluginEndpointDiscovery } from '@backstage/backend-plugin-api'; +import type { JsonObject } from '@backstage/types'; + +export interface ClusterLinksFormatterOptions { + dashboardUrl?: URL; + dashboardParameters?: JsonObject; + object: any; + kind: string; +} + +export type ClusterLinksFormatter = ( + options: ClusterLinksFormatterOptions, +) => URL; diff --git a/plugins/kubernetes/src/utils/clusterLinks/formatClusterLink.test.ts b/plugins/kubernetes-react/src/utils/clusterLinks/formatClusterLink.test.ts similarity index 100% rename from plugins/kubernetes/src/utils/clusterLinks/formatClusterLink.test.ts rename to plugins/kubernetes-react/src/utils/clusterLinks/formatClusterLink.test.ts diff --git a/plugins/kubernetes/src/utils/clusterLinks/formatClusterLink.ts b/plugins/kubernetes-react/src/utils/clusterLinks/formatClusterLink.ts similarity index 90% rename from plugins/kubernetes/src/utils/clusterLinks/formatClusterLink.ts rename to plugins/kubernetes-react/src/utils/clusterLinks/formatClusterLink.ts index 6a998bbce2..ae3bdb950f 100644 --- a/plugins/kubernetes/src/utils/clusterLinks/formatClusterLink.ts +++ b/plugins/kubernetes-react/src/utils/clusterLinks/formatClusterLink.ts @@ -17,6 +17,7 @@ import type { JsonObject } from '@backstage/types'; import { defaultFormatterName, clusterLinksFormatters } from './formatters'; +// @Deprecated use import { FormatClusterLinkOptions } from '@backstage/kubernetes-react' export type FormatClusterLinkOptions = { dashboardUrl?: string; dashboardApp?: string; @@ -25,6 +26,7 @@ export type FormatClusterLinkOptions = { kind: string; }; +// @Deprecated use import { formatClusterLink } from '@backstage/kubernetes-react' export function formatClusterLink(options: FormatClusterLinkOptions) { if (!options.dashboardUrl && !options.dashboardParameters) { return undefined; diff --git a/plugins/kubernetes/src/utils/clusterLinks/formatters/aks.test.ts b/plugins/kubernetes-react/src/utils/clusterLinks/formatters/aks.test.ts similarity index 100% rename from plugins/kubernetes/src/utils/clusterLinks/formatters/aks.test.ts rename to plugins/kubernetes-react/src/utils/clusterLinks/formatters/aks.test.ts diff --git a/plugins/kubernetes/src/utils/clusterLinks/formatters/aks.ts b/plugins/kubernetes-react/src/utils/clusterLinks/formatters/aks.ts similarity index 100% rename from plugins/kubernetes/src/utils/clusterLinks/formatters/aks.ts rename to plugins/kubernetes-react/src/utils/clusterLinks/formatters/aks.ts diff --git a/plugins/kubernetes/src/utils/clusterLinks/formatters/eks.test.ts b/plugins/kubernetes-react/src/utils/clusterLinks/formatters/eks.test.ts similarity index 100% rename from plugins/kubernetes/src/utils/clusterLinks/formatters/eks.test.ts rename to plugins/kubernetes-react/src/utils/clusterLinks/formatters/eks.test.ts diff --git a/plugins/kubernetes/src/utils/clusterLinks/formatters/eks.ts b/plugins/kubernetes-react/src/utils/clusterLinks/formatters/eks.ts similarity index 100% rename from plugins/kubernetes/src/utils/clusterLinks/formatters/eks.ts rename to plugins/kubernetes-react/src/utils/clusterLinks/formatters/eks.ts diff --git a/plugins/kubernetes/src/utils/clusterLinks/formatters/gke.test.ts b/plugins/kubernetes-react/src/utils/clusterLinks/formatters/gke.test.ts similarity index 100% rename from plugins/kubernetes/src/utils/clusterLinks/formatters/gke.test.ts rename to plugins/kubernetes-react/src/utils/clusterLinks/formatters/gke.test.ts diff --git a/plugins/kubernetes/src/utils/clusterLinks/formatters/gke.ts b/plugins/kubernetes-react/src/utils/clusterLinks/formatters/gke.ts similarity index 100% rename from plugins/kubernetes/src/utils/clusterLinks/formatters/gke.ts rename to plugins/kubernetes-react/src/utils/clusterLinks/formatters/gke.ts diff --git a/plugins/kubernetes/src/utils/clusterLinks/formatters/index.ts b/plugins/kubernetes-react/src/utils/clusterLinks/formatters/index.ts similarity index 100% rename from plugins/kubernetes/src/utils/clusterLinks/formatters/index.ts rename to plugins/kubernetes-react/src/utils/clusterLinks/formatters/index.ts diff --git a/plugins/kubernetes/src/utils/clusterLinks/formatters/openshift.test.ts b/plugins/kubernetes-react/src/utils/clusterLinks/formatters/openshift.test.ts similarity index 100% rename from plugins/kubernetes/src/utils/clusterLinks/formatters/openshift.test.ts rename to plugins/kubernetes-react/src/utils/clusterLinks/formatters/openshift.test.ts diff --git a/plugins/kubernetes/src/utils/clusterLinks/formatters/openshift.ts b/plugins/kubernetes-react/src/utils/clusterLinks/formatters/openshift.ts similarity index 100% rename from plugins/kubernetes/src/utils/clusterLinks/formatters/openshift.ts rename to plugins/kubernetes-react/src/utils/clusterLinks/formatters/openshift.ts diff --git a/plugins/kubernetes/src/utils/clusterLinks/formatters/rancher.test.ts b/plugins/kubernetes-react/src/utils/clusterLinks/formatters/rancher.test.ts similarity index 100% rename from plugins/kubernetes/src/utils/clusterLinks/formatters/rancher.test.ts rename to plugins/kubernetes-react/src/utils/clusterLinks/formatters/rancher.test.ts diff --git a/plugins/kubernetes/src/utils/clusterLinks/formatters/rancher.ts b/plugins/kubernetes-react/src/utils/clusterLinks/formatters/rancher.ts similarity index 100% rename from plugins/kubernetes/src/utils/clusterLinks/formatters/rancher.ts rename to plugins/kubernetes-react/src/utils/clusterLinks/formatters/rancher.ts diff --git a/plugins/kubernetes/src/utils/clusterLinks/formatters/standard.test.ts b/plugins/kubernetes-react/src/utils/clusterLinks/formatters/standard.test.ts similarity index 100% rename from plugins/kubernetes/src/utils/clusterLinks/formatters/standard.test.ts rename to plugins/kubernetes-react/src/utils/clusterLinks/formatters/standard.test.ts diff --git a/plugins/kubernetes/src/utils/clusterLinks/formatters/standard.ts b/plugins/kubernetes-react/src/utils/clusterLinks/formatters/standard.ts similarity index 100% rename from plugins/kubernetes/src/utils/clusterLinks/formatters/standard.ts rename to plugins/kubernetes-react/src/utils/clusterLinks/formatters/standard.ts diff --git a/plugins/kubernetes/src/utils/clusterLinks/index.ts b/plugins/kubernetes-react/src/utils/clusterLinks/index.ts similarity index 100% rename from plugins/kubernetes/src/utils/clusterLinks/index.ts rename to plugins/kubernetes-react/src/utils/clusterLinks/index.ts diff --git a/plugins/kubernetes/src/utils/crons.test.ts b/plugins/kubernetes-react/src/utils/crons.test.ts similarity index 100% rename from plugins/kubernetes/src/utils/crons.test.ts rename to plugins/kubernetes-react/src/utils/crons.test.ts diff --git a/plugins/kubernetes/src/utils/crons.ts b/plugins/kubernetes-react/src/utils/crons.ts similarity index 100% rename from plugins/kubernetes/src/utils/crons.ts rename to plugins/kubernetes-react/src/utils/crons.ts diff --git a/plugins/kubernetes/src/utils/index.ts b/plugins/kubernetes-react/src/utils/index.ts similarity index 100% rename from plugins/kubernetes/src/utils/index.ts rename to plugins/kubernetes-react/src/utils/index.ts diff --git a/plugins/kubernetes/src/utils/owner.test.ts b/plugins/kubernetes-react/src/utils/owner.test.ts similarity index 100% rename from plugins/kubernetes/src/utils/owner.test.ts rename to plugins/kubernetes-react/src/utils/owner.test.ts diff --git a/plugins/kubernetes/src/utils/owner.ts b/plugins/kubernetes-react/src/utils/owner.ts similarity index 100% rename from plugins/kubernetes/src/utils/owner.ts rename to plugins/kubernetes-react/src/utils/owner.ts diff --git a/plugins/kubernetes/src/utils/pod.test.tsx b/plugins/kubernetes-react/src/utils/pod.test.tsx similarity index 100% rename from plugins/kubernetes/src/utils/pod.test.tsx rename to plugins/kubernetes-react/src/utils/pod.test.tsx diff --git a/plugins/kubernetes/src/utils/pod.tsx b/plugins/kubernetes-react/src/utils/pod.tsx similarity index 100% rename from plugins/kubernetes/src/utils/pod.tsx rename to plugins/kubernetes-react/src/utils/pod.tsx diff --git a/plugins/kubernetes/src/utils/resources.ts b/plugins/kubernetes-react/src/utils/resources.ts similarity index 100% rename from plugins/kubernetes/src/utils/resources.ts rename to plugins/kubernetes-react/src/utils/resources.ts diff --git a/plugins/kubernetes/CHANGELOG.md b/plugins/kubernetes/CHANGELOG.md index 3bc309c060..55fda1b465 100644 --- a/plugins/kubernetes/CHANGELOG.md +++ b/plugins/kubernetes/CHANGELOG.md @@ -1,5 +1,40 @@ # @backstage/plugin-kubernetes +## 0.11.0-next.1 + +### Minor Changes + +- 2d8151061c: Refactor Kubernetes plugins in line with ADR 11, no breaking changes yet + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-kubernetes-common@0.7.0-next.0 + - @backstage/plugin-kubernetes-react@0.1.0-next.0 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + +## 0.10.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + - @backstage/plugin-kubernetes-common@0.6.6 + ## 0.10.3 ### Patch Changes diff --git a/plugins/kubernetes/api-report.md b/plugins/kubernetes/api-report.md index 77ec8dd19c..64b56cf786 100644 --- a/plugins/kubernetes/api-report.md +++ b/plugins/kubernetes/api-report.md @@ -5,162 +5,10 @@ ```ts /// <reference types="react" /> -import { ApiRef } from '@backstage/core-plugin-api'; -import { AsyncState } from 'react-use/lib/useAsyncFn'; import { BackstagePlugin } from '@backstage/core-plugin-api'; -import { ClientContainerStatus } from '@backstage/plugin-kubernetes-common'; -import { ClientPodStatus } from '@backstage/plugin-kubernetes-common'; -import { ClusterAttributes } from '@backstage/plugin-kubernetes-common'; -import { ClusterObjects } from '@backstage/plugin-kubernetes-common'; -import { CustomObjectsByEntityRequest } from '@backstage/plugin-kubernetes-common'; -import { CustomResourceMatcher } from '@backstage/plugin-kubernetes-common'; -import { DiscoveryApi } from '@backstage/core-plugin-api'; import { Entity } from '@backstage/catalog-model'; -import { Event as Event_2 } from 'kubernetes-models/v1'; -import { IContainer } from 'kubernetes-models/v1'; -import { IContainerStatus } from 'kubernetes-models/v1'; -import { IdentityApi } from '@backstage/core-plugin-api'; -import { IIoK8sApimachineryPkgApisMetaV1ObjectMeta } from '@kubernetes-models/apimachinery/apis/meta/v1/ObjectMeta'; -import { IObjectMeta } from '@kubernetes-models/apimachinery/apis/meta/v1/ObjectMeta'; -import type { JsonObject } from '@backstage/types'; -import { KubernetesRequestBody } from '@backstage/plugin-kubernetes-common'; -import { OAuthApi } from '@backstage/core-plugin-api'; -import { ObjectsByEntityResponse } from '@backstage/plugin-kubernetes-common'; -import { OpenIdConnectApi } from '@backstage/core-plugin-api'; -import { Pod } from 'kubernetes-models/v1/Pod'; -import { Pod as Pod_2 } from 'kubernetes-models/v1'; import { default as React_2 } from 'react'; -import * as React_3 from 'react'; import { RouteRef } from '@backstage/core-plugin-api'; -import { TypeMeta } from '@kubernetes-models/base'; -import { V1ConfigMap } from '@kubernetes/client-node'; -import { V1CronJob } from '@kubernetes/client-node'; -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 { V1ObjectMeta } from '@kubernetes/client-node'; -import { V1Pod } from '@kubernetes/client-node'; -import { V1ReplicaSet } from '@kubernetes/client-node'; -import { V1Service } from '@kubernetes/client-node'; -import { V1StatefulSet } from '@kubernetes/client-node'; -import { WorkloadsByEntityRequest } from '@backstage/plugin-kubernetes-common'; - -// Warning: (ae-forgotten-export) The symbol "ClusterProps" needs to be exported by the entry point index.d.ts -// Warning: (ae-missing-release-tag) "Cluster" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export const Cluster: ({ - clusterObjects, - podsWithErrors, -}: ClusterProps) => React_2.JSX.Element; - -// Warning: (ae-missing-release-tag) "ClusterContext" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export const ClusterContext: React_2.Context<ClusterAttributes>; - -// Warning: (ae-missing-release-tag) "ClusterLinksFormatter" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export type ClusterLinksFormatter = ( - options: ClusterLinksFormatterOptions, -) => URL; - -// Warning: (ae-missing-release-tag) "ClusterLinksFormatterOptions" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export interface ClusterLinksFormatterOptions { - // (undocumented) - dashboardParameters?: JsonObject; - // (undocumented) - dashboardUrl?: URL; - // (undocumented) - kind: string; - // (undocumented) - object: any; -} - -// Warning: (ae-missing-release-tag) "clusterLinksFormatters" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export const clusterLinksFormatters: Record<string, ClusterLinksFormatter>; - -// @public -export const ContainerCard: React_2.FC<ContainerCardProps>; - -// @public -export interface ContainerCardProps { - // (undocumented) - containerMetrics?: ClientContainerStatus; - // (undocumented) - containerSpec?: IContainer; - // (undocumented) - containerStatus: IContainerStatus; - // (undocumented) - podScope: PodScope; -} - -// @public -export interface ContainerScope extends PodScope { - // (undocumented) - containerName: string; -} - -// Warning: (ae-forgotten-export) The symbol "CronJobsAccordionsProps" needs to be exported by the entry point index.d.ts -// Warning: (ae-missing-release-tag) "CronJobsAccordions" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export const CronJobsAccordions: ({}: CronJobsAccordionsProps) => React_2.JSX.Element; - -// Warning: (ae-forgotten-export) The symbol "CustomResourcesProps" needs to be exported by the entry point index.d.ts -// Warning: (ae-missing-release-tag) "CustomResources" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export const CustomResources: ({}: CustomResourcesProps) => React_2.JSX.Element; - -// Warning: (ae-missing-release-tag) "DeploymentResources" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export interface DeploymentResources { - // (undocumented) - deployments: V1Deployment[]; - // (undocumented) - horizontalPodAutoscalers: V1HorizontalPodAutoscaler[]; - // (undocumented) - pods: V1Pod[]; - // (undocumented) - replicaSets: V1ReplicaSet[]; -} - -// @public -export interface DetectedError { - // (undocumented) - message: string; - // (undocumented) - occurrenceCount: number; - // Warning: (ae-forgotten-export) The symbol "ProposedFix" needs to be exported by the entry point index.d.ts - // - // (undocumented) - proposedFix?: ProposedFix; - // (undocumented) - severity: ErrorSeverity; - // (undocumented) - sourceRef: ResourceRef; - // (undocumented) - type: string; -} - -// @public -export type DetectedErrorsByCluster = Map<string, DetectedError[]>; - -// @public -export const DetectedErrorsContext: React_2.Context<DetectedError[]>; - -// @public -export const detectErrors: ( - objects: ObjectsByEntityResponse, -) => DetectedErrorsByCluster; // Warning: (ae-missing-release-tag) "EntityKubernetesContent" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -174,338 +22,11 @@ export type EntityKubernetesContentProps = { refreshIntervalMs?: number; }; -// @public -export const ErrorList: ({ - podAndErrors, -}: ErrorListProps) => React_2.JSX.Element; - -// @public -export interface ErrorListProps { - // (undocumented) - podAndErrors: PodAndErrors[]; -} - -// @public (undocumented) -export type ErrorMatcher = { - metadata?: IIoK8sApimachineryPkgApisMetaV1ObjectMeta; -} & TypeMeta; - -// Warning: (ae-forgotten-export) The symbol "ErrorPanelProps" needs to be exported by the entry point index.d.ts -// Warning: (ae-missing-release-tag) "ErrorPanel" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export const ErrorPanel: ({ - entityName, - errorMessage, - clustersWithErrors, -}: ErrorPanelProps) => React_2.JSX.Element; - -// Warning: (ae-forgotten-export) The symbol "ErrorReportingProps" needs to be exported by the entry point index.d.ts -// Warning: (ae-missing-release-tag) "ErrorReporting" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export const ErrorReporting: ({ - detectedErrors, -}: ErrorReportingProps) => React_3.JSX.Element; - -// @public -export type ErrorSeverity = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10; - -// @public -export const Events: ({ - involvedObjectName, - namespace, - clusterName, - warningEventsOnly, -}: EventsProps) => React_2.JSX.Element; - -// @public -export const EventsContent: ({ - events, - warningEventsOnly, -}: EventsContentProps) => React_2.JSX.Element; - -// @public -export interface EventsContentProps { - // (undocumented) - events: Event_2[]; - // (undocumented) - warningEventsOnly?: boolean; -} - -// @public -export interface EventsOptions { - // (undocumented) - clusterName: string; - // (undocumented) - involvedObjectName: string; - // (undocumented) - namespace: string; -} - -// @public -export interface EventsProps { - // (undocumented) - clusterName: string; - // (undocumented) - involvedObjectName: string; - // (undocumented) - namespace: string; - // (undocumented) - warningEventsOnly?: boolean; -} - -// @public -export const FixDialog: React_2.FC<FixDialogProps>; - -// @public -export interface FixDialogProps { - // (undocumented) - clusterName: string; - // (undocumented) - error: DetectedError; - // (undocumented) - open?: boolean; - // (undocumented) - pod: Pod; -} - -// Warning: (ae-forgotten-export) The symbol "FormatClusterLinkOptions" needs to be exported by the entry point index.d.ts -// Warning: (ae-missing-release-tag) "formatClusterLink" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export function formatClusterLink( - options: FormatClusterLinkOptions, -): string | undefined; - -// Warning: (ae-forgotten-export) The symbol "KubernetesAuthProvider" needs to be exported by the entry point index.d.ts -// Warning: (ae-missing-release-tag) "GoogleKubernetesAuthProvider" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export class GoogleKubernetesAuthProvider implements KubernetesAuthProvider { - constructor(authProvider: OAuthApi); - // (undocumented) - authProvider: OAuthApi; - // (undocumented) - decorateRequestBodyForAuth( - requestBody: KubernetesRequestBody, - ): Promise<KubernetesRequestBody>; - // (undocumented) - getCredentials(): Promise<{ - token: string; - }>; -} - -// Warning: (ae-missing-release-tag) "GroupedResponses" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export interface GroupedResponses extends DeploymentResources { - // (undocumented) - configMaps: V1ConfigMap[]; - // (undocumented) - cronJobs: V1CronJob[]; - // (undocumented) - customResources: any[]; - // (undocumented) - ingresses: V1Ingress[]; - // (undocumented) - jobs: V1Job[]; - // (undocumented) - services: V1Service[]; - // (undocumented) - statefulsets: V1StatefulSet[]; -} - -// Warning: (ae-missing-release-tag) "GroupedResponsesContext" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export const GroupedResponsesContext: React_2.Context<GroupedResponses>; - -// @public (undocumented) -export const HorizontalPodAutoscalerDrawer: (props: { - hpa: V1HorizontalPodAutoscaler; - expanded?: boolean; - children?: React_2.ReactNode; -}) => React_2.JSX.Element; - -// Warning: (ae-forgotten-export) The symbol "IngressesAccordionsProps" needs to be exported by the entry point index.d.ts -// Warning: (ae-missing-release-tag) "IngressesAccordions" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export const IngressesAccordions: ({}: IngressesAccordionsProps) => React_2.JSX.Element; - // Warning: (ae-missing-release-tag) "isKubernetesAvailable" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) export const isKubernetesAvailable: (entity: Entity) => boolean; -// Warning: (ae-forgotten-export) The symbol "JobsAccordionsProps" needs to be exported by the entry point index.d.ts -// Warning: (ae-missing-release-tag) "JobsAccordions" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export const JobsAccordions: ({ - jobs, -}: JobsAccordionsProps) => React_2.JSX.Element; - -// Warning: (ae-missing-release-tag) "KubernetesApi" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export interface KubernetesApi { - // (undocumented) - getClusters(): Promise< - { - name: string; - authProvider: string; - oidcTokenProvider?: string | undefined; - }[] - >; - // (undocumented) - getCustomObjectsByEntity( - request: CustomObjectsByEntityRequest, - ): Promise<ObjectsByEntityResponse>; - // (undocumented) - getObjectsByEntity( - requestBody: KubernetesRequestBody, - ): Promise<ObjectsByEntityResponse>; - // (undocumented) - getWorkloadsByEntity( - request: WorkloadsByEntityRequest, - ): Promise<ObjectsByEntityResponse>; - // (undocumented) - proxy(options: { - clusterName: string; - path: string; - init?: RequestInit; - }): Promise<Response>; -} - -// Warning: (ae-missing-release-tag) "kubernetesApiRef" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export const kubernetesApiRef: ApiRef<KubernetesApi>; - -// Warning: (ae-missing-release-tag) "KubernetesAuthProviders" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export class KubernetesAuthProviders implements KubernetesAuthProvidersApi { - constructor(options: { - microsoftAuthApi: OAuthApi; - googleAuthApi: OAuthApi; - oidcProviders?: { - [key: string]: OpenIdConnectApi; - }; - }); - // (undocumented) - decorateRequestBodyForAuth( - authProvider: string, - requestBody: KubernetesRequestBody, - ): Promise<KubernetesRequestBody>; - // (undocumented) - getCredentials(authProvider: string): Promise<{ - token?: string; - }>; -} - -// Warning: (ae-missing-release-tag) "KubernetesAuthProvidersApi" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export interface KubernetesAuthProvidersApi { - // (undocumented) - decorateRequestBodyForAuth( - authProvider: string, - requestBody: KubernetesRequestBody, - ): Promise<KubernetesRequestBody>; - // (undocumented) - getCredentials(authProvider: string): Promise<{ - token?: string; - }>; -} - -// Warning: (ae-missing-release-tag) "kubernetesAuthProvidersApiRef" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export const kubernetesAuthProvidersApiRef: ApiRef<KubernetesAuthProvidersApi>; - -// Warning: (ae-missing-release-tag) "KubernetesBackendClient" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export class KubernetesBackendClient implements KubernetesApi { - constructor(options: { - discoveryApi: DiscoveryApi; - identityApi: IdentityApi; - kubernetesAuthProvidersApi: KubernetesAuthProvidersApi; - }); - // (undocumented) - getClusters(): Promise< - { - name: string; - authProvider: string; - }[] - >; - // (undocumented) - getCustomObjectsByEntity( - request: CustomObjectsByEntityRequest, - ): Promise<ObjectsByEntityResponse>; - // (undocumented) - getObjectsByEntity( - requestBody: KubernetesRequestBody, - ): Promise<ObjectsByEntityResponse>; - // (undocumented) - getWorkloadsByEntity( - request: WorkloadsByEntityRequest, - ): Promise<ObjectsByEntityResponse>; - // (undocumented) - proxy(options: { - clusterName: string; - path: string; - init?: RequestInit; - }): Promise<Response>; -} - -// Warning: (ae-forgotten-export) The symbol "KubernetesContentProps" needs to be exported by the entry point index.d.ts -// Warning: (ae-missing-release-tag) "KubernetesContent" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export const KubernetesContent: ({ - entity, - refreshIntervalMs, -}: KubernetesContentProps) => React_2.JSX.Element; - -// Warning: (ae-forgotten-export) The symbol "KubernetesDrawerProps" needs to be exported by the entry point index.d.ts -// Warning: (ae-missing-release-tag) "KubernetesDrawer" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export const KubernetesDrawer: ({ - open, - label, - drawerContentsHeader, - kubernetesObject, - children, -}: KubernetesDrawerProps) => React_2.JSX.Element; - -// Warning: (ae-forgotten-export) The symbol "KubernetesDrawerContentProps" needs to be exported by the entry point index.d.ts -// Warning: (ae-missing-release-tag) "KubernetesDrawerContent" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export const KubernetesDrawerContent: ({ - children, - header, - kubernetesObject, - close, -}: KubernetesDrawerContentProps) => React_2.JSX.Element; - -// Warning: (ae-missing-release-tag) "KubernetesObjects" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export interface KubernetesObjects { - // (undocumented) - error?: string; - // (undocumented) - kubernetesObjects?: ObjectsByEntityResponse; - // (undocumented) - loading: boolean; -} - // Warning: (ae-missing-release-tag) "kubernetesPlugin" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -513,240 +34,11 @@ const kubernetesPlugin: BackstagePlugin< { entityContent: RouteRef<undefined>; }, - {}, {} >; export { kubernetesPlugin }; export { kubernetesPlugin as plugin }; -// Warning: (ae-missing-release-tag) "KubernetesProxyApi" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export interface KubernetesProxyApi { - // (undocumented) - getEventsByInvolvedObjectName(request: { - clusterName: string; - involvedObjectName: string; - namespace: string; - }): Promise<Event_2[]>; - // (undocumented) - getPodLogs(request: { - podName: string; - namespace: string; - clusterName: string; - containerName: string; - previous?: boolean; - }): Promise<{ - text: string; - }>; -} - -// Warning: (ae-missing-release-tag) "kubernetesProxyApiRef" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export const kubernetesProxyApiRef: ApiRef<KubernetesProxyApi>; - -// @public -export class KubernetesProxyClient { - constructor(options: { kubernetesApi: KubernetesApi }); - // (undocumented) - getEventsByInvolvedObjectName({ - clusterName, - involvedObjectName, - namespace, - }: { - clusterName: string; - involvedObjectName: string; - namespace: string; - }): Promise<Event_2[]>; - // (undocumented) - getPodLogs({ - podName, - namespace, - clusterName, - containerName, - previous, - }: { - podName: string; - namespace: string; - clusterName: string; - containerName: string; - previous?: boolean; - }): Promise<{ - text: string; - }>; -} - -// Warning: (ae-forgotten-export) The symbol "KubernetesDrawerable" needs to be exported by the entry point index.d.ts -// Warning: (ae-forgotten-export) The symbol "KubernetesStructuredMetadataTableDrawerProps" needs to be exported by the entry point index.d.ts -// Warning: (ae-missing-release-tag) "KubernetesStructuredMetadataTableDrawer" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export const KubernetesStructuredMetadataTableDrawer: < - T extends KubernetesDrawerable, ->({ - object, - renderObject, - kind, - buttonVariant, - expanded, - children, -}: KubernetesStructuredMetadataTableDrawerProps<T>) => React_2.JSX.Element; - -// Warning: (ae-forgotten-export) The symbol "ErrorPanelProps_2" needs to be exported by the entry point index.d.ts -// Warning: (ae-missing-release-tag) "LinkErrorPanel" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export const LinkErrorPanel: ({ - cluster, - errorMessage, -}: ErrorPanelProps_2) => React_2.JSX.Element; - -// @public -export const PendingPodContent: ({ - pod, -}: PendingPodContentProps) => React_2.JSX.Element; - -// @public -export interface PendingPodContentProps { - // (undocumented) - pod: Pod_2; -} - -// @public -export interface PodAndErrors { - // (undocumented) - clusterName: string; - // (undocumented) - errors: DetectedError[]; - // (undocumented) - pod: Pod_2; -} - -// Warning: (ae-forgotten-export) The symbol "PodDrawerProps" needs to be exported by the entry point index.d.ts -// -// @public -export const PodDrawer: ({ - podAndErrors, - open, -}: PodDrawerProps) => React_2.JSX.Element; - -// @public -export const PodExecTerminal: ( - props: PodExecTerminalProps, -) => React_2.JSX.Element; - -// @public -export const PodExecTerminalDialog: ( - props: PodExecTerminalProps, -) => React_2.JSX.Element; - -// @public -export interface PodExecTerminalProps { - // (undocumented) - clusterName: string; - // (undocumented) - containerName: string; - // (undocumented) - podName: string; - // (undocumented) - podNamespace: string; -} - -// @public -export const PodLogs: React_2.FC<PodLogsProps>; - -// @public -export const PodLogsDialog: ({ - containerScope, -}: PodLogsDialogProps) => React_2.JSX.Element; - -// @public -export interface PodLogsDialogProps { - // (undocumented) - containerScope: ContainerScope; -} - -// @public -export interface PodLogsOptions { - // (undocumented) - containerScope: ContainerScope; - // (undocumented) - previous?: boolean; -} - -// @public -export interface PodLogsProps { - // (undocumented) - containerScope: ContainerScope; - // (undocumented) - previous?: boolean; -} - -// @public -export const PodMetricsContext: React_2.Context<Map<string, ClientPodStatus[]>>; - -// Warning: (ae-missing-release-tag) "PodMetricsMatcher" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export type PodMetricsMatcher = { - metadata?: IObjectMeta; -}; - -// Warning: (ae-missing-release-tag) "PodNamesWithErrorsContext" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export const PodNamesWithErrorsContext: React_2.Context<Set<string>>; - -// Warning: (ae-missing-release-tag) "PodNamesWithMetricsContext" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export const PodNamesWithMetricsContext: React_2.Context< - Map<string, ClientPodStatus> ->; - -// @public -export interface PodScope { - // (undocumented) - clusterName: string; - // (undocumented) - podName: string; - // (undocumented) - podNamespace: string; -} - -// Warning: (ae-forgotten-export) The symbol "PodsTablesProps" needs to be exported by the entry point index.d.ts -// Warning: (ae-missing-release-tag) "PodsTable" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export const PodsTable: ({ - pods, - extraColumns, -}: PodsTablesProps) => React_2.JSX.Element; - -// @public -export interface ResourceRef { - // (undocumented) - apiGroup: string; - // (undocumented) - kind: string; - // (undocumented) - name: string; - // (undocumented) - namespace: string; -} - -// Warning: (ae-forgotten-export) The symbol "ResourceUtilizationProps" needs to be exported by the entry point index.d.ts -// -// @public -export const ResourceUtilization: ({ - compressed, - title, - usage, - total, - totalFormatted, -}: ResourceUtilizationProps) => React_2.JSX.Element; - // Warning: (ae-missing-release-tag) "Router" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -754,60 +46,5 @@ export const Router: (props: { refreshIntervalMs?: number; }) => React_2.JSX.Element; -// @public -export class ServerSideKubernetesAuthProvider - implements KubernetesAuthProvider -{ - // (undocumented) - decorateRequestBodyForAuth( - requestBody: KubernetesRequestBody, - ): Promise<KubernetesRequestBody>; - // (undocumented) - getCredentials(): Promise<{}>; -} - -// Warning: (ae-forgotten-export) The symbol "ServicesAccordionsProps" needs to be exported by the entry point index.d.ts -// Warning: (ae-missing-release-tag) "ServicesAccordions" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export const ServicesAccordions: ({}: ServicesAccordionsProps) => React_2.JSX.Element; - -// @public -export const useCustomResources: ( - entity: Entity, - customResourceMatchers: CustomResourceMatcher[], - intervalMs?: number, -) => KubernetesObjects; - -// @public -export const useEvents: ({ - involvedObjectName, - namespace, - clusterName, -}: EventsOptions) => AsyncState<Event_2[]>; - -// Warning: (ae-missing-release-tag) "useKubernetesObjects" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export const useKubernetesObjects: ( - entity: Entity, - intervalMs?: number, -) => KubernetesObjects; - -// @public -export const useMatchingErrors: (matcher: ErrorMatcher) => DetectedError[]; - -// @public -export const usePodLogs: ({ - containerScope, - previous, -}: PodLogsOptions) => AsyncState<{ - text: string; -}>; - -// @public -export const usePodMetrics: ( - clusterName: string, - matcher: PodMetricsMatcher, -) => ClientPodStatus | undefined; +export * from '@backstage/plugin-kubernetes-react'; ``` diff --git a/plugins/kubernetes/dev/index.tsx b/plugins/kubernetes/dev/index.tsx index 520f8802a9..fbc666ae13 100644 --- a/plugins/kubernetes/dev/index.tsx +++ b/plugins/kubernetes/dev/index.tsx @@ -116,6 +116,12 @@ class MockKubernetesClient implements KubernetesApi { return [{ name: 'mock-cluster', authProvider: 'serviceAccount' }]; } + async getCluster( + _clusterName: string, + ): Promise<{ name: string; authProvider: string }> { + return { name: 'mock-cluster', authProvider: 'serviceAccount' }; + } + async proxy(_options: { clusterName: String; path: String }): Promise<any> { return { kind: 'Namespace', diff --git a/plugins/kubernetes/package.json b/plugins/kubernetes/package.json index 80498b5b69..8ed59595c2 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.10.3", + "version": "0.11.0-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -41,6 +41,7 @@ "@backstage/errors": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", "@backstage/plugin-kubernetes-common": "workspace:^", + "@backstage/plugin-kubernetes-react": "workspace:^", "@backstage/theme": "workspace:^", "@backstage/types": "workspace:^", "@kubernetes-models/apimachinery": "^1.1.0", diff --git a/plugins/kubernetes/src/components/KubernetesContent.test.tsx b/plugins/kubernetes/src/KubernetesContent.test.tsx similarity index 91% rename from plugins/kubernetes/src/components/KubernetesContent.test.tsx rename to plugins/kubernetes/src/KubernetesContent.test.tsx index 4c85298dba..7c21c6f5a7 100644 --- a/plugins/kubernetes/src/components/KubernetesContent.test.tsx +++ b/plugins/kubernetes/src/KubernetesContent.test.tsx @@ -18,13 +18,19 @@ import React from 'react'; import { screen } from '@testing-library/react'; import { renderInTestApp } from '@backstage/test-utils'; import { KubernetesContent } from './KubernetesContent'; -import { useKubernetesObjects } from '../hooks'; +import { useKubernetesObjects } from '@backstage/plugin-kubernetes-react'; +import * as oneDeployment from './__fixtures__/1-deployments.json'; +import * as twoDeployments from './__fixtures__/2-deployments.json'; -jest.mock('../hooks'); -import * as oneDeployment from '../__fixtures__/1-deployments.json'; -import * as twoDeployments from '../__fixtures__/2-deployments.json'; +jest.mock('@backstage/plugin-kubernetes-react', () => ({ + ...jest.requireActual('@backstage/plugin-kubernetes-react'), + useKubernetesObjects: jest.fn(), +})); describe('KubernetesContent', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); it('render empty response', async () => { (useKubernetesObjects as any).mockReturnValue({ kubernetesObjects: { diff --git a/plugins/kubernetes/src/components/KubernetesContent.tsx b/plugins/kubernetes/src/KubernetesContent.tsx similarity index 81% rename from plugins/kubernetes/src/components/KubernetesContent.tsx rename to plugins/kubernetes/src/KubernetesContent.tsx index a465422095..9c266b1854 100644 --- a/plugins/kubernetes/src/components/KubernetesContent.tsx +++ b/plugins/kubernetes/src/KubernetesContent.tsx @@ -17,14 +17,23 @@ import React from 'react'; import { Grid, Typography } from '@material-ui/core'; import { Entity } from '@backstage/catalog-model'; -import { ErrorPanel } from './ErrorPanel'; -import { ErrorReporting } from './ErrorReporting'; -import { DetectedError, detectErrors } from '../error-detection'; -import { Cluster } from './Cluster'; -import EmptyStateImage from '../assets/emptystate.svg'; -import { useKubernetesObjects } from '../hooks'; -import { Content, Page, Progress } from '@backstage/core-components'; -import { DetectedErrorsContext } from '../hooks/useMatchingErrors'; +import { + ErrorPanel, + ErrorReporting, + Cluster, + useKubernetesObjects, + DetectedErrorsContext, +} from '@backstage/plugin-kubernetes-react'; +import { + DetectedError, + detectErrors, +} from '@backstage/plugin-kubernetes-common'; +import { + Content, + EmptyState, + Page, + Progress, +} from '@backstage/core-components'; type KubernetesContentProps = { entity: Entity; @@ -98,17 +107,11 @@ export const KubernetesContent = ({ alignItems="center" spacing={2} > - <Grid item xs={4}> - <Typography variant="h5"> - No resources on any known clusters for{' '} - {entity.metadata.name} - </Typography> - </Grid> - <Grid item xs={4}> - <img - src={EmptyStateImage} - alt="EmptyState" - data-testid="emptyStateImg" + <Grid item xs={8}> + <EmptyState + missing="data" + title="No Kubernetes resources" + description={`No resources on any known clusters for ${entity.metadata.name}`} /> </Grid> </Grid> diff --git a/plugins/kubernetes/src/Router.tsx b/plugins/kubernetes/src/Router.tsx index fd3a4bd0ce..bd8fc09edc 100644 --- a/plugins/kubernetes/src/Router.tsx +++ b/plugins/kubernetes/src/Router.tsx @@ -18,7 +18,7 @@ import React from 'react'; import { Entity } from '@backstage/catalog-model'; import { useEntity } from '@backstage/plugin-catalog-react'; import { Route, Routes } from 'react-router-dom'; -import { KubernetesContent } from './components/KubernetesContent'; +import { KubernetesContent } from './KubernetesContent'; import { Button } from '@material-ui/core'; import { MissingAnnotationEmptyState } from '@backstage/core-components'; diff --git a/plugins/kubernetes/src/assets/emptystate.svg b/plugins/kubernetes/src/assets/emptystate.svg deleted file mode 100644 index 8a0490727f..0000000000 --- a/plugins/kubernetes/src/assets/emptystate.svg +++ /dev/null @@ -1 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="282" height="173" fill="none" viewBox="0 0 282 173"><path fill="#000" fill-opacity=".05" fill-rule="evenodd" d="M16.4571 45.1637C11.0514 46.1711 7.48574 51.3699 8.49306 56.7756C9.50039 62.1814 14.6992 65.747 20.105 64.7397L27.5528 63.3518C25.4791 65.5835 24.4525 68.7347 25.0535 71.9596C26.0608 77.3653 31.2596 80.931 36.6654 79.9236L89.691 70.0427C89.7016 70.1067 89.7129 70.1708 89.7249 70.2349C90.3258 73.4598 92.4185 76.0298 95.1569 77.3647L91.9031 77.971C86.4974 78.9784 82.9318 84.1772 83.9391 89.583C84.9464 94.9887 90.1452 98.5543 95.551 97.547L250.098 68.7482C255.504 67.7409 259.069 62.5421 258.062 57.1363C257.461 53.9114 255.368 51.3414 252.63 50.0065L257.835 49.0366C263.241 48.0292 266.807 42.8304 265.799 37.4247C264.792 32.0189 259.593 28.4533 254.187 29.4606L161.492 46.7338C161.481 46.6697 161.47 46.6056 161.458 46.5415C160.857 43.3166 158.764 40.7466 156.026 39.4117L165.025 37.7347C170.431 36.7274 173.997 31.5286 172.989 26.1228C171.982 20.7171 166.783 17.1514 161.378 18.1588L16.4571 45.1637ZM24.3031 122.54C23.2958 117.134 26.8614 111.936 32.2672 110.928L190.856 81.3762C196.262 80.3688 201.461 83.9345 202.468 89.3402C203.476 94.746 199.91 99.9448 194.504 100.952L189.963 101.798C190.493 102.057 190.999 102.362 191.474 102.708L246.43 92.4677C251.835 91.4604 257.034 95.026 258.041 100.432C258.642 103.657 257.616 106.808 255.542 109.04L256.649 108.833C262.055 107.826 267.253 111.392 268.261 116.797C269.268 122.203 265.702 127.402 260.297 128.409L95.5591 159.107C90.1534 160.114 84.9545 156.549 83.9472 151.143C82.9399 145.737 86.5055 140.538 91.9113 139.531L103.94 137.29C103.41 137.031 102.904 136.726 102.429 136.38L29.1002 150.044C23.6944 151.051 18.4956 147.486 17.4882 142.08C16.4809 136.674 20.0465 131.475 25.4523 130.468L29.7352 129.67C26.9967 128.335 24.904 125.765 24.3031 122.54Z" clip-rule="evenodd"/><circle cx="188" cy="55" r="6" fill="#69DDC7"/><circle cx="91" cy="92" r="6" fill="#69DDC7"/><path fill="#69DDC7" d="M121 114L95.5 88L86.5 96L121 130L192.5 59L183.5 51L121 114Z"/></svg> diff --git a/plugins/kubernetes/src/components/CronJobsAccordions/index.ts b/plugins/kubernetes/src/components/CronJobsAccordions/index.ts deleted file mode 100644 index e72e3f7e6d..0000000000 --- a/plugins/kubernetes/src/components/CronJobsAccordions/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright 2021 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -export { CronJobsAccordions } from './CronJobsAccordions'; diff --git a/plugins/kubernetes/src/components/IngressesAccordions/index.ts b/plugins/kubernetes/src/components/IngressesAccordions/index.ts deleted file mode 100644 index 8e7f103e42..0000000000 --- a/plugins/kubernetes/src/components/IngressesAccordions/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -export { IngressesAccordions } from './IngressesAccordions'; diff --git a/plugins/kubernetes/src/components/ServicesAccordions/index.ts b/plugins/kubernetes/src/components/ServicesAccordions/index.ts deleted file mode 100644 index 04fee9caca..0000000000 --- a/plugins/kubernetes/src/components/ServicesAccordions/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -export { ServicesAccordions } from './ServicesAccordions'; diff --git a/plugins/kubernetes/src/index.ts b/plugins/kubernetes/src/index.ts index 616caaef62..3651a861fc 100644 --- a/plugins/kubernetes/src/index.ts +++ b/plugins/kubernetes/src/index.ts @@ -27,10 +27,5 @@ export { } from './plugin'; export type { EntityKubernetesContentProps } from './plugin'; export { Router, isKubernetesAvailable } from './Router'; -export * from './api'; -export * from './kubernetes-auth-provider'; -export * from './utils/clusterLinks'; -export * from './components'; -export * from './error-detection'; -export * from './hooks'; -export * from './types'; +// TODO remove this re-export as a breaking change after a couple of releases +export * from '@backstage/plugin-kubernetes-react'; diff --git a/plugins/kubernetes/src/kubernetes-auth-provider/index.ts b/plugins/kubernetes/src/kubernetes-auth-provider/index.ts deleted file mode 100644 index 23197321f6..0000000000 --- a/plugins/kubernetes/src/kubernetes-auth-provider/index.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -export { kubernetesAuthProvidersApiRef } from './types'; -export type { KubernetesAuthProvidersApi } from './types'; -export { KubernetesAuthProviders } from './KubernetesAuthProviders'; -export { GoogleKubernetesAuthProvider } from './GoogleKubernetesAuthProvider'; -export { ServerSideKubernetesAuthProvider } from './ServerSideAuthProvider'; diff --git a/plugins/kubernetes/src/plugin.ts b/plugins/kubernetes/src/plugin.ts index 02c7bfd2d6..ac55dbbf23 100644 --- a/plugins/kubernetes/src/plugin.ts +++ b/plugins/kubernetes/src/plugin.ts @@ -13,10 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { KubernetesBackendClient } from './api/KubernetesBackendClient'; -import { kubernetesApiRef, kubernetesProxyApiRef } from './api/types'; -import { kubernetesAuthProvidersApiRef } from './kubernetes-auth-provider/types'; -import { KubernetesAuthProviders } from './kubernetes-auth-provider/KubernetesAuthProviders'; +import { + KubernetesBackendClient, + kubernetesApiRef, + kubernetesProxyApiRef, + kubernetesAuthProvidersApiRef, + KubernetesAuthProviders, + KubernetesProxyClient, +} from '@backstage/plugin-kubernetes-react'; import { createApiFactory, createPlugin, @@ -30,7 +34,6 @@ import { oneloginAuthApiRef, createRoutableExtension, } from '@backstage/core-plugin-api'; -import { KubernetesProxyClient } from './api'; export const rootCatalogKubernetesRouteRef = createRouteRef({ id: 'kubernetes', diff --git a/plugins/kubernetes/src/types/types.ts b/plugins/kubernetes/src/types/types.ts deleted file mode 100644 index f15c4f335a..0000000000 --- a/plugins/kubernetes/src/types/types.ts +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { JsonObject } from '@backstage/types'; -import { - V1Deployment, - V1Pod, - V1ReplicaSet, - V1HorizontalPodAutoscaler, - V1Service, - V1ConfigMap, - V1Ingress, - V1Job, - V1CronJob, - V1StatefulSet, -} from '@kubernetes/client-node'; - -export interface DeploymentResources { - pods: V1Pod[]; - replicaSets: V1ReplicaSet[]; - deployments: V1Deployment[]; - horizontalPodAutoscalers: V1HorizontalPodAutoscaler[]; -} - -export interface GroupedResponses extends DeploymentResources { - services: V1Service[]; - configMaps: V1ConfigMap[]; - ingresses: V1Ingress[]; - jobs: V1Job[]; - cronJobs: V1CronJob[]; - customResources: any[]; - statefulsets: V1StatefulSet[]; -} - -export interface ClusterLinksFormatterOptions { - dashboardUrl?: URL; - dashboardParameters?: JsonObject; - object: any; - kind: string; -} - -export type ClusterLinksFormatter = ( - options: ClusterLinksFormatterOptions, -) => URL; diff --git a/plugins/lighthouse-backend/CHANGELOG.md b/plugins/lighthouse-backend/CHANGELOG.md index 209ca47094..32c2b599dd 100644 --- a/plugins/lighthouse-backend/CHANGELOG.md +++ b/plugins/lighthouse-backend/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/plugin-lighthouse-backend +## 0.3.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/types@1.1.1 + - @backstage/plugin-lighthouse-common@0.1.3 + +## 0.3.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-node@1.4.6-next.0 + - @backstage/plugin-lighthouse-common@0.1.3 + ## 0.3.0 ### Minor Changes diff --git a/plugins/lighthouse-backend/package.json b/plugins/lighthouse-backend/package.json index 555f3e2819..bd337e185a 100644 --- a/plugins/lighthouse-backend/package.json +++ b/plugins/lighthouse-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-lighthouse-backend", "description": "Backend functionalities for lighthouse", - "version": "0.3.0", + "version": "0.3.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/lighthouse/CHANGELOG.md b/plugins/lighthouse/CHANGELOG.md index 56882e2a45..4ae227281a 100644 --- a/plugins/lighthouse/CHANGELOG.md +++ b/plugins/lighthouse/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/plugin-lighthouse +## 0.4.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-lighthouse-common@0.1.3 + +## 0.4.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-lighthouse-common@0.1.3 + ## 0.4.9 ### Patch Changes diff --git a/plugins/lighthouse/api-report.md b/plugins/lighthouse/api-report.md index 9794fe1728..40a4ff514f 100644 --- a/plugins/lighthouse/api-report.md +++ b/plugins/lighthouse/api-report.md @@ -49,7 +49,6 @@ const lighthousePlugin: BackstagePlugin< root: RouteRef<undefined>; entityContent: RouteRef<undefined>; }, - {}, {} >; export { lighthousePlugin }; diff --git a/plugins/lighthouse/package.json b/plugins/lighthouse/package.json index 3e62644212..1b81e64511 100644 --- a/plugins/lighthouse/package.json +++ b/plugins/lighthouse/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-lighthouse", "description": "A Backstage plugin that integrates towards Lighthouse", - "version": "0.4.9", + "version": "0.4.10-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/linguist-backend/CHANGELOG.md b/plugins/linguist-backend/CHANGELOG.md index 10bfface1c..5bc5640704 100644 --- a/plugins/linguist-backend/CHANGELOG.md +++ b/plugins/linguist-backend/CHANGELOG.md @@ -1,5 +1,39 @@ # @backstage/plugin-linguist-backend +## 0.5.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-linguist-common@0.1.2 + +## 0.5.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-node@1.4.6-next.0 + - @backstage/plugin-linguist-common@0.1.2 + ## 0.5.0 ### Minor Changes diff --git a/plugins/linguist-backend/package.json b/plugins/linguist-backend/package.json index d2c63c7f44..99ce86abd8 100644 --- a/plugins/linguist-backend/package.json +++ b/plugins/linguist-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-linguist-backend", - "version": "0.5.0", + "version": "0.5.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/linguist/CHANGELOG.md b/plugins/linguist/CHANGELOG.md index 6b0b23a4bb..b5f72d53ba 100644 --- a/plugins/linguist/CHANGELOG.md +++ b/plugins/linguist/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/plugin-linguist +## 0.1.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-linguist-common@0.1.2 + +## 0.1.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-linguist-common@0.1.2 + ## 0.1.9 ### Patch Changes diff --git a/plugins/linguist/api-report.md b/plugins/linguist/api-report.md index 5182ce12f6..71e2460088 100644 --- a/plugins/linguist/api-report.md +++ b/plugins/linguist/api-report.md @@ -16,7 +16,7 @@ export const EntityLinguistCard: () => JSX_2.Element; export const isLinguistAvailable: (entity: Entity) => boolean; // @public (undocumented) -export const linguistPlugin: BackstagePlugin<{}, {}, {}>; +export const linguistPlugin: BackstagePlugin<{}, {}>; // (No @packageDocumentation comment for this package) ``` diff --git a/plugins/linguist/package.json b/plugins/linguist/package.json index ecae75cddf..4bdc89ce29 100644 --- a/plugins/linguist/package.json +++ b/plugins/linguist/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-linguist", - "version": "0.1.9", + "version": "0.1.10-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/microsoft-calendar/CHANGELOG.md b/plugins/microsoft-calendar/CHANGELOG.md index 7c88ec2087..1b1942ce6f 100644 --- a/plugins/microsoft-calendar/CHANGELOG.md +++ b/plugins/microsoft-calendar/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-microsoft-calendar +## 0.1.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## 0.1.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + ## 0.1.7 ### Patch Changes diff --git a/plugins/microsoft-calendar/package.json b/plugins/microsoft-calendar/package.json index 8ffe31e790..63ce1d7dfa 100644 --- a/plugins/microsoft-calendar/package.json +++ b/plugins/microsoft-calendar/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-microsoft-calendar", - "version": "0.1.7", + "version": "0.1.8-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/newrelic-dashboard/CHANGELOG.md b/plugins/newrelic-dashboard/CHANGELOG.md index 6a6ad77acf..c667e3594c 100644 --- a/plugins/newrelic-dashboard/CHANGELOG.md +++ b/plugins/newrelic-dashboard/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-newrelic-dashboard +## 0.2.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + +## 0.2.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + ## 0.2.17 ### Patch Changes diff --git a/plugins/newrelic-dashboard/api-report.md b/plugins/newrelic-dashboard/api-report.md index 2e9b11a88e..ce7b8d5b7e 100644 --- a/plugins/newrelic-dashboard/api-report.md +++ b/plugins/newrelic-dashboard/api-report.md @@ -31,7 +31,6 @@ export const newRelicDashboardPlugin: BackstagePlugin< { root: RouteRef<undefined>; }, - {}, {} >; diff --git a/plugins/newrelic-dashboard/package.json b/plugins/newrelic-dashboard/package.json index 42db37738a..af5003dc1a 100644 --- a/plugins/newrelic-dashboard/package.json +++ b/plugins/newrelic-dashboard/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-newrelic-dashboard", - "version": "0.2.17", + "version": "0.2.18-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/newrelic/CHANGELOG.md b/plugins/newrelic/CHANGELOG.md index dc69d20143..a0d122a18c 100644 --- a/plugins/newrelic/CHANGELOG.md +++ b/plugins/newrelic/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-newrelic +## 0.3.41-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/theme@0.4.2 + +## 0.3.41-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/theme@0.4.2 + ## 0.3.40 ### Patch Changes diff --git a/plugins/newrelic/api-report.md b/plugins/newrelic/api-report.md index 04fd229465..a77b80c862 100644 --- a/plugins/newrelic/api-report.md +++ b/plugins/newrelic/api-report.md @@ -17,7 +17,6 @@ const newRelicPlugin: BackstagePlugin< { root: RouteRef<undefined>; }, - {}, {} >; export { newRelicPlugin }; diff --git a/plugins/newrelic/package.json b/plugins/newrelic/package.json index 5629a10f86..da63717dda 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.40", + "version": "0.3.41-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/nomad-backend/CHANGELOG.md b/plugins/nomad-backend/CHANGELOG.md index 9ff5e392fc..a5186f75f8 100644 --- a/plugins/nomad-backend/CHANGELOG.md +++ b/plugins/nomad-backend/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-nomad-backend +## 0.1.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + +## 0.1.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + ## 0.1.5 ### Patch Changes diff --git a/plugins/nomad-backend/README.md b/plugins/nomad-backend/README.md index d06444809e..231f1ddccb 100644 --- a/plugins/nomad-backend/README.md +++ b/plugins/nomad-backend/README.md @@ -1,6 +1,20 @@ # @backstage/plugin-nomad-backend -A backend for [Nomad](https://www.nomadproject.io/), this plugin exposes a service with routes that are used by the `@backstage/plugin-nomad` plugin to query Job and Group information from a Nomad API. +A backend for [Nomad](https://www.nomadproject.io/), this plugin exposes a service with routes that are used by the `@backstage/plugin-nomad-backend` plugin to query Job and Group information from a Nomad API. + +## New Backend System + +The Nomad backend plugin has support for the [new backend system](https://backstage.io/docs/backend-system/), here's how you can set that up: + +In your `packages/backend/src/index.ts` make the following changes: + +```diff + import { createBackend } from '@backstage/backend-defaults'; + const backend = createBackend(); + // ... other feature additions + backend.add(import('@backstage/plugin-nomad-backend')); + backend.start(); +``` ## Set Up diff --git a/plugins/nomad-backend/api-report.md b/plugins/nomad-backend/api-report.md index 5b56661e43..82bb823d2d 100644 --- a/plugins/nomad-backend/api-report.md +++ b/plugins/nomad-backend/api-report.md @@ -3,6 +3,7 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +import { BackendFeature } from '@backstage/backend-plugin-api'; import { Config } from '@backstage/config'; import express from 'express'; import { Logger } from 'winston'; @@ -10,6 +11,10 @@ import { Logger } from 'winston'; // @public (undocumented) export function createRouter(options: RouterOptions): Promise<express.Router>; +// @public +const nomadPlugin: () => BackendFeature; +export default nomadPlugin; + // @public (undocumented) export interface RouterOptions { // (undocumented) diff --git a/plugins/nomad-backend/package.json b/plugins/nomad-backend/package.json index 24ffd9eeff..7873f846ba 100644 --- a/plugins/nomad-backend/package.json +++ b/plugins/nomad-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-nomad-backend", - "version": "0.1.5", + "version": "0.1.7-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -29,6 +29,7 @@ }, "dependencies": { "@backstage/backend-common": "workspace:^", + "@backstage/backend-plugin-api": "workspace:^", "@backstage/config": "workspace:^", "@backstage/errors": "workspace:^", "@types/express": "*", diff --git a/plugins/nomad-backend/src/index.ts b/plugins/nomad-backend/src/index.ts index d2e8d61bad..21aa299d6d 100644 --- a/plugins/nomad-backend/src/index.ts +++ b/plugins/nomad-backend/src/index.ts @@ -14,3 +14,4 @@ * limitations under the License. */ export * from './service/router'; +export { nomadPlugin as default } from './plugin'; diff --git a/packages/techdocs-cli-embedded-app/cypress/integration/app.js b/plugins/nomad-backend/src/plugin.test.ts similarity index 75% rename from packages/techdocs-cli-embedded-app/cypress/integration/app.js rename to plugins/nomad-backend/src/plugin.test.ts index d31f7a7964..6ed8d2b194 100644 --- a/packages/techdocs-cli-embedded-app/cypress/integration/app.js +++ b/plugins/nomad-backend/src/plugin.test.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Backstage Authors + * Copyright 2023 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { nomadPlugin } from './plugin'; -describe('App', () => { - it('should render the catalog', () => { - cy.visit('/'); - cy.contains('My Company Service Catalog'); +describe('nomad', () => { + it('should export the nomad plugin', () => { + expect(nomadPlugin).toBeDefined(); }); }); diff --git a/plugins/nomad-backend/src/plugin.ts b/plugins/nomad-backend/src/plugin.ts new file mode 100644 index 0000000000..f3a43c4a91 --- /dev/null +++ b/plugins/nomad-backend/src/plugin.ts @@ -0,0 +1,52 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { loggerToWinstonLogger } from '@backstage/backend-common'; +import { + createBackendPlugin, + coreServices, +} from '@backstage/backend-plugin-api'; +import { createRouter } from './service/router'; + +/** + * Nomad backend plugin + * + * @public + */ +export const nomadPlugin = createBackendPlugin({ + pluginId: 'nomad', + register(env) { + env.registerInit({ + deps: { + logger: coreServices.logger, + config: coreServices.rootConfig, + httpRouter: coreServices.httpRouter, + }, + async init({ logger, config, httpRouter }) { + const winstonLogger = loggerToWinstonLogger(logger); + httpRouter.use( + await createRouter({ + /** + * Logger for logging purposes + */ + logger: winstonLogger, + config, + }), + ); + }, + }); + }, +}); diff --git a/plugins/nomad/CHANGELOG.md b/plugins/nomad/CHANGELOG.md index 8f3d96519a..15f8fca004 100644 --- a/plugins/nomad/CHANGELOG.md +++ b/plugins/nomad/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-nomad +## 0.1.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## 0.1.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + ## 0.1.5 ### Patch Changes diff --git a/plugins/nomad/api-report.md b/plugins/nomad/api-report.md index c2d06b9892..68cc47c33d 100644 --- a/plugins/nomad/api-report.md +++ b/plugins/nomad/api-report.md @@ -28,7 +28,6 @@ export const nomadPlugin: BackstagePlugin< root: RouteRef<undefined>; entityContent: RouteRef<undefined>; }, - {}, {} >; diff --git a/plugins/nomad/package.json b/plugins/nomad/package.json index 80971f5b6c..5a3964cdc1 100644 --- a/plugins/nomad/package.json +++ b/plugins/nomad/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-nomad", - "version": "0.1.5", + "version": "0.1.6-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/octopus-deploy/CHANGELOG.md b/plugins/octopus-deploy/CHANGELOG.md index 29b46afc14..b9d7dc084f 100644 --- a/plugins/octopus-deploy/CHANGELOG.md +++ b/plugins/octopus-deploy/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-octopus-deploy +## 0.2.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## 0.2.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + ## 0.2.6 ### Patch Changes diff --git a/plugins/octopus-deploy/api-report.md b/plugins/octopus-deploy/api-report.md index 713d99aa8f..3d65e40c64 100644 --- a/plugins/octopus-deploy/api-report.md +++ b/plugins/octopus-deploy/api-report.md @@ -55,7 +55,7 @@ export type OctopusDeployment = { }; // @public (undocumented) -export const octopusDeployPlugin: BackstagePlugin<{}, {}, {}>; +export const octopusDeployPlugin: BackstagePlugin<{}, {}>; // @public (undocumented) export type OctopusEnvironment = { diff --git a/plugins/octopus-deploy/package.json b/plugins/octopus-deploy/package.json index 608f9d5ace..5e0bf27520 100644 --- a/plugins/octopus-deploy/package.json +++ b/plugins/octopus-deploy/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-octopus-deploy", - "version": "0.2.6", + "version": "0.2.7-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/opencost/CHANGELOG.md b/plugins/opencost/CHANGELOG.md index ca4b9a990a..60edb74ed8 100644 --- a/plugins/opencost/CHANGELOG.md +++ b/plugins/opencost/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-opencost +## 0.2.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/theme@0.4.2 + +## 0.2.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/theme@0.4.2 + ## 0.2.0 ### Minor Changes diff --git a/plugins/opencost/api-report.md b/plugins/opencost/api-report.md index 079f394618..996bcea6ac 100644 --- a/plugins/opencost/api-report.md +++ b/plugins/opencost/api-report.md @@ -17,7 +17,6 @@ export const openCostPlugin: BackstagePlugin< { root: RouteRef<undefined>; }, - {}, {} >; ``` diff --git a/plugins/opencost/package.json b/plugins/opencost/package.json index 9db26eeb58..d733276152 100644 --- a/plugins/opencost/package.json +++ b/plugins/opencost/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-opencost", - "version": "0.2.0", + "version": "0.2.1-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/org-react/CHANGELOG.md b/plugins/org-react/CHANGELOG.md index fa32f33f00..2d5f4fbd7e 100644 --- a/plugins/org-react/CHANGELOG.md +++ b/plugins/org-react/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-org-react +## 0.1.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## 0.1.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + ## 0.1.13 ### Patch Changes diff --git a/plugins/org-react/package.json b/plugins/org-react/package.json index eecdd4fa6c..28876a6700 100644 --- a/plugins/org-react/package.json +++ b/plugins/org-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-org-react", - "version": "0.1.13", + "version": "0.1.14-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/org/CHANGELOG.md b/plugins/org/CHANGELOG.md index df02adcdfd..6ede70db1b 100644 --- a/plugins/org/CHANGELOG.md +++ b/plugins/org/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-org +## 0.6.15-next.1 + +### Patch Changes + +- dc5b6b971b: Fixed the display of OwnershipCard with aggregated relations by loading relations when getting children of entity. + This allows the already existing recursive method to work properly when children of entity have children themselves. +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## 0.6.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + ## 0.6.14 ### Patch Changes diff --git a/plugins/org/api-report.md b/plugins/org/api-report.md index d85df7125c..922b25b610 100644 --- a/plugins/org/api-report.md +++ b/plugins/org/api-report.md @@ -69,8 +69,7 @@ const orgPlugin: BackstagePlugin< {}, { catalogIndex: ExternalRouteRef<undefined, false>; - }, - {} + } >; export { orgPlugin }; export { orgPlugin as plugin }; diff --git a/plugins/org/package.json b/plugins/org/package.json index e0483b6e64..4f01b5fa09 100644 --- a/plugins/org/package.json +++ b/plugins/org/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-org", "description": "A Backstage plugin that helps you create entity pages for your organization", - "version": "0.6.14", + "version": "0.6.15-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -39,6 +39,7 @@ "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", "@types/react": "^16.13.1 || ^17.0.0", + "lodash": "^4.17.21", "p-limit": "^3.1.0", "pluralize": "^8.0.0", "qs": "^6.10.1", diff --git a/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.test.ts b/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.test.ts index 191bd10284..587dc689e3 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.test.ts +++ b/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.test.ts @@ -22,18 +22,8 @@ import { getEntityRelations } from '@backstage/plugin-catalog-react'; const givenParentGroup = 'team.squad1'; const givenLeafGroup = 'team.squad2'; const givenUser = 'user.john'; -const givenParentGroupEntity = { - kind: 'Group', - metadata: { - name: givenParentGroup, - }, -} as Partial<Entity> as Entity; -const givenLeafGroupEntity = { - kind: 'Group', - metadata: { - name: givenLeafGroup, - }, -} as Partial<Entity> as Entity; +const givenParentGroupEntity = createGroupEntityFromName(givenParentGroup); +const givenLeafGroupEntity = createGroupEntityFromName(givenLeafGroup); const givenUserEntity = { kind: 'User', metadata: { @@ -41,49 +31,35 @@ const givenUserEntity = { }, } as Partial<Entity> as Entity; +const getEntitiesByRefsMock = jest.fn(); const catalogApiMock: Pick<CatalogApi, 'getEntities' | 'getEntitiesByRefs'> = { getEntities: jest.fn(async () => Promise.resolve({ items: [] })), - getEntitiesByRefs: jest.fn(async ({ entityRefs: [ref] }) => - ref.includes(givenParentGroup) - ? { items: [givenParentGroupEntity] } - : { items: [givenLeafGroupEntity] }, - ), + getEntitiesByRefs: getEntitiesByRefsMock, }; jest.mock('@backstage/core-plugin-api', () => ({ useApi: jest.fn(() => catalogApiMock), })); -jest.mock('@backstage/plugin-catalog-react', () => ({ - catalogApiRef: {}, - getEntityRelations: jest.fn(entity => { - if (entity?.metadata.name === givenParentGroup) { - return [ - { - kind: 'Group', - namespace: 'default', - name: givenLeafGroup, - } as CompoundEntityRef, - ]; - } else if (entity?.kind === 'User') { - return [ - { - kind: 'Group', - namespace: 'default', - name: givenLeafGroup, - } as CompoundEntityRef, - ]; - } - return []; - }) as typeof getEntityRelations, -})); +const getEntityRelationsMock: jest.Mock< + CompoundEntityRef[], + [Entity | undefined] +> = jest.fn(); +jest.mock('@backstage/plugin-catalog-react', () => { + return { + catalogApiRef: {}, + getEntityRelations: jest.fn(entity => { + return getEntityRelationsMock(entity); + }) as typeof getEntityRelations, + }; +}); describe('useGetEntities', () => { const ownersFilter = (...owners: string[]) => expect.objectContaining({ filter: expect.arrayContaining([ expect.objectContaining({ - 'relations.ownedBy': owners, + 'relations.ownedBy': expect.arrayContaining(owners), }), ]), }); @@ -100,24 +76,132 @@ describe('useGetEntities', () => { await hook.waitForNextUpdate(); }; - it('given group entity should aggregate child ownership', async () => { - await whenHookIsCalledWith(givenParentGroupEntity); - expect(catalogApiMock.getEntities).toHaveBeenCalledWith( - ownersFilter( - `group:default/${givenParentGroup}`, - `group:default/${givenLeafGroup}`, - ), + beforeEach(() => { + getEntitiesByRefsMock.mockImplementation(async ({ entityRefs: [ref] }) => + ref.includes(givenParentGroup) + ? { items: [givenParentGroupEntity] } + : { items: [givenLeafGroupEntity] }, ); }); - it('given user entity should aggregate parent ownership and direct', async () => { - await whenHookIsCalledWith(givenUserEntity); - expect(catalogApiMock.getEntities).toHaveBeenCalledWith( - ownersFilter( - `group:default/${givenLeafGroup}`, - `user:default/${givenUser}`, - ), - ); + afterEach(() => { + getEntityRelationsMock.mockRestore(); + getEntitiesByRefsMock.mockRestore(); + }); + + describe('when given entity is a group', () => { + beforeEach(() => { + getEntityRelationsMock + .mockReturnValueOnce([createGroupRefFromName(givenLeafGroup)]) + .mockReturnValue([]); + }); + + it('should aggregate child ownership', async () => { + await whenHookIsCalledWith(givenParentGroupEntity); + expect(catalogApiMock.getEntities).toHaveBeenCalledWith( + ownersFilter( + `group:default/${givenParentGroup}`, + `group:default/${givenLeafGroup}`, + ), + ); + }); + + it('should retrieve child with their relations', async () => { + await whenHookIsCalledWith(givenParentGroupEntity); + expect(catalogApiMock.getEntitiesByRefs).toHaveBeenCalledWith({ + entityRefs: [`group:default/${givenLeafGroup}`], + fields: ['kind', 'metadata.namespace', 'metadata.name', 'relations'], + }); + }); + + describe('when relations are deep (children of children)', () => { + const givenIntermediateGroup = 'intermediate-group'; + const givenIntermediateGroupEntity = createGroupEntityFromName( + givenIntermediateGroup, + ); + + beforeEach(() => { + getEntitiesByRefsMock.mockRestore(); + getEntitiesByRefsMock.mockImplementation( + async ({ entityRefs: [ref] }) => { + if (ref.includes(givenParentGroup)) { + return { items: [givenParentGroupEntity] }; + } + + if (ref.includes(givenIntermediateGroup)) { + return { items: [givenIntermediateGroupEntity] }; + } + + return { items: [givenLeafGroupEntity] }; + }, + ); + }); + + it('should retrieve entities owned by any children', async () => { + getEntityRelationsMock.mockRestore(); + getEntityRelationsMock.mockImplementation(entity => { + if (entity?.metadata.name === givenParentGroup) { + return [createGroupRefFromName(givenIntermediateGroup)]; + } + + if (entity?.metadata.name === givenIntermediateGroup) { + return [createGroupRefFromName(givenLeafGroup)]; + } + + return []; + }); + + await whenHookIsCalledWith(givenParentGroupEntity); + expect(catalogApiMock.getEntities).toHaveBeenCalledWith( + ownersFilter( + `group:default/${givenParentGroup}`, + `group:default/${givenIntermediateGroup}`, + `group:default/${givenLeafGroup}`, + ), + ); + }); + + it('should retrieve entities owned by any children when circular relation', async () => { + getEntityRelationsMock.mockRestore(); + getEntityRelationsMock.mockImplementation(entity => { + if (entity?.metadata.name === givenParentGroup) { + return [createGroupRefFromName(givenIntermediateGroup)]; + } + + if (entity?.metadata.name === givenIntermediateGroup) { + return [createGroupRefFromName(givenLeafGroup)]; + } + + // returns parent by default so givenLeafGroup will have the givenParentGroup as child + return [createGroupRefFromName(givenParentGroup)]; + }); + + await whenHookIsCalledWith(givenParentGroupEntity); + expect(catalogApiMock.getEntities).toHaveBeenCalledWith( + ownersFilter( + `group:default/${givenParentGroup}`, + `group:default/${givenIntermediateGroup}`, + `group:default/${givenLeafGroup}`, + ), + ); + }); + }); + }); + + describe('when given entity is a user', () => { + it('should aggregate parent ownership and direct', async () => { + getEntityRelationsMock.mockReturnValue([ + createGroupRefFromName(givenLeafGroup), + ]); + + await whenHookIsCalledWith(givenUserEntity); + expect(catalogApiMock.getEntities).toHaveBeenCalledWith( + ownersFilter( + `group:default/${givenLeafGroup}`, + `user:default/${givenUser}`, + ), + ); + }); }); }); @@ -148,3 +232,20 @@ describe('useGetEntities', () => { }); }); }); + +function createGroupEntityFromName(name: string): Entity { + return { + kind: 'Group', + metadata: { + name: name, + }, + } as Partial<Entity> as Entity; +} + +function createGroupRefFromName(name: string): CompoundEntityRef { + return { + kind: 'Group', + namespace: 'default', + name: name, + }; +} diff --git a/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.ts b/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.ts index 1ff01cd8e1..b6fa9cbfd1 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.ts +++ b/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.ts @@ -16,9 +16,9 @@ import { Entity, + parseEntityRef, RELATION_MEMBER_OF, RELATION_PARENT_OF, - parseEntityRef, stringifyEntityRef, } from '@backstage/catalog-model'; import { @@ -32,6 +32,7 @@ import { useApi } from '@backstage/core-plugin-api'; import useAsync from 'react-use/lib/useAsync'; import qs from 'qs'; import { EntityRelationAggregation as EntityRelationsAggregation } from './types'; +import { uniq } from 'lodash'; const limiter = limiterFactory(10); @@ -80,6 +81,7 @@ const isEntity = (entity: Entity | undefined): entity is Entity => const getChildOwnershipEntityRefs = async ( entity: Entity, catalogApi: CatalogApi, + alreadyRetrievedParentRefs: string[] = [], ): Promise<string[]> => { const childGroups = getEntityRelations(entity, RELATION_PARENT_OF, { kind: 'Group', @@ -87,26 +89,38 @@ const getChildOwnershipEntityRefs = async ( const hasChildGroups = childGroups.length > 0; + const entityRef = stringifyEntityRef(entity); if (hasChildGroups) { const entityRefs = childGroups.map(r => stringifyEntityRef(r)); const childGroupResponse = await catalogApi.getEntitiesByRefs({ - fields: ['kind', 'metadata.namespace', 'metadata.name'], + fields: ['kind', 'metadata.namespace', 'metadata.name', 'relations'], entityRefs, }); const childGroupEntities = childGroupResponse.items.filter(isEntity); - return ( + const unknownChildren = childGroupEntities.filter( + childGroupEntity => + !alreadyRetrievedParentRefs.includes( + stringifyEntityRef(childGroupEntity), + ), + ); + const childrenRefs = ( await Promise.all( - childGroupEntities.map(childGroupEntity => + unknownChildren.map(childGroupEntity => limiter(() => - getChildOwnershipEntityRefs(childGroupEntity, catalogApi), + getChildOwnershipEntityRefs(childGroupEntity, catalogApi, [ + ...alreadyRetrievedParentRefs, + entityRef, + ]), ), ), ) ).flatMap(aggregated => aggregated); + + return uniq([...childrenRefs, entityRef]); } - return [stringifyEntityRef(entity)]; + return [entityRef]; }; const getOwners = async ( @@ -118,23 +132,15 @@ const getOwners = async ( const isAggregated = relations === 'aggregated'; const isUserEntity = entity.kind === 'User'; - const owners: string[] = []; - if (isAggregated && isGroup) { - const childEntityRefs = await getChildOwnershipEntityRefs( - entity, - catalogApi, - ); - owners.push(stringifyEntityRef(entity)); - owners.push.apply(owners, childEntityRefs); - } else if (isAggregated && isUserEntity) { - const parentEntityRefs = getMemberOfEntityRefs(entity); - owners.push.apply(owners, parentEntityRefs); - } else { - owners.push(stringifyEntityRef(entity)); + return getChildOwnershipEntityRefs(entity, catalogApi); } - return owners; + if (isAggregated && isUserEntity) { + return getMemberOfEntityRefs(entity); + } + + return [stringifyEntityRef(entity)]; }; const getOwnedEntitiesByOwners = ( diff --git a/plugins/pagerduty/CHANGELOG.md b/plugins/pagerduty/CHANGELOG.md index ad47a35b37..d37d6b4033 100644 --- a/plugins/pagerduty/CHANGELOG.md +++ b/plugins/pagerduty/CHANGELOG.md @@ -1,5 +1,32 @@ # @backstage/plugin-pagerduty +## 0.6.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/plugin-home-react@0.1.4-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## 0.6.6-next.0 + +### Patch Changes + +- b9ce306814: Minor fix to avoid usage of deprecated prop +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/plugin-home-react@0.1.4-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + ## 0.6.5 ### Patch Changes diff --git a/plugins/pagerduty/api-report.md b/plugins/pagerduty/api-report.md index 24c2e103cf..db73259dd5 100644 --- a/plugins/pagerduty/api-report.md +++ b/plugins/pagerduty/api-report.md @@ -177,7 +177,7 @@ export type PagerDutyOnCallsResponse = { }; // @public (undocumented) -const pagerDutyPlugin: BackstagePlugin<{}, {}, {}>; +const pagerDutyPlugin: BackstagePlugin<{}, {}>; export { pagerDutyPlugin }; export { pagerDutyPlugin as plugin }; diff --git a/plugins/pagerduty/package.json b/plugins/pagerduty/package.json index 3551ab55ec..4ade1d9224 100644 --- a/plugins/pagerduty/package.json +++ b/plugins/pagerduty/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-pagerduty", "description": "A Backstage plugin that integrates towards PagerDuty", - "version": "0.6.5", + "version": "0.6.6-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/periskop-backend/CHANGELOG.md b/plugins/periskop-backend/CHANGELOG.md index 79abda94c5..c4b41389b6 100644 --- a/plugins/periskop-backend/CHANGELOG.md +++ b/plugins/periskop-backend/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-periskop-backend +## 0.2.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + +## 0.2.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + ## 0.2.0 ### Minor Changes diff --git a/plugins/periskop-backend/package.json b/plugins/periskop-backend/package.json index 2d08441b02..ff276b7a55 100644 --- a/plugins/periskop-backend/package.json +++ b/plugins/periskop-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-periskop-backend", - "version": "0.2.0", + "version": "0.2.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/periskop/CHANGELOG.md b/plugins/periskop/CHANGELOG.md index 98dd5ff8d9..7030b94dfc 100644 --- a/plugins/periskop/CHANGELOG.md +++ b/plugins/periskop/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-periskop +## 0.1.23-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## 0.1.23-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + ## 0.1.22 ### Patch Changes diff --git a/plugins/periskop/api-report.md b/plugins/periskop/api-report.md index 578fb1dc49..607cbbb4d0 100644 --- a/plugins/periskop/api-report.md +++ b/plugins/periskop/api-report.md @@ -120,7 +120,7 @@ export class PeriskopClient implements PeriskopApi { } // @public (undocumented) -export const periskopPlugin: BackstagePlugin<{}, {}, {}>; +export const periskopPlugin: BackstagePlugin<{}, {}>; // @public (undocumented) export interface RequestHeaders { diff --git a/plugins/periskop/package.json b/plugins/periskop/package.json index 3d4a8976a8..9d47082842 100644 --- a/plugins/periskop/package.json +++ b/plugins/periskop/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-periskop", - "version": "0.1.22", + "version": "0.1.23-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md b/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md index 64a3619daa..127e39e251 100644 --- a/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md +++ b/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-permission-backend-module-allow-all-policy +## 0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/plugin-permission-node@0.7.16-next.1 + - @backstage/plugin-permission-common@0.7.8 + +## 0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-permission-node@0.7.16-next.0 + ## 0.1.0 ### Minor Changes diff --git a/plugins/permission-backend-module-policy-allow-all/package.json b/plugins/permission-backend-module-policy-allow-all/package.json index c2f8488369..2b309e852c 100644 --- a/plugins/permission-backend-module-policy-allow-all/package.json +++ b/plugins/permission-backend-module-policy-allow-all/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-permission-backend-module-allow-all-policy", "description": "Allow all policy backend module for the permission plugin.", - "version": "0.1.0", + "version": "0.1.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/permission-backend/CHANGELOG.md b/plugins/permission-backend/CHANGELOG.md index b85d177879..d3419ba508 100644 --- a/plugins/permission-backend/CHANGELOG.md +++ b/plugins/permission-backend/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/plugin-permission-backend +## 0.5.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/plugin-permission-node@0.7.16-next.1 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + - @backstage/plugin-permission-common@0.7.8 + +## 0.5.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/errors@1.2.2 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-permission-node@0.7.16-next.0 + ## 0.5.26 ### Patch Changes diff --git a/plugins/permission-backend/package.json b/plugins/permission-backend/package.json index 184e782782..2709204635 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.26", + "version": "0.5.28-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/permission-node/CHANGELOG.md b/plugins/permission-node/CHANGELOG.md index 5bdb0edf7b..e387547156 100644 --- a/plugins/permission-node/CHANGELOG.md +++ b/plugins/permission-node/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-permission-node +## 0.7.16-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + - @backstage/plugin-permission-common@0.7.8 + +## 0.7.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/errors@1.2.2 + - @backstage/plugin-permission-common@0.7.8 + ## 0.7.14 ### Patch Changes diff --git a/plugins/permission-node/package.json b/plugins/permission-node/package.json index c90d011332..9f57f44886 100644 --- a/plugins/permission-node/package.json +++ b/plugins/permission-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-permission-node", "description": "Common permission and authorization utilities for backend plugins", - "version": "0.7.14", + "version": "0.7.16-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/permission-react/CHANGELOG.md b/plugins/permission-react/CHANGELOG.md index 45bb4dc7d9..0df727d454 100644 --- a/plugins/permission-react/CHANGELOG.md +++ b/plugins/permission-react/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-permission-react +## 0.4.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/plugin-permission-common@0.7.8 + ## 0.4.15 ### Patch Changes diff --git a/plugins/permission-react/package.json b/plugins/permission-react/package.json index 267cf89f5f..7e79128739 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.15", + "version": "0.4.16-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/playlist-backend/CHANGELOG.md b/plugins/playlist-backend/CHANGELOG.md index 7d957d259a..c7f001ae4b 100644 --- a/plugins/playlist-backend/CHANGELOG.md +++ b/plugins/playlist-backend/CHANGELOG.md @@ -1,5 +1,38 @@ # @backstage/plugin-playlist-backend +## 0.3.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/plugin-permission-node@0.7.16-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-playlist-common@0.1.10 + +## 0.3.9-next.0 + +### Patch Changes + +- 9e46f5ff49: Added support to the playlist plugin for the new backend +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-permission-node@0.7.16-next.0 + - @backstage/plugin-playlist-common@0.1.10 + ## 0.3.7 ### Patch Changes diff --git a/plugins/playlist-backend/README.md b/plugins/playlist-backend/README.md index c0055ebdf7..b5c9b8797b 100644 --- a/plugins/playlist-backend/README.md +++ b/plugins/playlist-backend/README.md @@ -85,3 +85,20 @@ export default async function createPlugin(env: PluginEnvironment): Promise<Rout policy: new BackstagePermissionPolicy(), ... ``` + +### New Backend System + +The Playlist backend plugin has support for the [new backend system](https://backstage.io/docs/backend-system/), here's how you can set that up: + +In your `packages/backend/src/index.ts` make the following changes: + +```diff +import { createBackend } from '@backstage/backend-defaults'; + +const backend = createBackend(); + +backend.add(import('@backstage/plugin-playlist-backend')); +// ... other feature additions + +backend.start(); +``` diff --git a/plugins/playlist-backend/api-report.md b/plugins/playlist-backend/api-report.md index b755347205..40b05c25d4 100644 --- a/plugins/playlist-backend/api-report.md +++ b/plugins/playlist-backend/api-report.md @@ -3,6 +3,7 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +import { BackendFeature } from '@backstage/backend-plugin-api'; import { BackstageIdentityResponse } from '@backstage/plugin-auth-node'; import { ConditionalPolicyDecision } from '@backstage/plugin-permission-common'; import { Conditions } from '@backstage/plugin-permission-node'; @@ -80,6 +81,10 @@ export const playlistConditions: Conditions<{ >; }>; +// @public +const playlistPlugin: () => BackendFeature; +export default playlistPlugin; + // @public (undocumented) export interface RouterOptions { // (undocumented) diff --git a/plugins/playlist-backend/package.json b/plugins/playlist-backend/package.json index 78a1fa5e69..319206e6c6 100644 --- a/plugins/playlist-backend/package.json +++ b/plugins/playlist-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-playlist-backend", - "version": "0.3.7", + "version": "0.3.9-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -29,6 +29,7 @@ }, "dependencies": { "@backstage/backend-common": "workspace:^", + "@backstage/backend-plugin-api": "workspace:^", "@backstage/catalog-client": "workspace:^", "@backstage/catalog-model": "workspace:^", "@backstage/config": "workspace:^", diff --git a/plugins/playlist-backend/src/index.ts b/plugins/playlist-backend/src/index.ts index eeccd8913f..9081552e00 100644 --- a/plugins/playlist-backend/src/index.ts +++ b/plugins/playlist-backend/src/index.ts @@ -26,3 +26,4 @@ export { isPlaylistPermission, playlistConditions, } from './permissions'; +export { playlistPlugin as default } from './plugin'; diff --git a/plugins/playlist-backend/src/plugin.ts b/plugins/playlist-backend/src/plugin.ts new file mode 100644 index 0000000000..b4d926c05e --- /dev/null +++ b/plugins/playlist-backend/src/plugin.ts @@ -0,0 +1,53 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { + coreServices, + createBackendPlugin, +} from '@backstage/backend-plugin-api'; +import { createRouter } from './service'; +import { loggerToWinstonLogger } from '@backstage/backend-common'; + +/** + * Playlist backend plugin + * + * @public + */ +export const playlistPlugin = createBackendPlugin({ + pluginId: 'playlist', + register(env) { + env.registerInit({ + deps: { + http: coreServices.httpRouter, + logger: coreServices.logger, + database: coreServices.database, + identity: coreServices.identity, + discovery: coreServices.discovery, + permissions: coreServices.permissions, + }, + async init({ http, logger, database, identity, discovery, permissions }) { + http.use( + await createRouter({ + logger: loggerToWinstonLogger(logger), + database, + identity, + discovery, + permissions, + }), + ); + }, + }); + }, +}); diff --git a/plugins/playlist/CHANGELOG.md b/plugins/playlist/CHANGELOG.md index f3ed681214..301f289b8c 100644 --- a/plugins/playlist/CHANGELOG.md +++ b/plugins/playlist/CHANGELOG.md @@ -1,5 +1,39 @@ # @backstage/plugin-playlist +## 0.1.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-search-react@1.7.1-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/plugin-permission-react@0.4.16-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-playlist-common@0.1.10 + +## 0.1.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/plugin-permission-react@0.4.16-next.0 + - @backstage/plugin-search-react@1.7.1-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-playlist-common@0.1.10 + ## 0.1.16 ### Patch Changes diff --git a/plugins/playlist/api-report.md b/plugins/playlist/api-report.md index cf0ebe8a37..be7605d1e6 100644 --- a/plugins/playlist/api-report.md +++ b/plugins/playlist/api-report.md @@ -101,7 +101,6 @@ export const playlistPlugin: BackstagePlugin< { root: RouteRef<undefined>; }, - {}, {} >; ``` diff --git a/plugins/playlist/package.json b/plugins/playlist/package.json index 5613a61baa..10a3c651ed 100644 --- a/plugins/playlist/package.json +++ b/plugins/playlist/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-playlist", - "version": "0.1.16", + "version": "0.1.17-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/proxy-backend/CHANGELOG.md b/plugins/proxy-backend/CHANGELOG.md index 81319f537b..22dae797a3 100644 --- a/plugins/proxy-backend/CHANGELOG.md +++ b/plugins/proxy-backend/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-proxy-backend +## 0.4.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + +## 0.4.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + ## 0.4.0 ### Minor Changes diff --git a/plugins/proxy-backend/package.json b/plugins/proxy-backend/package.json index 2b98ba54ab..9b21073dc7 100644 --- a/plugins/proxy-backend/package.json +++ b/plugins/proxy-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-proxy-backend", "description": "A Backstage backend plugin that helps you set up proxy endpoints in the backend", - "version": "0.4.0", + "version": "0.4.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/puppetdb/CHANGELOG.md b/plugins/puppetdb/CHANGELOG.md index 1fc509b29c..5d9dc0be04 100644 --- a/plugins/puppetdb/CHANGELOG.md +++ b/plugins/puppetdb/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-puppetdb +## 0.1.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## 0.1.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + ## 0.1.7 ### Patch Changes diff --git a/plugins/puppetdb/api-report.md b/plugins/puppetdb/api-report.md index c7d1d0ff0e..890980591f 100644 --- a/plugins/puppetdb/api-report.md +++ b/plugins/puppetdb/api-report.md @@ -20,7 +20,7 @@ export const isPuppetDbAvailable: (entity: Entity) => boolean; export const PuppetDbPage: () => JSX_2.Element; // @public -const puppetdbPlugin: BackstagePlugin<{}, {}, {}>; +const puppetdbPlugin: BackstagePlugin<{}, {}>; export { puppetdbPlugin as plugin }; export { puppetdbPlugin }; diff --git a/plugins/puppetdb/package.json b/plugins/puppetdb/package.json index 73c8d5d88a..ad23b77a8f 100644 --- a/plugins/puppetdb/package.json +++ b/plugins/puppetdb/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-puppetdb", "description": "Backstage plugin to visualize resource information and Puppet facts from PuppetDB.", - "version": "0.1.7", + "version": "0.1.8-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/rollbar-backend/CHANGELOG.md b/plugins/rollbar-backend/CHANGELOG.md index 8f6eb0f67c..6d4b6b309e 100644 --- a/plugins/rollbar-backend/CHANGELOG.md +++ b/plugins/rollbar-backend/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-rollbar-backend +## 0.1.50-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/config@1.1.0 + +## 0.1.50-next.0 + +### Patch Changes + +- 407f4284be: ensure rollbar token is hidden +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + ## 0.1.48 ### Patch Changes diff --git a/plugins/rollbar-backend/package.json b/plugins/rollbar-backend/package.json index 491dcd409c..019f851d04 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.48", + "version": "0.1.50-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/rollbar/CHANGELOG.md b/plugins/rollbar/CHANGELOG.md index 77e2631e93..69c38eead1 100644 --- a/plugins/rollbar/CHANGELOG.md +++ b/plugins/rollbar/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-rollbar +## 0.4.25-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## 0.4.25-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + ## 0.4.24 ### Patch Changes diff --git a/plugins/rollbar/api-report.md b/plugins/rollbar/api-report.md index 45c672e7bb..c59475466f 100644 --- a/plugins/rollbar/api-report.md +++ b/plugins/rollbar/api-report.md @@ -196,7 +196,6 @@ const rollbarPlugin: BackstagePlugin< { entityContent: RouteRef<undefined>; }, - {}, {} >; export { rollbarPlugin as plugin }; diff --git a/plugins/rollbar/package.json b/plugins/rollbar/package.json index 262b51abc0..5a5159ceb6 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.24", + "version": "0.4.25-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md b/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md index 7ccbb5e286..366698d2e6 100644 --- a/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-scaffolder-backend-module-confluence-to-markdown +## 0.2.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/plugin-scaffolder-node@0.2.5-next.1 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/types@1.1.1 + +## 0.2.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/plugin-scaffolder-node@0.2.5-next.0 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + ## 0.2.4 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-confluence-to-markdown/package.json b/plugins/scaffolder-backend-module-confluence-to-markdown/package.json index b1ce79bf1d..bb996d7da8 100644 --- a/plugins/scaffolder-backend-module-confluence-to-markdown/package.json +++ b/plugins/scaffolder-backend-module-confluence-to-markdown/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-backend-module-confluence-to-markdown", "description": "The confluence-to-markdown module for @backstage/plugin-scaffolder-backend", - "version": "0.2.4", + "version": "0.2.6-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md index 5662119c27..8a4dc42f44 100644 --- a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-scaffolder-backend-module-cookiecutter +## 0.2.29-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/plugin-scaffolder-node@0.2.5-next.1 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/types@1.1.1 + +## 0.2.29-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/plugin-scaffolder-node@0.2.5-next.0 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + ## 0.2.27 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-cookiecutter/package.json b/plugins/scaffolder-backend-module-cookiecutter/package.json index 152b103919..908f907f13 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.27", + "version": "0.2.29-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md b/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md index 44c9337b17..3cd1812ca7 100644 --- a/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-scaffolder-backend-module-gitlab +## 0.2.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.5-next.1 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + +## 0.2.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/plugin-scaffolder-node@0.2.5-next.0 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + ## 0.2.6 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-gitlab/package.json b/plugins/scaffolder-backend-module-gitlab/package.json index e34ee93523..89d755f1dd 100644 --- a/plugins/scaffolder-backend-module-gitlab/package.json +++ b/plugins/scaffolder-backend-module-gitlab/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-gitlab", - "version": "0.2.6", + "version": "0.2.8-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder-backend-module-rails/CHANGELOG.md b/plugins/scaffolder-backend-module-rails/CHANGELOG.md index eed053be6f..c51d36eb64 100644 --- a/plugins/scaffolder-backend-module-rails/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-rails/CHANGELOG.md @@ -1,5 +1,30 @@ # @backstage/plugin-scaffolder-backend-module-rails +## 0.4.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/plugin-scaffolder-node@0.2.5-next.1 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/types@1.1.1 + +## 0.4.22-next.0 + +### Patch Changes + +- de42eebaaf: Bumped dev dependencies `@types/node` and `mock-fs`. +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/plugin-scaffolder-node@0.2.5-next.0 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + ## 0.4.20 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-rails/package.json b/plugins/scaffolder-backend-module-rails/package.json index f53072ebc3..c58fb6a035 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.20", + "version": "0.4.22-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder-backend-module-sentry/CHANGELOG.md b/plugins/scaffolder-backend-module-sentry/CHANGELOG.md index ad10b1467c..e07feaa885 100644 --- a/plugins/scaffolder-backend-module-sentry/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-sentry/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-scaffolder-backend-module-sentry +## 0.1.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.5-next.1 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + +## 0.1.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.5-next.0 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + ## 0.1.11 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-sentry/package.json b/plugins/scaffolder-backend-module-sentry/package.json index d735b34666..366f7a9126 100644 --- a/plugins/scaffolder-backend-module-sentry/package.json +++ b/plugins/scaffolder-backend-module-sentry/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-sentry", - "version": "0.1.11", + "version": "0.1.13-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md b/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md index d2df8786c0..a24ec57bb3 100644 --- a/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-scaffolder-backend-module-yeoman +## 0.2.26-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.5-next.1 + - @backstage/config@1.1.0 + - @backstage/types@1.1.1 + +## 0.2.26-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.5-next.0 + - @backstage/config@1.1.0 + - @backstage/types@1.1.1 + ## 0.2.24 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-yeoman/package.json b/plugins/scaffolder-backend-module-yeoman/package.json index 2eec398969..cd4350f681 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.24", + "version": "0.2.26-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder-backend/CHANGELOG.md b/plugins/scaffolder-backend/CHANGELOG.md index 9dd4c120b5..50fda07ce7 100644 --- a/plugins/scaffolder-backend/CHANGELOG.md +++ b/plugins/scaffolder-backend/CHANGELOG.md @@ -1,5 +1,57 @@ # @backstage/plugin-scaffolder-backend +## 1.18.0-next.1 + +### Minor Changes + +- f41099bb31: Display meaningful error to the output if Gitlab namespace not found inside `publish:gitlab`. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-backend@1.14.0-next.1 + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.2-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/plugin-permission-node@0.7.16-next.1 + - @backstage/plugin-scaffolder-node@0.2.5-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-scaffolder-common@1.4.1 + +## 1.17.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/plugin-catalog-backend@1.14.0-next.0 + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/plugin-scaffolder-node@0.2.5-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.2-next.0 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-catalog-node@1.4.6-next.0 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-permission-node@0.7.16-next.0 + - @backstage/plugin-scaffolder-common@1.4.1 + ## 1.17.0 ### Minor Changes diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index 99f6256069..cab9abae96 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.17.0", + "version": "1.18.0-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", 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 994d1c580a..dc8e3eb0ee 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 @@ -393,4 +393,23 @@ describe('publish:gitlab', () => { visibility: 'private', }); }); + + it('should show proper error message when token has insufficient permissions or namespace not found', async () => { + mockGitlabClient.Namespaces.show.mockRejectedValue({ + response: { + statusCode: 404, + }, + }); + const owner = 'infrastructure/devex'; + const repoName = 'backstage'; + + await expect( + action.handler({ + ...mockContext, + input: { repoUrl: `gitlab.com?owner=${owner}&repo=${repoName}` }, + }), + ).rejects.toThrow( + `The namespace ${owner} is not found or the user doesn't have permissions to access it`, + ); + }); }); 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 dbab7b11b8..25f78452a4 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.ts @@ -174,20 +174,33 @@ export function createPublishGitlabAction(options: { [tokenType]: token, }); - let { id: targetNamespace } = (await client.Namespaces.show(owner)) as { - id: number; - }; + let targetNamespaceId; + + try { + const namespaceResponse = (await client.Namespaces.show(owner)) as { + id: number; + }; + + targetNamespaceId = namespaceResponse.id; + } catch (e) { + if (e.response && e.response.statusCode === 404) { + throw new InputError( + `The namespace ${owner} is not found or the user doesn't have permissions to access it`, + ); + } + throw e; + } const { id: userId } = (await client.Users.current()) as { id: number; }; - if (!targetNamespace) { - targetNamespace = userId; + if (!targetNamespaceId) { + targetNamespaceId = userId; } const { id: projectId, http_url_to_repo } = await client.Projects.create({ - namespace_id: targetNamespace, + namespace_id: targetNamespaceId, name: repo, visibility: repoVisibility, ...(topics.length ? { topics } : {}), diff --git a/plugins/scaffolder-node/CHANGELOG.md b/plugins/scaffolder-node/CHANGELOG.md index 6d21eef023..c3a17eaf61 100644 --- a/plugins/scaffolder-node/CHANGELOG.md +++ b/plugins/scaffolder-node/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/plugin-scaffolder-node +## 0.2.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-common@1.4.1 + +## 0.2.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-scaffolder-common@1.4.1 + ## 0.2.3 ### Patch Changes diff --git a/plugins/scaffolder-node/package.json b/plugins/scaffolder-node/package.json index 694e440ef9..b46d4207c5 100644 --- a/plugins/scaffolder-node/package.json +++ b/plugins/scaffolder-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-node", "description": "The plugin-scaffolder-node module for @backstage/plugin-scaffolder-backend", - "version": "0.2.3", + "version": "0.2.5-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder-react/CHANGELOG.md b/plugins/scaffolder-react/CHANGELOG.md index 3b41c76469..77ef8b2d45 100644 --- a/plugins/scaffolder-react/CHANGELOG.md +++ b/plugins/scaffolder-react/CHANGELOG.md @@ -1,5 +1,37 @@ # @backstage/plugin-scaffolder-react +## 1.5.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.5 + - @backstage/plugin-scaffolder-common@1.4.1 + +## 1.5.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.5 + - @backstage/plugin-scaffolder-common@1.4.1 + ## 1.5.5 ### Patch Changes diff --git a/plugins/scaffolder-react/package.json b/plugins/scaffolder-react/package.json index e6859ad369..9722c366c4 100644 --- a/plugins/scaffolder-react/package.json +++ b/plugins/scaffolder-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-react", "description": "A frontend library that helps other Backstage plugins interact with the Scaffolder", - "version": "1.5.5", + "version": "1.5.6-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder/CHANGELOG.md b/plugins/scaffolder/CHANGELOG.md index 940331aa80..75417547a2 100644 --- a/plugins/scaffolder/CHANGELOG.md +++ b/plugins/scaffolder/CHANGELOG.md @@ -1,5 +1,48 @@ # @backstage/plugin-scaffolder +## 1.15.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-scaffolder-react@1.5.6-next.1 + - @backstage/integration-react@1.1.20-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/plugin-permission-react@0.4.16-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-scaffolder-common@1.4.1 + +## 1.15.1-next.0 + +### Patch Changes + +- b337d78c3b: fixed issue related template editor fails with multiple templates per file. +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/integration-react@1.1.20-next.0 + - @backstage/plugin-scaffolder-react@1.5.6-next.0 + - @backstage/config@1.1.0 + - @backstage/plugin-permission-react@0.4.16-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-scaffolder-common@1.4.1 + ## 1.15.0 ### Minor Changes diff --git a/plugins/scaffolder/api-report.md b/plugins/scaffolder/api-report.md index a776628da5..ddda40d95f 100644 --- a/plugins/scaffolder/api-report.md +++ b/plugins/scaffolder/api-report.md @@ -561,8 +561,7 @@ export const scaffolderPlugin: BackstagePlugin< }, true >; - }, - {} + } >; // @public @deprecated (undocumented) diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index 2e28f70cff..841e6d61d6 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.15.0", + "version": "1.15.1-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder/src/next/OngoingTask/OngoingTask.test.tsx b/plugins/scaffolder/src/next/OngoingTask/OngoingTask.test.tsx index 16d9740c15..9d3f29fe7b 100644 --- a/plugins/scaffolder/src/next/OngoingTask/OngoingTask.test.tsx +++ b/plugins/scaffolder/src/next/OngoingTask/OngoingTask.test.tsx @@ -112,4 +112,29 @@ describe('OngoingTask', () => { expect(getByTestId('cancel-button')).toHaveClass('Mui-disabled'); }); }); + + it('should initially do not display logs', async () => { + const rendered = await renderInTestApp( + <TestApiProvider apis={[[scaffolderApiRef, mockScaffolderApi]]}> + <OngoingTask /> + </TestApiProvider>, + { mountedRoutes: { '/': rootRouteRef } }, + ); + await expect(rendered.findByText('Show Logs')).resolves.toBeInTheDocument(); + }); + + it('should toggle logs visibility', async () => { + const rendered = await renderInTestApp( + <TestApiProvider apis={[[scaffolderApiRef, mockScaffolderApi]]}> + <OngoingTask /> + </TestApiProvider>, + { mountedRoutes: { '/': rootRouteRef } }, + ); + await act(async () => { + const element = await rendered.findByText('Show Logs'); + fireEvent.click(element); + }); + + await expect(rendered.findByText('Hide Logs')).resolves.toBeInTheDocument(); + }); }); diff --git a/plugins/scaffolder/src/next/OngoingTask/OngoingTask.tsx b/plugins/scaffolder/src/next/OngoingTask/OngoingTask.tsx index 91c04897d9..b483cd27cb 100644 --- a/plugins/scaffolder/src/next/OngoingTask/OngoingTask.tsx +++ b/plugins/scaffolder/src/next/OngoingTask/OngoingTask.tsx @@ -46,6 +46,9 @@ const useStyles = makeStyles(theme => ({ cancelButton: { marginRight: theme.spacing(1), }, + logsVisibilityButton: { + marginRight: theme.spacing(1), + }, })); export const OngoingTask = (props: { @@ -188,6 +191,14 @@ export const OngoingTask = (props: { > Cancel </Button> + <Button + className={classes.logsVisibilityButton} + color="primary" + variant="outlined" + onClick={() => setLogVisibleState(!logsVisible)} + > + {logsVisible ? 'Hide Logs' : 'Show Logs'} + </Button> <Button variant="contained" color="primary" diff --git a/plugins/search-backend-module-catalog/CHANGELOG.md b/plugins/search-backend-module-catalog/CHANGELOG.md index ed17ffbf63..402b501695 100644 --- a/plugins/search-backend-module-catalog/CHANGELOG.md +++ b/plugins/search-backend-module-catalog/CHANGELOG.md @@ -1,5 +1,41 @@ # @backstage/plugin-search-backend-module-catalog +## 0.1.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-search-backend-node@1.2.9-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-search-common@1.2.6 + +## 0.1.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-catalog-node@1.4.6-next.0 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-search-backend-node@1.2.9-next.0 + - @backstage/plugin-search-common@1.2.6 + ## 0.1.7 ### Patch Changes diff --git a/plugins/search-backend-module-catalog/package.json b/plugins/search-backend-module-catalog/package.json index 1fb18a303b..4963708861 100644 --- a/plugins/search-backend-module-catalog/package.json +++ b/plugins/search-backend-module-catalog/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search-backend-module-catalog", "description": "A module for the search backend that exports catalog modules", - "version": "0.1.7", + "version": "0.1.9-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/search-backend-module-elasticsearch/CHANGELOG.md b/plugins/search-backend-module-elasticsearch/CHANGELOG.md index 6b0bb7ce1a..0e92e7c3db 100644 --- a/plugins/search-backend-module-elasticsearch/CHANGELOG.md +++ b/plugins/search-backend-module-elasticsearch/CHANGELOG.md @@ -1,5 +1,30 @@ # @backstage/plugin-search-backend-module-elasticsearch +## 1.3.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-search-backend-node@1.2.9-next.1 + - @backstage/config@1.1.0 + - @backstage/integration-aws-node@0.1.6 + - @backstage/plugin-search-common@1.2.6 + +## 1.3.8-next.0 + +### Patch Changes + +- 3963d0b885: Ensure that all relevant config fields are properly marked as secret +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/integration-aws-node@0.1.6 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/plugin-search-backend-node@1.2.9-next.0 + - @backstage/plugin-search-common@1.2.6 + ## 1.3.6 ### Patch Changes diff --git a/plugins/search-backend-module-elasticsearch/package.json b/plugins/search-backend-module-elasticsearch/package.json index f1c9f39a17..36d66e827b 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": "1.3.6", + "version": "1.3.8-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/search-backend-module-explore/CHANGELOG.md b/plugins/search-backend-module-explore/CHANGELOG.md index dfcfa262de..c26bf84328 100644 --- a/plugins/search-backend-module-explore/CHANGELOG.md +++ b/plugins/search-backend-module-explore/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/plugin-search-backend-module-explore +## 0.1.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-search-backend-node@1.2.9-next.1 + - @backstage/config@1.1.0 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-common@1.2.6 + +## 0.1.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-backend-node@1.2.9-next.0 + - @backstage/plugin-search-common@1.2.6 + ## 0.1.7 ### Patch Changes diff --git a/plugins/search-backend-module-explore/package.json b/plugins/search-backend-module-explore/package.json index 630020a93d..f70d70dd73 100644 --- a/plugins/search-backend-module-explore/package.json +++ b/plugins/search-backend-module-explore/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search-backend-module-explore", "description": "A module for the search backend that exports explore modules", - "version": "0.1.7", + "version": "0.1.9-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/search-backend-module-pg/CHANGELOG.md b/plugins/search-backend-module-pg/CHANGELOG.md index e119c76e26..10453b9500 100644 --- a/plugins/search-backend-module-pg/CHANGELOG.md +++ b/plugins/search-backend-module-pg/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-search-backend-module-pg +## 0.5.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-search-backend-node@1.2.9-next.1 + - @backstage/config@1.1.0 + - @backstage/plugin-search-common@1.2.6 + +## 0.5.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/plugin-search-backend-node@1.2.9-next.0 + - @backstage/plugin-search-common@1.2.6 + ## 0.5.12 ### Patch Changes diff --git a/plugins/search-backend-module-pg/package.json b/plugins/search-backend-module-pg/package.json index a411464d52..ad9f9e0a3b 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.5.12", + "version": "0.5.14-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/search-backend-module-techdocs/CHANGELOG.md b/plugins/search-backend-module-techdocs/CHANGELOG.md index 6a0fd46b02..5364e493c6 100644 --- a/plugins/search-backend-module-techdocs/CHANGELOG.md +++ b/plugins/search-backend-module-techdocs/CHANGELOG.md @@ -1,5 +1,41 @@ # @backstage/plugin-search-backend-module-techdocs +## 0.1.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-search-backend-node@1.2.9-next.1 + - @backstage/plugin-techdocs-node@1.8.2-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-search-common@1.2.6 + +## 0.1.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/plugin-techdocs-node@1.8.2-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-catalog-node@1.4.6-next.0 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-search-backend-node@1.2.9-next.0 + - @backstage/plugin-search-common@1.2.6 + ## 0.1.7 ### Patch Changes diff --git a/plugins/search-backend-module-techdocs/package.json b/plugins/search-backend-module-techdocs/package.json index fda3d1cd8f..54e9b86afa 100644 --- a/plugins/search-backend-module-techdocs/package.json +++ b/plugins/search-backend-module-techdocs/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search-backend-module-techdocs", "description": "A module for the search backend that exports techdocs modules", - "version": "0.1.7", + "version": "0.1.9-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/search-backend-node/CHANGELOG.md b/plugins/search-backend-node/CHANGELOG.md index a6374f7701..880615383a 100644 --- a/plugins/search-backend-node/CHANGELOG.md +++ b/plugins/search-backend-node/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/plugin-search-backend-node +## 1.2.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-search-common@1.2.6 + +## 1.2.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/errors@1.2.2 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-search-common@1.2.6 + ## 1.2.7 ### Patch Changes diff --git a/plugins/search-backend-node/package.json b/plugins/search-backend-node/package.json index cc688e7bb6..587b98cd61 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": "1.2.7", + "version": "1.2.9-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/search-backend/CHANGELOG.md b/plugins/search-backend/CHANGELOG.md index b7c6873af2..a1cae58b98 100644 --- a/plugins/search-backend/CHANGELOG.md +++ b/plugins/search-backend/CHANGELOG.md @@ -1,5 +1,39 @@ # @backstage/plugin-search-backend +## 1.4.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-search-backend-node@1.2.9-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/plugin-permission-node@0.7.16-next.1 + - @backstage/config@1.1.0 + - @backstage/backend-openapi-utils@0.0.4 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-search-common@1.2.6 + +## 1.4.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-openapi-utils@0.0.4 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-permission-node@0.7.16-next.0 + - @backstage/plugin-search-backend-node@1.2.9-next.0 + - @backstage/plugin-search-common@1.2.6 + ## 1.4.3 ### Patch Changes diff --git a/plugins/search-backend/package.json b/plugins/search-backend/package.json index fc02e552cd..10c09a0178 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": "1.4.3", + "version": "1.4.5-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/search-react/CHANGELOG.md b/plugins/search-react/CHANGELOG.md index f01b5b0a54..1cb3a0e329 100644 --- a/plugins/search-react/CHANGELOG.md +++ b/plugins/search-react/CHANGELOG.md @@ -1,5 +1,32 @@ # @backstage/plugin-search-react +## 1.7.1-next.1 + +### Patch Changes + +- 703a4ffc5b: Create `createSearchResultListItem` alpha version that only supports declarative integration. +- Updated dependencies + - @backstage/frontend-plugin-api@0.1.1-next.1 + - @backstage/core-components@0.13.6-next.1 + - @backstage/frontend-app-api@0.2.0-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.5 + - @backstage/plugin-search-common@1.2.6 + +## 1.7.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.5 + - @backstage/plugin-search-common@1.2.6 + ## 1.7.0 ### Minor Changes diff --git a/plugins/search-react/alpha-api-report.md b/plugins/search-react/alpha-api-report.md new file mode 100644 index 0000000000..d62a0f1f0e --- /dev/null +++ b/plugins/search-react/alpha-api-report.md @@ -0,0 +1,65 @@ +## API Report File for "@backstage/plugin-search-react" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +/// <reference types="react" /> + +import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; +import { Extension } from '@backstage/frontend-plugin-api'; +import { ListItemProps } from '@material-ui/core'; +import { PortableSchema } from '@backstage/frontend-plugin-api'; +import { SearchDocument } from '@backstage/plugin-search-common'; +import { SearchResult } from '@backstage/plugin-search-common'; + +// @alpha (undocumented) +export type BaseSearchResultListItemProps<T = {}> = T & { + rank?: number; + result?: SearchDocument; +} & Omit<ListItemProps, 'button'>; + +// @alpha (undocumented) +export function createSearchResultListItemExtension< + TConfig extends { + noTrack?: boolean; + }, +>(options: SearchResultItemExtensionOptions<TConfig>): Extension<TConfig>; + +// @alpha (undocumented) +export type SearchResultItemExtensionComponent = < + P extends BaseSearchResultListItemProps, +>( + props: P, +) => JSX.Element | null; + +// @alpha (undocumented) +export const searchResultItemExtensionData: ConfigurableExtensionDataRef< + { + predicate?: SearchResultItemExtensionPredicate | undefined; + component: SearchResultItemExtensionComponent; + }, + {} +>; + +// @alpha (undocumented) +export type SearchResultItemExtensionOptions< + TConfig extends { + noTrack?: boolean; + }, +> = { + id: string; + at?: string; + configSchema?: PortableSchema<TConfig>; + component: (options: { + config: TConfig; + }) => Promise<SearchResultItemExtensionComponent>; + predicate?: SearchResultItemExtensionPredicate; +}; + +// @alpha (undocumented) +export type SearchResultItemExtensionPredicate = ( + result: SearchResult, +) => boolean; + +// (No @packageDocumentation comment for this package) +``` diff --git a/plugins/search-react/package.json b/plugins/search-react/package.json index 9ed330c37b..3591e75e94 100644 --- a/plugins/search-react/package.json +++ b/plugins/search-react/package.json @@ -1,13 +1,26 @@ { "name": "@backstage/plugin-search-react", - "version": "1.7.0", + "version": "1.7.1-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", "publishConfig": { - "access": "public", - "main": "dist/index.esm.js", - "types": "dist/index.d.ts" + "access": "public" + }, + "exports": { + ".": "./src/index.ts", + "./alpha": "./src/alpha.tsx", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "alpha": [ + "src/alpha.tsx" + ], + "package.json": [ + "package.json" + ] + } }, "backstage": { "role": "web-library" @@ -34,6 +47,8 @@ "dependencies": { "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", + "@backstage/frontend-app-api": "workspace:^", + "@backstage/frontend-plugin-api": "workspace:^", "@backstage/plugin-search-common": "workspace:^", "@backstage/theme": "workspace:^", "@backstage/types": "workspace:^", diff --git a/plugins/search-react/src/alpha.test.tsx b/plugins/search-react/src/alpha.test.tsx new file mode 100644 index 0000000000..b61a400832 --- /dev/null +++ b/plugins/search-react/src/alpha.test.tsx @@ -0,0 +1,206 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; + +import { render, screen } from '@testing-library/react'; + +import { + createExtensionInput, + createPageExtension, + createPlugin, + createSchemaFromZod, +} from '@backstage/frontend-plugin-api'; +import { SearchResult } from '@backstage/plugin-search-common'; +import { createApp } from '@backstage/frontend-app-api'; +import { MockConfigApi } from '@backstage/test-utils'; + +import { + BaseSearchResultListItemProps, + createSearchResultListItemExtension, + searchResultItemExtensionData as searchResultListItemExtensionData, +} from './alpha'; + +// TODO: Remove this mock when we have a permanent solution for nav items extensions +// The `GraphiQLIcon` used in "packages/frontend-app-api/src/extensions/CoreNav.tsx" file +// is throwing a "ReferenceError: ref is not defined" error during test +jest.mock('@backstage/plugin-graphiql', () => ({ + ...jest.requireActual('@backstage/plugin-graphiql'), + GraphiQLIcon: () => null, +})); + +describe('createSearchResultListItemExtension', () => { + it('Should use the correct result component', async () => { + type TechDocsSearchReasulListItemProps = BaseSearchResultListItemProps<{ + lineClamp: number; + }>; + const TechDocsSearchResultItemComponent = ( + props: TechDocsSearchReasulListItemProps, + ) => ( + <div> + TechDocs - Rank: {props.rank} - Line clamp: {props.lineClamp} + </div> + ); + + const TechDocsSearchResultItemExtension = + createSearchResultListItemExtension({ + id: 'techdocs', + at: 'plugin.search.page/items', + configSchema: createSchemaFromZod(z => + z.object({ + noTrack: z.boolean().default(true), + lineClamp: z.number().default(5), + }), + ), + predicate: result => result.type === 'techdocs', + component: + async ({ config }) => + props => + <TechDocsSearchResultItemComponent {...props} {...config} />, + }); + + const ExploreSearchResultItemComponent = ( + props: BaseSearchResultListItemProps, + ) => <div>Explore - Rank: {props.rank}</div>; + + const ExploreSearchResultItemExtension = + createSearchResultListItemExtension({ + id: 'explore', + at: 'plugin.search.page/items', + predicate: result => result.type === 'explore', + component: async () => ExploreSearchResultItemComponent, + }); + + const SearchPageExtension = createPageExtension({ + id: 'plugin.search.page', + defaultPath: '/', + inputs: { + items: createExtensionInput({ + item: searchResultListItemExtensionData, + }), + }, + loader: async ({ inputs }) => { + const results = [ + { + type: 'techdocs', + rank: 1, + document: { + title: 'Title1', + text: 'Text1', + location: '/location1', + }, + }, + { + type: 'explore', + rank: 2, + document: { + title: 'Title2', + text: 'Text2', + location: '/location2', + }, + }, + { + type: 'other', + rank: 3, + document: { + title: 'Title3', + text: 'Text3', + location: '/location3', + }, + }, + ]; + + const DefaultResultItem = (props: BaseSearchResultListItemProps) => ( + <div>Default - Rank: {props.rank}</div> + ); + + const getResultItemComponent = (result: SearchResult) => { + const value = inputs.items.find(({ item }) => + item?.predicate?.(result), + ); + return value?.item.component ?? DefaultResultItem; + }; + + const Component = () => { + return ( + <div> + <h1>Search Page</h1> + <ul> + {results.map((result, index) => { + const SearchResultListItem = getResultItemComponent(result); + return ( + <SearchResultListItem + key={index} + rank={result.rank} + result={result.document} + /> + ); + })} + </ul> + </div> + ); + }; + + return <Component />; + }, + }); + + const SearchPlugin = createPlugin({ + id: 'search.plugin', + extensions: [ + SearchPageExtension, + ExploreSearchResultItemExtension, + TechDocsSearchResultItemExtension, + ], + }); + + const app = createApp({ + plugins: [SearchPlugin], + configLoader: async () => + new MockConfigApi({ + app: { + extensions: [ + { + 'plugin.search.result.item.techdocs': { + config: { + lineClamp: 3, + }, + }, + }, + ], + }, + }), + }); + + render(app.createRoot()); + + expect(await screen.findByText(/Search Page/)).toBeInTheDocument(); + + expect( + await screen.findByText(/TechDocs - Rank: 1 - Line clamp: 3/, { + exact: false, + }), + ).toBeInTheDocument(); + + expect( + await screen.findByText(/Explore - Rank: 2/, { exact: false }), + ).toBeInTheDocument(); + + expect( + await screen.findByText(/Default - Rank: 3/, { exact: false }), + ).toBeInTheDocument(); + }); +}); diff --git a/plugins/search-react/src/alpha.tsx b/plugins/search-react/src/alpha.tsx new file mode 100644 index 0000000000..5b44a7bbb5 --- /dev/null +++ b/plugins/search-react/src/alpha.tsx @@ -0,0 +1,132 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React, { lazy, Suspense } from 'react'; + +import { ListItemProps } from '@material-ui/core'; + +import { + ExtensionBoundary, + PortableSchema, + createExtension, + createExtensionDataRef, + createSchemaFromZod, +} from '@backstage/frontend-plugin-api'; +import { Progress } from '@backstage/core-components'; +import { SearchDocument, SearchResult } from '@backstage/plugin-search-common'; + +import { SearchResultListItemExtension } from './extensions'; + +/** @alpha */ +export type BaseSearchResultListItemProps<T = {}> = T & { + rank?: number; + result?: SearchDocument; +} & Omit<ListItemProps, 'button'>; + +/** @alpha */ +export type SearchResultItemExtensionComponent = < + P extends BaseSearchResultListItemProps, +>( + props: P, +) => JSX.Element | null; + +/** @alpha */ +export type SearchResultItemExtensionPredicate = ( + result: SearchResult, +) => boolean; + +/** @alpha */ +export const searchResultItemExtensionData = createExtensionDataRef<{ + predicate?: SearchResultItemExtensionPredicate; + component: SearchResultItemExtensionComponent; +}>('plugin.search.result.item.data'); + +/** @alpha */ +export type SearchResultItemExtensionOptions< + TConfig extends { noTrack?: boolean }, +> = { + /** + * The extension id. + */ + id: string; + /** + * The extension attachment point (e.g., search modal or page). + */ + at?: string; + /** + * Optional extension config schema. + */ + configSchema?: PortableSchema<TConfig>; + /** + * The extension component. + */ + component: (options: { + config: TConfig; + }) => Promise<SearchResultItemExtensionComponent>; + /** + * When an extension defines a predicate, it returns true if the result should be rendered by that extension. + * Defaults to a predicate that returns true, which means it renders all sorts of results. + */ + predicate?: SearchResultItemExtensionPredicate; +}; + +/** @alpha */ +export function createSearchResultListItemExtension< + TConfig extends { noTrack?: boolean }, +>(options: SearchResultItemExtensionOptions<TConfig>) { + const configSchema = + 'configSchema' in options + ? options.configSchema + : (createSchemaFromZod(z => + z.object({ + noTrack: z.boolean().default(false), + }), + ) as PortableSchema<TConfig>); + return createExtension({ + id: `plugin.search.result.item.${options.id}`, + at: options.at ?? 'plugin.search.page/items', + configSchema, + output: { + item: searchResultItemExtensionData, + }, + factory({ bind, config, source }) { + const LazyComponent = lazy(() => + options + .component({ config }) + .then(component => ({ default: component })), + ) as unknown as SearchResultItemExtensionComponent; + + bind({ + item: { + predicate: options.predicate, + component: props => ( + <ExtensionBoundary source={source}> + <Suspense fallback={<Progress />}> + <SearchResultListItemExtension + rank={props.rank} + result={props.result} + noTrack={config.noTrack} + > + <LazyComponent {...props} /> + </SearchResultListItemExtension> + </Suspense> + </ExtensionBoundary> + ), + }, + }); + }, + }); +} diff --git a/plugins/search-react/src/extensions.tsx b/plugins/search-react/src/extensions.tsx index a29311b1ff..132fad25b5 100644 --- a/plugins/search-react/src/extensions.tsx +++ b/plugins/search-react/src/extensions.tsx @@ -90,7 +90,7 @@ export type SearchResultListItemExtensionProps<Props extends {} = {}> = Props & * Extends children with extension capabilities. * @param props - see {@link SearchResultListItemExtensionProps}. */ -const SearchResultListItemExtension = ( +export const SearchResultListItemExtension = ( props: SearchResultListItemExtensionProps, ) => { const { diff --git a/plugins/search/CHANGELOG.md b/plugins/search/CHANGELOG.md index 24ea0920c7..714e4ef1de 100644 --- a/plugins/search/CHANGELOG.md +++ b/plugins/search/CHANGELOG.md @@ -1,5 +1,41 @@ # @backstage/plugin-search +## 1.4.1-next.1 + +### Patch Changes + +- e5a2956dd2: Create an experimental search plugin that is compatible with the declarative integration system, it is exported from `/alpha` subpath. +- Updated dependencies + - @backstage/frontend-plugin-api@0.1.1-next.1 + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-search-react@1.7.1-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.5 + - @backstage/plugin-search-common@1.2.6 + +## 1.4.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/config@1.1.0 + - @backstage/plugin-search-react@1.7.1-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.5 + - @backstage/plugin-search-common@1.2.6 + ## 1.4.0 ### Minor Changes diff --git a/plugins/search/alpha-api-report.md b/plugins/search/alpha-api-report.md new file mode 100644 index 0000000000..5799ff5cd6 --- /dev/null +++ b/plugins/search/alpha-api-report.md @@ -0,0 +1,28 @@ +## API Report File for "@backstage/plugin-search" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { BackstagePlugin } from '@backstage/frontend-plugin-api'; +import { Extension } from '@backstage/frontend-plugin-api'; + +// @alpha (undocumented) +const _default: BackstagePlugin; +export default _default; + +// @alpha (undocumented) +export const SearchApi: Extension<{}>; + +// @alpha (undocumented) +export const SearchNavItem: Extension<{ + title: string; +}>; + +// @alpha (undocumented) +export const SearchPage: Extension<{ + path: string; + noTrack: boolean; +}>; + +// (No @packageDocumentation comment for this package) +``` diff --git a/plugins/search/api-report.md b/plugins/search/api-report.md index 616b63bd31..64f596ab11 100644 --- a/plugins/search/api-report.md +++ b/plugins/search/api-report.md @@ -71,7 +71,6 @@ const searchPlugin: BackstagePlugin< { root: RouteRef<undefined>; }, - {}, {} >; export { searchPlugin as plugin }; diff --git a/plugins/search/package.json b/plugins/search/package.json index d31a9e0c1f..6067d0004c 100644 --- a/plugins/search/package.json +++ b/plugins/search/package.json @@ -1,14 +1,27 @@ { "name": "@backstage/plugin-search", "description": "The Backstage plugin that provides your backstage app with search", - "version": "1.4.0", + "version": "1.4.1-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", "publishConfig": { - "access": "public", - "main": "dist/index.esm.js", - "types": "dist/index.d.ts" + "access": "public" + }, + "exports": { + ".": "./src/index.ts", + "./alpha": "./src/alpha.tsx", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "alpha": [ + "src/alpha.tsx" + ], + "package.json": [ + "package.json" + ] + } }, "backstage": { "role": "frontend-plugin" @@ -38,6 +51,7 @@ "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/errors": "workspace:^", + "@backstage/frontend-plugin-api": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", "@backstage/plugin-search-common": "workspace:^", "@backstage/plugin-search-react": "workspace:^", diff --git a/plugins/search/src/alpha.tsx b/plugins/search/src/alpha.tsx new file mode 100644 index 0000000000..6d74c85d49 --- /dev/null +++ b/plugins/search/src/alpha.tsx @@ -0,0 +1,247 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; + +import { makeStyles, Theme, Grid, Paper } from '@material-ui/core'; +import SearchIcon from '@material-ui/icons/Search'; + +import { + CatalogIcon, + Content, + DocsIcon, + Header, + Page, + useSidebarPinState, +} from '@backstage/core-components'; +import { + createRouteRef, + useApi, + DiscoveryApi, + IdentityApi, + discoveryApiRef, + identityApiRef, +} from '@backstage/core-plugin-api'; + +import { + createPlugin, + createApiExtension, + createPageExtension, + createExtensionInput, + createNavItemExtension, + createSchemaFromZod, +} from '@backstage/frontend-plugin-api'; + +import { + catalogApiRef, + CATALOG_FILTER_EXISTS, +} from '@backstage/plugin-catalog-react'; + +import { + DefaultResultListItem, + SearchBar, + SearchFilter, + SearchPagination, + SearchResult as SearchResults, + SearchResultPager, + useSearch, + SearchContextProvider, +} from '@backstage/plugin-search-react'; +import { SearchResult } from '@backstage/plugin-search-common'; +import { searchApiRef } from '@backstage/plugin-search-react'; +import { searchResultItemExtensionData } from '@backstage/plugin-search-react/alpha'; + +import { SearchClient } from './apis'; +import { SearchType } from './components/SearchType'; +import { UrlUpdater } from './components/SearchPage/SearchPage'; + +/** @alpha */ +export const SearchApi = createApiExtension({ + factory: { + api: searchApiRef, + deps: { discoveryApi: discoveryApiRef, identityApi: identityApiRef }, + factory: ({ + identityApi, + discoveryApi, + }: { + identityApi: IdentityApi; + discoveryApi: DiscoveryApi; + }) => new SearchClient({ discoveryApi, identityApi }), + }, +}); + +const useSearchPageStyles = makeStyles((theme: Theme) => ({ + filter: { + '& + &': { + marginTop: theme.spacing(2.5), + }, + }, + filters: { + padding: theme.spacing(2), + marginTop: theme.spacing(2), + }, +})); + +const searchRouteRef = createRouteRef({ id: 'plugin.search.page' }); + +/** @alpha */ +export const SearchPage = createPageExtension({ + id: 'plugin.search.page', + routeRef: searchRouteRef, + configSchema: createSchemaFromZod(z => + z.object({ + path: z.string().default('/search'), + noTrack: z.boolean().default(false), + }), + ), + inputs: { + items: createExtensionInput({ + item: searchResultItemExtensionData, + }), + }, + loader: async ({ config, inputs }) => { + const getResultItemComponent = (result: SearchResult) => { + const value = inputs.items.find(({ item }) => item?.predicate?.(result)); + return value?.item.component ?? DefaultResultListItem; + }; + + const Component = () => { + const classes = useSearchPageStyles(); + const { isMobile } = useSidebarPinState(); + const { types } = useSearch(); + const catalogApi = useApi(catalogApiRef); + + return ( + <Page themeId="home"> + {!isMobile && <Header title="Search" />} + <Content> + <Grid container direction="row"> + <Grid item xs={12}> + <SearchBar debounceTime={100} /> + </Grid> + {!isMobile && ( + <Grid item xs={3}> + <SearchType.Accordion + name="Result Type" + defaultValue="software-catalog" + showCounts + types={[ + { + value: 'software-catalog', + name: 'Software Catalog', + icon: <CatalogIcon />, + }, + { + value: 'techdocs', + name: 'Documentation', + icon: <DocsIcon />, + }, + { + value: 'adr', + name: 'Architecture Decision Records', + icon: <DocsIcon />, + }, + ]} + /> + <Paper className={classes.filters}> + {types.includes('techdocs') && ( + <SearchFilter.Select + className={classes.filter} + label="Entity" + name="name" + values={async () => { + // Return a list of entities which are documented. + const { items } = await catalogApi.getEntities({ + fields: ['metadata.name'], + filter: { + 'metadata.annotations.backstage.io/techdocs-ref': + CATALOG_FILTER_EXISTS, + }, + }); + + const names = items.map( + entity => entity.metadata.name, + ); + names.sort(); + return names; + }} + /> + )} + <SearchFilter.Select + className={classes.filter} + label="Kind" + name="kind" + values={['Component', 'Template']} + /> + <SearchFilter.Checkbox + className={classes.filter} + label="Lifecycle" + name="lifecycle" + values={['experimental', 'production']} + /> + </Paper> + </Grid> + )} + <Grid item xs> + <SearchPagination /> + <SearchResults> + {({ results }) => + results.map((result, index) => { + const { noTrack } = config; + const { document, ...rest } = result; + const SearchResultListItem = + getResultItemComponent(result); + return ( + <SearchResultListItem + {...rest} + key={index} + result={document} + noTrack={noTrack} + /> + ); + }) + } + </SearchResults> + <SearchResultPager /> + </Grid> + </Grid> + </Content> + </Page> + ); + }; + + return ( + <SearchContextProvider> + <UrlUpdater /> + <Component /> + </SearchContextProvider> + ); + }, +}); + +/** @alpha */ +export const SearchNavItem = createNavItemExtension({ + id: 'plugin.search.nav.index', + routeRef: searchRouteRef, + title: 'Search', + icon: SearchIcon, +}); + +/** @alpha */ +export default createPlugin({ + id: 'plugin.search', + extensions: [SearchApi, SearchPage, SearchNavItem], +}); diff --git a/plugins/search/src/components/SearchPage/UrlUpdater.tsx b/plugins/search/src/components/SearchPage/UrlUpdater.tsx new file mode 100644 index 0000000000..d44195b6e2 --- /dev/null +++ b/plugins/search/src/components/SearchPage/UrlUpdater.tsx @@ -0,0 +1,85 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { useEffect } from 'react'; +import usePrevious from 'react-use/lib/usePrevious'; +import qs from 'qs'; +import { useLocation } from 'react-router-dom'; +import { useSearch } from '@backstage/plugin-search-react'; +import { JsonObject } from '@backstage/types'; + +export const UrlUpdater = () => { + const location = useLocation(); + const { + term, + setTerm, + types, + setTypes, + pageCursor, + setPageCursor, + filters, + setFilters, + } = useSearch(); + + const prevQueryParams = usePrevious(location.search); + + useEffect(() => { + // Only respond to changes to url query params + if (location.search === prevQueryParams) { + return; + } + + const query = + qs.parse(location.search.substring(1), { arrayLimit: 0 }) || {}; + + if (query.filters) { + setFilters(query.filters as JsonObject); + } + + if (query.query) { + setTerm(query.query as string); + } + + if (query.pageCursor) { + setPageCursor(query.pageCursor as string); + } + + if (query.types) { + setTypes(query.types as string[]); + } + }, [prevQueryParams, location, setTerm, setTypes, setPageCursor, setFilters]); + + useEffect(() => { + const newParams = qs.stringify( + { + query: term, + types, + pageCursor, + filters, + }, + { arrayFormat: 'brackets' }, + ); + const newUrl = `${window.location.pathname}?${newParams}`; + + // We directly manipulate window history here in order to not re-render + // infinitely (state => location => state => etc). The intention of this + // code is just to ensure the right query/filters are loaded when a user + // clicks the "back" button after clicking a result. + window.history.replaceState(null, document.title, newUrl); + }, [term, types, pageCursor, filters]); + + return null; +}; diff --git a/plugins/sentry/CHANGELOG.md b/plugins/sentry/CHANGELOG.md index dcb5684f9a..0e2a3d446c 100644 --- a/plugins/sentry/CHANGELOG.md +++ b/plugins/sentry/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-sentry +## 0.5.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## 0.5.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + ## 0.5.9 ### Patch Changes diff --git a/plugins/sentry/api-report.md b/plugins/sentry/api-report.md index 43a5caa0bd..dc5fb69556 100644 --- a/plugins/sentry/api-report.md +++ b/plugins/sentry/api-report.md @@ -138,7 +138,6 @@ const sentryPlugin: BackstagePlugin< { root: RouteRef<undefined>; }, - {}, {} >; export { sentryPlugin as plugin }; diff --git a/plugins/sentry/package.json b/plugins/sentry/package.json index be9230572d..b6f502baee 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.5.9", + "version": "0.5.10-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/shortcuts/CHANGELOG.md b/plugins/shortcuts/CHANGELOG.md index c8774a9fcb..29eb3eefc5 100644 --- a/plugins/shortcuts/CHANGELOG.md +++ b/plugins/shortcuts/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-shortcuts +## 0.3.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + +## 0.3.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + ## 0.3.14 ### Patch Changes diff --git a/plugins/shortcuts/api-report.md b/plugins/shortcuts/api-report.md index ae8225d5b5..64d9d15156 100644 --- a/plugins/shortcuts/api-report.md +++ b/plugins/shortcuts/api-report.md @@ -58,7 +58,7 @@ export const Shortcuts: (props: ShortcutsProps) => JSX_2.Element; export const shortcutsApiRef: ApiRef<ShortcutApi>; // @public (undocumented) -export const shortcutsPlugin: BackstagePlugin<{}, {}, {}>; +export const shortcutsPlugin: BackstagePlugin<{}, {}>; // @public export interface ShortcutsProps { diff --git a/plugins/shortcuts/package.json b/plugins/shortcuts/package.json index a344e111c6..b3f3d53858 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.3.14", + "version": "0.3.15-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/sonarqube-backend/CHANGELOG.md b/plugins/sonarqube-backend/CHANGELOG.md index f7353f9985..d5f8999191 100644 --- a/plugins/sonarqube-backend/CHANGELOG.md +++ b/plugins/sonarqube-backend/CHANGELOG.md @@ -1,5 +1,26 @@ # @backstage/plugin-sonarqube-backend +## 0.2.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + +## 0.2.7-next.0 + +### Patch Changes + +- a5d592d0ad: Added support for the [new backend system](https://backstage.io/docs/backend-system/) +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/errors@1.2.2 + ## 0.2.5 ### Patch Changes diff --git a/plugins/sonarqube-backend/README.md b/plugins/sonarqube-backend/README.md index b417fea7c4..1a1e2ae2dd 100644 --- a/plugins/sonarqube-backend/README.md +++ b/plugins/sonarqube-backend/README.md @@ -2,6 +2,20 @@ Welcome to the sonarqube-backend backend plugin! +## New Backend System + +The Sonarqube backend plugin has support for the [new backend system](https://backstage.io/docs/backend-system/), here's how you can set that up: + +In your `packages/backend/src/index.ts` make the following changes: + +```diff + import { createBackend } from '@backstage/backend-defaults'; + const backend = createBackend(); + // ... other feature additions ++ backend.add(import('@backstage/plugin-sonarqube-backend'); + backend.start(); +``` + ## Integrating into a backstage instance This plugin needs to be added to an existing backstage instance. diff --git a/plugins/sonarqube-backend/api-report.md b/plugins/sonarqube-backend/api-report.md index 535db37185..c3c684f9d4 100644 --- a/plugins/sonarqube-backend/api-report.md +++ b/plugins/sonarqube-backend/api-report.md @@ -3,6 +3,7 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +import { BackendFeature } from '@backstage/backend-plugin-api'; import { Config } from '@backstage/config'; import express from 'express'; import { Logger } from 'winston'; @@ -72,5 +73,9 @@ export interface SonarqubeMeasure { value: string; } +// @public +const sonarqubePlugin: () => BackendFeature; +export default sonarqubePlugin; + // (No @packageDocumentation comment for this package) ``` diff --git a/plugins/sonarqube-backend/package.json b/plugins/sonarqube-backend/package.json index 2b1d8182c8..1ff45c2ac9 100644 --- a/plugins/sonarqube-backend/package.json +++ b/plugins/sonarqube-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-sonarqube-backend", - "version": "0.2.5", + "version": "0.2.7-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -29,6 +29,7 @@ }, "dependencies": { "@backstage/backend-common": "workspace:^", + "@backstage/backend-plugin-api": "workspace:^", "@backstage/config": "workspace:^", "@backstage/errors": "workspace:^", "@types/express": "*", diff --git a/plugins/sonarqube-backend/src/index.ts b/plugins/sonarqube-backend/src/index.ts index c91aef09f8..4bb82df34e 100644 --- a/plugins/sonarqube-backend/src/index.ts +++ b/plugins/sonarqube-backend/src/index.ts @@ -16,3 +16,4 @@ export * from './service/router'; export * from './service/sonarqubeInfoProvider'; +export { sonarqubePlugin as default } from './plugin'; diff --git a/packages/app/cypress/support/commands.js b/plugins/sonarqube-backend/src/plugin.test.tsx similarity index 77% rename from packages/app/cypress/support/commands.js rename to plugins/sonarqube-backend/src/plugin.test.tsx index f26d2c999b..9b26a88862 100644 --- a/packages/app/cypress/support/commands.js +++ b/plugins/sonarqube-backend/src/plugin.test.tsx @@ -13,7 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -Cypress.Commands.add('enterAsGuest', () => { - cy.visit('/'); - cy.get('button').contains('Enter').click(); +import { sonarqubePlugin } from './plugin'; + +describe('sonarqube', () => { + it('should export the sonarqube plugin', () => { + expect(sonarqubePlugin).toBeDefined(); + }); }); diff --git a/plugins/sonarqube-backend/src/plugin.ts b/plugins/sonarqube-backend/src/plugin.ts new file mode 100644 index 0000000000..fd4fb77fb4 --- /dev/null +++ b/plugins/sonarqube-backend/src/plugin.ts @@ -0,0 +1,57 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { loggerToWinstonLogger } from '@backstage/backend-common'; +import { + createBackendPlugin, + coreServices, +} from '@backstage/backend-plugin-api'; +import { DefaultSonarqubeInfoProvider } from './service/sonarqubeInfoProvider'; +import { createRouter } from './service/router'; + +/** + * Sonarqube backend plugin + * + * @public + */ +export const sonarqubePlugin = createBackendPlugin({ + pluginId: 'sonarqube', + register(env) { + env.registerInit({ + deps: { + logger: coreServices.logger, + config: coreServices.rootConfig, + httpRouter: coreServices.httpRouter, + }, + async init({ logger, config, httpRouter }) { + const winstonLogger = loggerToWinstonLogger(logger); + httpRouter.use( + await createRouter({ + /** + * Logger for logging purposes + */ + logger: winstonLogger, + /** + * Info provider to be able to get all necessary information for the APIs + */ + sonarqubeInfoProvider: + DefaultSonarqubeInfoProvider.fromConfig(config), + }), + ); + }, + }); + }, +}); diff --git a/plugins/sonarqube-react/CHANGELOG.md b/plugins/sonarqube-react/CHANGELOG.md index e8fdd45a40..5fea1d2e9e 100644 --- a/plugins/sonarqube-react/CHANGELOG.md +++ b/plugins/sonarqube-react/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-sonarqube-react +## 0.1.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + ## 0.1.8 ### Patch Changes diff --git a/plugins/sonarqube-react/package.json b/plugins/sonarqube-react/package.json index 7ffb55ad69..6e1adb42f9 100644 --- a/plugins/sonarqube-react/package.json +++ b/plugins/sonarqube-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-sonarqube-react", - "version": "0.1.8", + "version": "0.1.9-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/sonarqube/CHANGELOG.md b/plugins/sonarqube/CHANGELOG.md index 178058ef03..d951104286 100644 --- a/plugins/sonarqube/CHANGELOG.md +++ b/plugins/sonarqube/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-sonarqube +## 0.7.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-sonarqube-react@0.1.9-next.0 + +## 0.7.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-sonarqube-react@0.1.9-next.0 + ## 0.7.5 ### Patch Changes diff --git a/plugins/sonarqube/api-report.md b/plugins/sonarqube/api-report.md index 72f2eb1c09..32894b6eeb 100644 --- a/plugins/sonarqube/api-report.md +++ b/plugins/sonarqube/api-report.md @@ -71,5 +71,5 @@ export type SonarQubeContentPageProps = { }; // @public (undocumented) -export const sonarQubePlugin: BackstagePlugin<{}, {}, {}>; +export const sonarQubePlugin: BackstagePlugin<{}, {}>; ``` diff --git a/plugins/sonarqube/package.json b/plugins/sonarqube/package.json index 238423fc98..b68c28b76b 100644 --- a/plugins/sonarqube/package.json +++ b/plugins/sonarqube/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-sonarqube", "description": "", - "version": "0.7.5", + "version": "0.7.6-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/splunk-on-call/CHANGELOG.md b/plugins/splunk-on-call/CHANGELOG.md index 3360ebdcae..1117cfee3e 100644 --- a/plugins/splunk-on-call/CHANGELOG.md +++ b/plugins/splunk-on-call/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-splunk-on-call +## 0.4.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + +## 0.4.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/theme@0.4.2 + ## 0.4.13 ### Patch Changes diff --git a/plugins/splunk-on-call/api-report.md b/plugins/splunk-on-call/api-report.md index 4c054e8a1a..d80ee6f874 100644 --- a/plugins/splunk-on-call/api-report.md +++ b/plugins/splunk-on-call/api-report.md @@ -240,7 +240,6 @@ const splunkOnCallPlugin: BackstagePlugin< { root: RouteRef<undefined>; }, - {}, {} >; export { splunkOnCallPlugin as plugin }; diff --git a/plugins/splunk-on-call/package.json b/plugins/splunk-on-call/package.json index d86d555fe1..b677f6f425 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.4.13", + "version": "0.4.14-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/stack-overflow-backend/CHANGELOG.md b/plugins/stack-overflow-backend/CHANGELOG.md index f5922da46c..149dd6913f 100644 --- a/plugins/stack-overflow-backend/CHANGELOG.md +++ b/plugins/stack-overflow-backend/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-stack-overflow-backend +## 0.2.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/config@1.1.0 + - @backstage/plugin-search-common@1.2.6 + +## 0.2.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/plugin-search-common@1.2.6 + ## 0.2.7 ### Patch Changes diff --git a/plugins/stack-overflow-backend/package.json b/plugins/stack-overflow-backend/package.json index 2825bfc310..57c8d6bcfc 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.2.7", + "version": "0.2.9-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/stack-overflow/CHANGELOG.md b/plugins/stack-overflow/CHANGELOG.md index 857aa92607..d0866a9211 100644 --- a/plugins/stack-overflow/CHANGELOG.md +++ b/plugins/stack-overflow/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/plugin-stack-overflow +## 0.1.21-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-search-react@1.7.1-next.1 + - @backstage/plugin-home-react@0.1.4-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/theme@0.4.2 + - @backstage/plugin-search-common@1.2.6 + +## 0.1.21-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/config@1.1.0 + - @backstage/plugin-home-react@0.1.4-next.0 + - @backstage/plugin-search-react@1.7.1-next.0 + - @backstage/theme@0.4.2 + - @backstage/plugin-search-common@1.2.6 + ## 0.1.20 ### Patch Changes diff --git a/plugins/stack-overflow/api-report.md b/plugins/stack-overflow/api-report.md index 4277aaac24..293c2ac226 100644 --- a/plugins/stack-overflow/api-report.md +++ b/plugins/stack-overflow/api-report.md @@ -32,7 +32,7 @@ export const stackOverflowApiRef: ApiRef<StackOverflowApi>; export const StackOverflowIcon: () => React_2.JSX.Element; // @public -export const stackOverflowPlugin: BackstagePlugin<{}, {}, {}>; +export const stackOverflowPlugin: BackstagePlugin<{}, {}>; // @public export type StackOverflowQuestion = { diff --git a/plugins/stack-overflow/package.json b/plugins/stack-overflow/package.json index 2e211987c4..eef133b305 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.20", + "version": "0.1.21-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/stackstorm/CHANGELOG.md b/plugins/stackstorm/CHANGELOG.md index fcb1dfed42..6734c7dd27 100644 --- a/plugins/stackstorm/CHANGELOG.md +++ b/plugins/stackstorm/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-stackstorm +## 0.1.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## 0.1.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + ## 0.1.6 ### Patch Changes diff --git a/plugins/stackstorm/api-report.md b/plugins/stackstorm/api-report.md index f6279be1bd..14f09c3202 100644 --- a/plugins/stackstorm/api-report.md +++ b/plugins/stackstorm/api-report.md @@ -25,7 +25,6 @@ export const stackstormPlugin: BackstagePlugin< { root: RouteRef<undefined>; }, - {}, {} >; ``` diff --git a/plugins/stackstorm/package.json b/plugins/stackstorm/package.json index df9a9f1d41..bd945feb36 100644 --- a/plugins/stackstorm/package.json +++ b/plugins/stackstorm/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-stackstorm", "description": "A Backstage plugin that integrates towards StackStorm", - "version": "0.1.6", + "version": "0.1.7-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/tech-insights-backend-module-jsonfc/CHANGELOG.md b/plugins/tech-insights-backend-module-jsonfc/CHANGELOG.md index 78a66da5a4..f8f70f1c0c 100644 --- a/plugins/tech-insights-backend-module-jsonfc/CHANGELOG.md +++ b/plugins/tech-insights-backend-module-jsonfc/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-tech-insights-backend-module-jsonfc +## 0.1.37-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/plugin-tech-insights-node@0.4.11-next.1 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + - @backstage/plugin-tech-insights-common@0.2.12 + +## 0.1.37-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + - @backstage/plugin-tech-insights-common@0.2.12 + - @backstage/plugin-tech-insights-node@0.4.11-next.0 + ## 0.1.35 ### Patch Changes diff --git a/plugins/tech-insights-backend-module-jsonfc/package.json b/plugins/tech-insights-backend-module-jsonfc/package.json index 65e94067e2..bd7b2c2226 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.35", + "version": "0.1.37-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/tech-insights-backend/CHANGELOG.md b/plugins/tech-insights-backend/CHANGELOG.md index 368490c8bb..cbafe8f3b5 100644 --- a/plugins/tech-insights-backend/CHANGELOG.md +++ b/plugins/tech-insights-backend/CHANGELOG.md @@ -1,5 +1,36 @@ # @backstage/plugin-tech-insights-backend +## 0.5.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/plugin-tech-insights-node@0.4.11-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + +## 0.5.19-next.0 + +### Patch Changes + +- cc7dddfa7f: Increase the maximum allowed length of an entity filter for tech insights fact schemas. +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + - @backstage/plugin-tech-insights-node@0.4.11-next.0 + ## 0.5.17 ### Patch Changes diff --git a/plugins/tech-insights-backend/migrations/20230925145017_increase_filter_fact_schemas_size.js b/plugins/tech-insights-backend/migrations/20230925145017_increase_filter_fact_schemas_size.js new file mode 100644 index 0000000000..848fb25777 --- /dev/null +++ b/plugins/tech-insights-backend/migrations/20230925145017_increase_filter_fact_schemas_size.js @@ -0,0 +1,37 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const factSchemasTable = 'fact_schemas'; + +/** + * @param { import("knex").Knex } knex + * @returns { Promise<void> } + */ +exports.up = async function up(knex) { + await knex.schema.alterTable(factSchemasTable, table => { + table.text('entityFilter').alter(); + }); +}; + +/** + * @param { import("knex").Knex } knex + * @returns { Promise<void> } + */ +exports.down = async function down() { + await knex.schema.alterTable(factSchemasTable, table => { + table.string('entityFilter').alter(); + }); +}; diff --git a/plugins/tech-insights-backend/package.json b/plugins/tech-insights-backend/package.json index 2aa1a4793f..a89907fd62 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.5.17", + "version": "0.5.19-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/tech-insights-node/CHANGELOG.md b/plugins/tech-insights-node/CHANGELOG.md index a2669c4e4a..549c427075 100644 --- a/plugins/tech-insights-node/CHANGELOG.md +++ b/plugins/tech-insights-node/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-tech-insights-node +## 0.4.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/config@1.1.0 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + +## 0.4.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + ## 0.4.9 ### Patch Changes diff --git a/plugins/tech-insights-node/package.json b/plugins/tech-insights-node/package.json index 0dae5947f1..980acd1a4b 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.4.9", + "version": "0.4.11-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/tech-insights/CHANGELOG.md b/plugins/tech-insights/CHANGELOG.md index 56648e0cda..053f9d97ed 100644 --- a/plugins/tech-insights/CHANGELOG.md +++ b/plugins/tech-insights/CHANGELOG.md @@ -1,5 +1,33 @@ # @backstage/plugin-tech-insights +## 0.3.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + +## 0.3.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + ## 0.3.16 ### Patch Changes diff --git a/plugins/tech-insights/api-report.md b/plugins/tech-insights/api-report.md index 14fe512ba0..92f66c14b3 100644 --- a/plugins/tech-insights/api-report.md +++ b/plugins/tech-insights/api-report.md @@ -125,7 +125,6 @@ export const techInsightsPlugin: BackstagePlugin< { root: RouteRef<undefined>; }, - {}, {} >; diff --git a/plugins/tech-insights/package.json b/plugins/tech-insights/package.json index d3ae234abc..142a24cb9b 100644 --- a/plugins/tech-insights/package.json +++ b/plugins/tech-insights/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-tech-insights", - "version": "0.3.16", + "version": "0.3.17-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/tech-radar/CHANGELOG.md b/plugins/tech-radar/CHANGELOG.md index 385b536004..a7684ba5c8 100644 --- a/plugins/tech-radar/CHANGELOG.md +++ b/plugins/tech-radar/CHANGELOG.md @@ -1,5 +1,26 @@ # @backstage/plugin-tech-radar +## 0.6.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.1.1-next.1 + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/theme@0.4.2 + +## 0.6.9-next.0 + +### Patch Changes + +- c09d2fa1d6: Added experimental support for the declarative integration. +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/frontend-plugin-api@0.1.1-next.0 + - @backstage/theme@0.4.2 + ## 0.6.8 ### Patch Changes diff --git a/plugins/tech-radar/alpha-api-report.md b/plugins/tech-radar/alpha-api-report.md new file mode 100644 index 0000000000..c54f692982 --- /dev/null +++ b/plugins/tech-radar/alpha-api-report.md @@ -0,0 +1,24 @@ +## API Report File for "@backstage/plugin-tech-radar" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { BackstagePlugin } from '@backstage/frontend-plugin-api'; +import { Extension } from '@backstage/frontend-plugin-api'; + +// @alpha (undocumented) +const _default: BackstagePlugin; +export default _default; + +// @alpha (undocumented) +export const TechRadarPage: Extension<{ + height: number; + width: number; + title: string; + path: string; + subtitle: string; + pageTitle: string; +}>; + +// (No @packageDocumentation comment for this package) +``` diff --git a/plugins/tech-radar/api-report.md b/plugins/tech-radar/api-report.md index f55f0ee39e..178fc202cd 100644 --- a/plugins/tech-radar/api-report.md +++ b/plugins/tech-radar/api-report.md @@ -106,7 +106,6 @@ const techRadarPlugin: BackstagePlugin< { root: RouteRef<undefined>; }, - {}, {} >; export { techRadarPlugin as plugin }; diff --git a/plugins/tech-radar/package.json b/plugins/tech-radar/package.json index 59b776d319..e99565bb67 100644 --- a/plugins/tech-radar/package.json +++ b/plugins/tech-radar/package.json @@ -1,14 +1,12 @@ { "name": "@backstage/plugin-tech-radar", "description": "A Backstage plugin that lets you display a Tech Radar for your organization", - "version": "0.6.8", + "version": "0.6.9-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", "publishConfig": { - "access": "public", - "main": "dist/index.esm.js", - "types": "dist/index.d.ts" + "access": "public" }, "backstage": { "role": "frontend-plugin" @@ -22,6 +20,21 @@ "keywords": [ "backstage" ], + "exports": { + ".": "./src/index.ts", + "./alpha": "./src/alpha.tsx", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "alpha": [ + "src/alpha.tsx" + ], + "package.json": [ + "package.json" + ] + } + }, "sideEffects": false, "scripts": { "build": "backstage-cli package build", @@ -35,6 +48,7 @@ "dependencies": { "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", + "@backstage/frontend-plugin-api": "workspace:^", "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", diff --git a/plugins/tech-radar/src/alpha.tsx b/plugins/tech-radar/src/alpha.tsx new file mode 100644 index 0000000000..6a2ec882ba --- /dev/null +++ b/plugins/tech-radar/src/alpha.tsx @@ -0,0 +1,62 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createApiFactory, createRouteRef } from '@backstage/core-plugin-api'; +import { + createApiExtension, + createPageExtension, + createPlugin, + createSchemaFromZod, +} from '@backstage/frontend-plugin-api'; +import React from 'react'; +import { techRadarApiRef } from './api'; +import { SampleTechRadarApi } from './sample'; + +const techRadarRouteRef = createRouteRef({ id: 'plugin.techradar.page' }); + +/** @alpha */ +export const TechRadarPage = createPageExtension({ + id: 'plugin.techradar.page', + defaultPath: '/tech-radar', + routeRef: techRadarRouteRef, + configSchema: createSchemaFromZod(z => + z.object({ + title: z.string().default('Tech Radar'), + subtitle: z + .string() + .default('Pick the recommended technologies for your projects'), + pageTitle: z.string().default('Company Radar'), + path: z.string().default('/tech-radar'), + width: z.number().default(1500), + height: z.number().default(800), + }), + ), + loader: ({ config }) => + import('./components').then(m => <m.RadarPage {...config} />), +}); + +const sampleTechRadarApi = createApiExtension({ + api: techRadarApiRef, + factory() { + return createApiFactory(techRadarApiRef, new SampleTechRadarApi()); + }, +}); + +/** @alpha */ +export default createPlugin({ + id: 'tech-radar', + extensions: [TechRadarPage, sampleTechRadarApi], +}); diff --git a/plugins/techdocs-addons-test-utils/CHANGELOG.md b/plugins/techdocs-addons-test-utils/CHANGELOG.md index 7c1c5eb0e3..ea84b35661 100644 --- a/plugins/techdocs-addons-test-utils/CHANGELOG.md +++ b/plugins/techdocs-addons-test-utils/CHANGELOG.md @@ -1,5 +1,37 @@ # @backstage/plugin-techdocs-addons-test-utils +## 1.0.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.14.0-next.1 + - @backstage/plugin-techdocs@1.7.1-next.1 + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-app-api@1.10.1-next.1 + - @backstage/test-utils@1.4.4-next.1 + - @backstage/plugin-search-react@1.7.1-next.1 + - @backstage/integration-react@1.1.20-next.1 + - @backstage/plugin-techdocs-react@1.1.12-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/theme@0.4.2 + +## 1.0.22-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/test-utils@1.4.4-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/plugin-catalog@1.14.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/integration-react@1.1.20-next.0 + - @backstage/plugin-techdocs@1.7.1-next.0 + - @backstage/core-app-api@1.10.1-next.0 + - @backstage/plugin-search-react@1.7.1-next.0 + - @backstage/plugin-techdocs-react@1.1.12-next.0 + - @backstage/theme@0.4.2 + ## 1.0.21 ### Patch Changes diff --git a/plugins/techdocs-addons-test-utils/package.json b/plugins/techdocs-addons-test-utils/package.json index af016f8c32..3a0f83ad6f 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.21", + "version": "1.0.22-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/techdocs-backend/CHANGELOG.md b/plugins/techdocs-backend/CHANGELOG.md index 55b6aefe3f..2723867071 100644 --- a/plugins/techdocs-backend/CHANGELOG.md +++ b/plugins/techdocs-backend/CHANGELOG.md @@ -1,5 +1,41 @@ # @backstage/plugin-techdocs-backend +## 1.7.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.1.9-next.1 + - @backstage/plugin-techdocs-node@1.8.2-next.1 + - @backstage/config@1.1.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-search-common@1.2.6 + +## 1.7.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/plugin-techdocs-node@1.8.2-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/plugin-catalog-common@1.0.16 + - @backstage/plugin-permission-common@0.7.8 + - @backstage/plugin-search-backend-module-techdocs@0.1.9-next.0 + - @backstage/plugin-search-common@1.2.6 + ## 1.7.0 ### Minor Changes diff --git a/plugins/techdocs-backend/package.json b/plugins/techdocs-backend/package.json index f4e13111dc..821457e518 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.7.0", + "version": "1.7.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/techdocs-module-addons-contrib/CHANGELOG.md b/plugins/techdocs-module-addons-contrib/CHANGELOG.md index 68bf1fce2e..3b4c893faa 100644 --- a/plugins/techdocs-module-addons-contrib/CHANGELOG.md +++ b/plugins/techdocs-module-addons-contrib/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-techdocs-module-addons-contrib +## 1.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/integration-react@1.1.20-next.1 + - @backstage/plugin-techdocs-react@1.1.12-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/integration@1.7.1-next.0 + - @backstage/theme@0.4.2 + +## 1.1.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/integration-react@1.1.20-next.0 + - @backstage/plugin-techdocs-react@1.1.12-next.0 + - @backstage/theme@0.4.2 + ## 1.1.0 ### Minor Changes diff --git a/plugins/techdocs-module-addons-contrib/api-report.md b/plugins/techdocs-module-addons-contrib/api-report.md index c242bb02f2..48e6b2bcdc 100644 --- a/plugins/techdocs-module-addons-contrib/api-report.md +++ b/plugins/techdocs-module-addons-contrib/api-report.md @@ -34,7 +34,7 @@ export type ReportIssueTemplateBuilder = (options: { }) => ReportIssueTemplate; // @public -export const techdocsModuleAddonsContribPlugin: BackstagePlugin<{}, {}, {}>; +export const techdocsModuleAddonsContribPlugin: BackstagePlugin<{}, {}>; // @public export const TextSize: () => JSX.Element | null; diff --git a/plugins/techdocs-module-addons-contrib/package.json b/plugins/techdocs-module-addons-contrib/package.json index 6ffb5c4afa..53ccd6c244 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.1.0", + "version": "1.1.1-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/techdocs-node/CHANGELOG.md b/plugins/techdocs-node/CHANGELOG.md index 06d0d88fae..a385a83136 100644 --- a/plugins/techdocs-node/CHANGELOG.md +++ b/plugins/techdocs-node/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/plugin-techdocs-node +## 1.8.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/config@1.1.0 + - @backstage/integration-aws-node@0.1.6 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/plugin-search-common@1.2.6 + +## 1.8.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/integration-aws-node@0.1.6 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/plugin-search-common@1.2.6 + ## 1.8.0 ### Minor Changes diff --git a/plugins/techdocs-node/package.json b/plugins/techdocs-node/package.json index 28de8a94fd..f49ecf1baa 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.8.0", + "version": "1.8.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/plugins/techdocs-react/CHANGELOG.md b/plugins/techdocs-react/CHANGELOG.md index 9e14cdbf36..3e502df15d 100644 --- a/plugins/techdocs-react/CHANGELOG.md +++ b/plugins/techdocs-react/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-techdocs-react +## 1.1.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/version-bridge@1.0.5 + +## 1.1.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/version-bridge@1.0.5 + ## 1.1.11 ### Patch Changes diff --git a/plugins/techdocs-react/package.json b/plugins/techdocs-react/package.json index c07283c0b4..64df90080d 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.1.11", + "version": "1.1.12-next.1", "publishConfig": { "access": "public", "main": "dist/index.esm.js", diff --git a/plugins/techdocs/CHANGELOG.md b/plugins/techdocs/CHANGELOG.md index e834585259..c407d11028 100644 --- a/plugins/techdocs/CHANGELOG.md +++ b/plugins/techdocs/CHANGELOG.md @@ -1,5 +1,44 @@ # @backstage/plugin-techdocs +## 1.7.1-next.1 + +### Patch Changes + +- 4918f65ab2: Create an experimental `TechDocsSearchResultItemExtension` for declarative integration with Backstage; it can be accessed via the `/alpha` import. +- df449a7a31: Add kind column by default to TechDocsTable +- Updated dependencies + - @backstage/frontend-plugin-api@0.1.1-next.1 + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-search-react@1.7.1-next.1 + - @backstage/integration-react@1.1.20-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/plugin-techdocs-react@1.1.12-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/config@1.1.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + - @backstage/theme@0.4.2 + - @backstage/plugin-search-common@1.2.6 + +## 1.7.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/integration-react@1.1.20-next.0 + - @backstage/config@1.1.0 + - @backstage/plugin-search-react@1.7.1-next.0 + - @backstage/plugin-techdocs-react@1.1.12-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/plugin-search-common@1.2.6 + ## 1.7.0 ### Minor Changes diff --git a/plugins/techdocs/alpha-api-report.md b/plugins/techdocs/alpha-api-report.md new file mode 100644 index 0000000000..30d208865c --- /dev/null +++ b/plugins/techdocs/alpha-api-report.md @@ -0,0 +1,23 @@ +## API Report File for "@backstage/plugin-techdocs" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { BackstagePlugin } from '@backstage/frontend-plugin-api'; +import { Extension } from '@backstage/frontend-plugin-api'; + +// @alpha (undocumented) +const _default: BackstagePlugin; +export default _default; + +// @alpha (undocumented) +export const TechDocsSearchResultListItemExtension: Extension<{ + lineClamp: number; + noTrack: boolean; + asListItem: boolean; + asLink: boolean; + title?: string | undefined; +}>; + +// (No @packageDocumentation comment for this package) +``` diff --git a/plugins/techdocs/api-report.md b/plugins/techdocs/api-report.md index 3207a16f87..f351996654 100644 --- a/plugins/techdocs/api-report.md +++ b/plugins/techdocs/api-report.md @@ -79,6 +79,7 @@ export const DocsTable: { columns: { createNameColumn(): TableColumn<DocsTableRow>; createOwnerColumn(): TableColumn<DocsTableRow>; + createKindColumn(): TableColumn<DocsTableRow>; createTypeColumn(): TableColumn<DocsTableRow>; }; actions: { @@ -142,6 +143,7 @@ export const EntityListDocsTable: { columns: { createNameColumn(): TableColumn<DocsTableRow>; createOwnerColumn(): TableColumn<DocsTableRow>; + createKindColumn(): TableColumn<DocsTableRow>; createTypeColumn(): TableColumn<DocsTableRow>; }; actions: { @@ -318,7 +320,6 @@ const techdocsPlugin: BackstagePlugin< }>; entityContent: RouteRef<undefined>; }, - {}, {} >; export { techdocsPlugin as plugin }; diff --git a/plugins/techdocs/package.json b/plugins/techdocs/package.json index a1f26694f8..e7251a4eb2 100644 --- a/plugins/techdocs/package.json +++ b/plugins/techdocs/package.json @@ -1,14 +1,27 @@ { "name": "@backstage/plugin-techdocs", "description": "The Backstage plugin that renders technical documentation for your components", - "version": "1.7.0", + "version": "1.7.1-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", "publishConfig": { - "access": "public", - "main": "dist/index.esm.js", - "types": "dist/index.d.ts" + "access": "public" + }, + "exports": { + ".": "./src/index.ts", + "./alpha": "./src/alpha.tsx", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "alpha": [ + "src/alpha.tsx" + ], + "package.json": [ + "package.json" + ] + } }, "backstage": { "role": "frontend-plugin" @@ -39,6 +52,7 @@ "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/errors": "workspace:^", + "@backstage/frontend-plugin-api": "workspace:^", "@backstage/integration": "workspace:^", "@backstage/integration-react": "workspace:^", "@backstage/plugin-catalog-react": "workspace:^", diff --git a/plugins/techdocs/src/alpha.tsx b/plugins/techdocs/src/alpha.tsx new file mode 100644 index 0000000000..bea4b7ab34 --- /dev/null +++ b/plugins/techdocs/src/alpha.tsx @@ -0,0 +1,51 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { + createPlugin, + createSchemaFromZod, +} from '@backstage/frontend-plugin-api'; +import { createSearchResultListItemExtension } from '@backstage/plugin-search-react/alpha'; + +/** @alpha */ +export const TechDocsSearchResultListItemExtension = + createSearchResultListItemExtension({ + id: 'techdocs', + configSchema: createSchemaFromZod(z => + z.object({ + // TODO: Define how the icon can be configurable + title: z.string().optional(), + lineClamp: z.number().default(5), + asLink: z.boolean().default(true), + asListItem: z.boolean().default(true), + noTrack: z.boolean().default(false), + }), + ), + predicate: result => result.type === 'techdocs', + component: async ({ config }) => { + const { TechDocsSearchResultListItem } = await import( + './search/components/TechDocsSearchResultListItem' + ); + return props => <TechDocsSearchResultListItem {...props} {...config} />; + }, + }); + +/** @alpha */ +export default createPlugin({ + id: 'techdocs', + extensions: [TechDocsSearchResultListItemExtension], +}); diff --git a/plugins/techdocs/src/home/components/Tables/DocsTable.tsx b/plugins/techdocs/src/home/components/Tables/DocsTable.tsx index 5e5b41ee3e..03ba442578 100644 --- a/plugins/techdocs/src/home/components/Tables/DocsTable.tsx +++ b/plugins/techdocs/src/home/components/Tables/DocsTable.tsx @@ -17,16 +17,16 @@ import React from 'react'; import useCopyToClipboard from 'react-use/lib/useCopyToClipboard'; -import { useRouteRef, useApi, configApiRef } from '@backstage/core-plugin-api'; +import { configApiRef, useApi, useRouteRef } from '@backstage/core-plugin-api'; import { Entity, RELATION_OWNED_BY } from '@backstage/catalog-model'; import { - humanizeEntityRef, getEntityRelations, + humanizeEntityRef, } from '@backstage/plugin-catalog-react'; import { rootDocsRouteRef } from '../../../routes'; import { - LinkButton, EmptyState, + LinkButton, Table, TableColumn, TableOptions, @@ -87,6 +87,7 @@ export const DocsTable = (props: DocsTableProps) => { const defaultColumns: TableColumn<DocsTableRow>[] = [ columnFactories.createNameColumn(), columnFactories.createOwnerColumn(), + columnFactories.createKindColumn(), columnFactories.createTypeColumn(), ]; diff --git a/plugins/techdocs/src/home/components/Tables/columns.tsx b/plugins/techdocs/src/home/components/Tables/columns.tsx index 774cfc5e8a..bc85bb7a63 100644 --- a/plugins/techdocs/src/home/components/Tables/columns.tsx +++ b/plugins/techdocs/src/home/components/Tables/columns.tsx @@ -57,6 +57,12 @@ export const columnFactories = { ), }; }, + createKindColumn(): TableColumn<DocsTableRow> { + return { + title: 'Kind', + field: 'entity.kind', + }; + }, createTypeColumn(): TableColumn<DocsTableRow> { return { title: 'Type', diff --git a/plugins/todo-backend/CHANGELOG.md b/plugins/todo-backend/CHANGELOG.md index e468aa66e6..4cbf70e538 100644 --- a/plugins/todo-backend/CHANGELOG.md +++ b/plugins/todo-backend/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/plugin-todo-backend +## 0.3.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.4.6-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/config@1.1.0 + - @backstage/backend-openapi-utils@0.0.4 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/integration@1.7.1-next.0 + +## 0.3.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.7.1-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-openapi-utils@0.0.4 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/catalog-client@1.4.4 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/plugin-catalog-node@1.4.6-next.0 + ## 0.3.1 ### Minor Changes diff --git a/plugins/todo-backend/package.json b/plugins/todo-backend/package.json index 1f9c74e11c..c741984f2d 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.3.1", + "version": "0.3.3-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/todo/CHANGELOG.md b/plugins/todo/CHANGELOG.md index f4ea8e5a23..68efd13892 100644 --- a/plugins/todo/CHANGELOG.md +++ b/plugins/todo/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-todo +## 0.2.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## 0.2.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + ## 0.2.27 ### Patch Changes diff --git a/plugins/todo/api-report.md b/plugins/todo/api-report.md index ae4c4f3645..215d1730bc 100644 --- a/plugins/todo/api-report.md +++ b/plugins/todo/api-report.md @@ -85,7 +85,6 @@ export const todoPlugin: BackstagePlugin< { entityContent: RouteRef<undefined>; }, - {}, {} >; ``` diff --git a/plugins/todo/package.json b/plugins/todo/package.json index 21a9dbaf6a..b255744e12 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.27", + "version": "0.2.28-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/user-settings-backend/CHANGELOG.md b/plugins/user-settings-backend/CHANGELOG.md index e3bcd23555..0dedc9dbce 100644 --- a/plugins/user-settings-backend/CHANGELOG.md +++ b/plugins/user-settings-backend/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-user-settings-backend +## 0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.1 + - @backstage/backend-plugin-api@0.6.5-next.1 + - @backstage/plugin-auth-node@0.3.2-next.1 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + +## 0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.3.2-next.0 + - @backstage/backend-common@0.19.7-next.0 + - @backstage/backend-plugin-api@0.6.5-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/types@1.1.1 + ## 0.2.1 ### Minor Changes diff --git a/plugins/user-settings-backend/package.json b/plugins/user-settings-backend/package.json index 6d0b85b06c..a8e8a711ae 100644 --- a/plugins/user-settings-backend/package.json +++ b/plugins/user-settings-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-user-settings-backend", "description": "The Backstage backend plugin to manage user settings", - "version": "0.2.1", + "version": "0.2.3-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/user-settings/CHANGELOG.md b/plugins/user-settings/CHANGELOG.md index 011e0e2511..dcd46282a1 100644 --- a/plugins/user-settings/CHANGELOG.md +++ b/plugins/user-settings/CHANGELOG.md @@ -1,5 +1,32 @@ # @backstage/plugin-user-settings +## 0.7.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-app-api@1.10.1-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + +## 0.7.11-next.0 + +### Patch Changes + +- d1b637d005: Fixed a bug where the theme icons would not be colored according to their active state. +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/core-app-api@1.10.1-next.0 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + - @backstage/types@1.1.1 + ## 0.7.10 ### Patch Changes diff --git a/plugins/user-settings/api-report.md b/plugins/user-settings/api-report.md index cdb576c45c..b92677f8ce 100644 --- a/plugins/user-settings/api-report.md +++ b/plugins/user-settings/api-report.md @@ -112,7 +112,6 @@ const userSettingsPlugin: BackstagePlugin< { settingsPage: RouteRef<undefined>; }, - {}, {} >; export { userSettingsPlugin as plugin }; diff --git a/plugins/user-settings/package.json b/plugins/user-settings/package.json index 01e158dc2c..251436e85a 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.7.10", + "version": "0.7.11-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/user-settings/src/components/General/UserSettingsThemeToggle.tsx b/plugins/user-settings/src/components/General/UserSettingsThemeToggle.tsx index 7279fcb96a..ca57de3a78 100644 --- a/plugins/user-settings/src/components/General/UserSettingsThemeToggle.tsx +++ b/plugins/user-settings/src/components/General/UserSettingsThemeToggle.tsx @@ -141,8 +141,8 @@ export const UserSettingsThemeToggle = () => { onChange={handleSetTheme} > {themeIds.map(theme => { - const themeIcon = themeIds.find(it => it.id === theme.id)?.icon; const themeId = theme.id; + const themeIcon = theme.icon; const themeTitle = theme.title || (themeId === 'light' || themeId === 'dark' @@ -156,7 +156,11 @@ export const UserSettingsThemeToggle = () => { > <> {themeTitle}  - <ThemeIcon id={themeId} icon={themeIcon} activeId={themeId} /> + <ThemeIcon + id={themeId} + icon={themeIcon} + activeId={activeThemeId} + /> </> </TooltipToggleButton> ); diff --git a/plugins/vault-backend/CHANGELOG.md b/plugins/vault-backend/CHANGELOG.md index a15ae01ac6..3253d8b99c 100644 --- a/plugins/vault-backend/CHANGELOG.md +++ b/plugins/vault-backend/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-vault-backend +## 0.3.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.5.10-next.1 + - @backstage/backend-common@0.19.7-next.1 + - @backstage/config@1.1.0 + - @backstage/errors@1.2.2 + +## 0.3.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.19.7-next.0 + - @backstage/config@1.1.0 + - @backstage/backend-tasks@0.5.10-next.0 + - @backstage/errors@1.2.2 + ## 0.3.8 ### Patch Changes diff --git a/plugins/vault-backend/package.json b/plugins/vault-backend/package.json index 034e8474aa..6906b8124d 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.3.8", + "version": "0.3.10-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/vault/CHANGELOG.md b/plugins/vault/CHANGELOG.md index 79f7427d28..38121353c0 100644 --- a/plugins/vault/CHANGELOG.md +++ b/plugins/vault/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-vault +## 0.1.20-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/plugin-catalog-react@1.8.5-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## 0.1.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.8.5-next.0 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/catalog-model@1.4.2 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + ## 0.1.19 ### Patch Changes diff --git a/plugins/vault/api-report.md b/plugins/vault/api-report.md index da13e2092d..59bcb1c527 100644 --- a/plugins/vault/api-report.md +++ b/plugins/vault/api-report.md @@ -33,7 +33,7 @@ export interface VaultApi { export const vaultApiRef: ApiRef<VaultApi>; // @public -export const vaultPlugin: BackstagePlugin<{}, {}, {}>; +export const vaultPlugin: BackstagePlugin<{}, {}>; // @public export type VaultSecret = { diff --git a/plugins/vault/package.json b/plugins/vault/package.json index dcc7a03d62..014e9b0d50 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.19", + "version": "0.1.20-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/vault/src/components/EntityVaultCard/EntityVaultCard.test.tsx b/plugins/vault/src/components/EntityVaultCard/EntityVaultCard.test.tsx index f46aa1e4c2..9450ddc41d 100644 --- a/plugins/vault/src/components/EntityVaultCard/EntityVaultCard.test.tsx +++ b/plugins/vault/src/components/EntityVaultCard/EntityVaultCard.test.tsx @@ -46,7 +46,7 @@ describe('EntityVaultCard', () => { </EntityProvider>, ); expect( - rendered.getByText(/Add the annotation to your component YAML/), + rendered.getByText(/Add the annotation to your Component YAML/), ).toBeInTheDocument(); }); }); diff --git a/plugins/xcmetrics/CHANGELOG.md b/plugins/xcmetrics/CHANGELOG.md index 61f0561fbf..f3bebcb916 100644 --- a/plugins/xcmetrics/CHANGELOG.md +++ b/plugins/xcmetrics/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-xcmetrics +## 0.2.44-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.6-next.1 + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + +## 0.2.44-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.7.0-next.0 + - @backstage/core-components@0.13.6-next.0 + - @backstage/errors@1.2.2 + - @backstage/theme@0.4.2 + ## 0.2.43 ### Patch Changes diff --git a/plugins/xcmetrics/api-report.md b/plugins/xcmetrics/api-report.md index 4cbac0683c..94a2d4afcd 100644 --- a/plugins/xcmetrics/api-report.md +++ b/plugins/xcmetrics/api-report.md @@ -17,7 +17,6 @@ export const xcmetricsPlugin: BackstagePlugin< { root: RouteRef<undefined>; }, - {}, {} >; ``` diff --git a/plugins/xcmetrics/package.json b/plugins/xcmetrics/package.json index ee16b186c1..c39c0e4963 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.43", + "version": "0.2.44-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/scripts/verify-lockfile-duplicates.js b/scripts/verify-lockfile-duplicates.js index a8d344b741..ddf99f4fd6 100644 --- a/scripts/verify-lockfile-duplicates.js +++ b/scripts/verify-lockfile-duplicates.js @@ -36,7 +36,7 @@ async function findLockFiles() { if (!files.length) { // List all lock files that are in the root or in an immediate subdirectory - files = ['yarn.lock', 'cypress/yarn.lock', 'microsite/yarn.lock']; + files = ['yarn.lock', 'microsite/yarn.lock']; } return files.map(file => ({ diff --git a/storybook/yarn.lock b/storybook/yarn.lock index a868c78ce4..e0f77cd510 100644 --- a/storybook/yarn.lock +++ b/storybook/yarn.lock @@ -2840,91 +2840,92 @@ __metadata: languageName: node linkType: hard -"@swc/core-darwin-arm64@npm:1.3.84": - version: 1.3.84 - resolution: "@swc/core-darwin-arm64@npm:1.3.84" +"@swc/core-darwin-arm64@npm:1.3.90": + version: 1.3.90 + resolution: "@swc/core-darwin-arm64@npm:1.3.90" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@swc/core-darwin-x64@npm:1.3.84": - version: 1.3.84 - resolution: "@swc/core-darwin-x64@npm:1.3.84" +"@swc/core-darwin-x64@npm:1.3.90": + version: 1.3.90 + resolution: "@swc/core-darwin-x64@npm:1.3.90" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@swc/core-linux-arm-gnueabihf@npm:1.3.84": - version: 1.3.84 - resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.84" +"@swc/core-linux-arm-gnueabihf@npm:1.3.90": + version: 1.3.90 + resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.90" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@swc/core-linux-arm64-gnu@npm:1.3.84": - version: 1.3.84 - resolution: "@swc/core-linux-arm64-gnu@npm:1.3.84" +"@swc/core-linux-arm64-gnu@npm:1.3.90": + version: 1.3.90 + resolution: "@swc/core-linux-arm64-gnu@npm:1.3.90" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-arm64-musl@npm:1.3.84": - version: 1.3.84 - resolution: "@swc/core-linux-arm64-musl@npm:1.3.84" +"@swc/core-linux-arm64-musl@npm:1.3.90": + version: 1.3.90 + resolution: "@swc/core-linux-arm64-musl@npm:1.3.90" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@swc/core-linux-x64-gnu@npm:1.3.84": - version: 1.3.84 - resolution: "@swc/core-linux-x64-gnu@npm:1.3.84" +"@swc/core-linux-x64-gnu@npm:1.3.90": + version: 1.3.90 + resolution: "@swc/core-linux-x64-gnu@npm:1.3.90" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-x64-musl@npm:1.3.84": - version: 1.3.84 - resolution: "@swc/core-linux-x64-musl@npm:1.3.84" +"@swc/core-linux-x64-musl@npm:1.3.90": + version: 1.3.90 + resolution: "@swc/core-linux-x64-musl@npm:1.3.90" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@swc/core-win32-arm64-msvc@npm:1.3.84": - version: 1.3.84 - resolution: "@swc/core-win32-arm64-msvc@npm:1.3.84" +"@swc/core-win32-arm64-msvc@npm:1.3.90": + version: 1.3.90 + resolution: "@swc/core-win32-arm64-msvc@npm:1.3.90" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@swc/core-win32-ia32-msvc@npm:1.3.84": - version: 1.3.84 - resolution: "@swc/core-win32-ia32-msvc@npm:1.3.84" +"@swc/core-win32-ia32-msvc@npm:1.3.90": + version: 1.3.90 + resolution: "@swc/core-win32-ia32-msvc@npm:1.3.90" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@swc/core-win32-x64-msvc@npm:1.3.84": - version: 1.3.84 - resolution: "@swc/core-win32-x64-msvc@npm:1.3.84" +"@swc/core-win32-x64-msvc@npm:1.3.90": + version: 1.3.90 + resolution: "@swc/core-win32-x64-msvc@npm:1.3.90" conditions: os=win32 & cpu=x64 languageName: node linkType: hard "@swc/core@npm:^1.3.46": - version: 1.3.84 - resolution: "@swc/core@npm:1.3.84" + version: 1.3.90 + resolution: "@swc/core@npm:1.3.90" dependencies: - "@swc/core-darwin-arm64": 1.3.84 - "@swc/core-darwin-x64": 1.3.84 - "@swc/core-linux-arm-gnueabihf": 1.3.84 - "@swc/core-linux-arm64-gnu": 1.3.84 - "@swc/core-linux-arm64-musl": 1.3.84 - "@swc/core-linux-x64-gnu": 1.3.84 - "@swc/core-linux-x64-musl": 1.3.84 - "@swc/core-win32-arm64-msvc": 1.3.84 - "@swc/core-win32-ia32-msvc": 1.3.84 - "@swc/core-win32-x64-msvc": 1.3.84 - "@swc/types": ^0.1.4 + "@swc/core-darwin-arm64": 1.3.90 + "@swc/core-darwin-x64": 1.3.90 + "@swc/core-linux-arm-gnueabihf": 1.3.90 + "@swc/core-linux-arm64-gnu": 1.3.90 + "@swc/core-linux-arm64-musl": 1.3.90 + "@swc/core-linux-x64-gnu": 1.3.90 + "@swc/core-linux-x64-musl": 1.3.90 + "@swc/core-win32-arm64-msvc": 1.3.90 + "@swc/core-win32-ia32-msvc": 1.3.90 + "@swc/core-win32-x64-msvc": 1.3.90 + "@swc/counter": ^0.1.1 + "@swc/types": ^0.1.5 peerDependencies: "@swc/helpers": ^0.5.0 dependenciesMeta: @@ -2951,14 +2952,21 @@ __metadata: peerDependenciesMeta: "@swc/helpers": optional: true - checksum: dee45823923c29dde579ed1121c4392c937826d575c87f62399ba7a0b27cacfeb05da97b65cf49a721a50127bb1e22ca5c07defa784ec2a47fed33e3498ef1b9 + checksum: f8ced5187068dc73445c135065c6492f0ac559d0f7720c2482aa9663c87bd015f3d2abef6ee7b2f817280a5e8dd0946c59cce7e1499180644fbc948a9e3823ab languageName: node linkType: hard -"@swc/types@npm:^0.1.4": - version: 0.1.4 - resolution: "@swc/types@npm:0.1.4" - checksum: 9b09de7dca8e4b19bfb43f9e332c771855158cb761d26000807fe858447ecbc5342a6c257b26d9aa5497f7138fc58913693e2bee222e5042e0e8f57c2979ae66 +"@swc/counter@npm:^0.1.1": + version: 0.1.1 + resolution: "@swc/counter@npm:0.1.1" + checksum: bb974babd493ba01c0d4a95ab610c3fc15fbf609c08cb0342798e485f57ecc0950abbf84e07124e63c5fe610b492d9a8dd03701d3b9ef7329d9e8bf3cc44980f + languageName: node + linkType: hard + +"@swc/types@npm:^0.1.5": + version: 0.1.5 + resolution: "@swc/types@npm:0.1.5" + checksum: 6aee11f62d3d805a64848e0bd5f0e0e615f958e327a9e1260056c368d7d28764d89e38bd8005a536c9bf18afbcd303edd84099d60df34a2975d62540f61df13b languageName: node linkType: hard diff --git a/yarn.lock b/yarn.lock index 9f1de1ab13..38af62fcd1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -103,8 +103,8 @@ __metadata: linkType: hard "@apollo/client@npm:^3.0.0": - version: 3.8.3 - resolution: "@apollo/client@npm:3.8.3" + version: 3.8.4 + resolution: "@apollo/client@npm:3.8.4" dependencies: "@graphql-typed-document-node/core": ^3.1.1 "@wry/context": ^0.7.3 @@ -134,7 +134,7 @@ __metadata: optional: true subscriptions-transport-ws: optional: true - checksum: cdecd5d613c0f941d00fc1904b9ecdeb502fc157c10400430231adb47d8f67727c78eed1b7489aed91cce6e20e32fc44e16b6c2d5424a42d7c100dcef65b942b + checksum: 509e37cdce7462cacda0a86c413ce471cd8f618625fb8ac3a60d6347d12f37a4fc60e12fc3fc1a375799caa21e56ff58d709e13ef5e13ab15e4dfc828a527848 languageName: node linkType: hard @@ -3305,12 +3305,12 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.1, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.14.6, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.18.6, @babel/runtime@npm:^7.2.0, @babel/runtime@npm:^7.20.1, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.20.6, @babel/runtime@npm:^7.20.7, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.22.10, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.4.4, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.0, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.3, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2": - version: 7.22.11 - resolution: "@babel/runtime@npm:7.22.11" +"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.1, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.18.6, @babel/runtime@npm:^7.2.0, @babel/runtime@npm:^7.20.1, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.20.6, @babel/runtime@npm:^7.20.7, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.22.15, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.4.4, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.0, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.3, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2": + version: 7.22.15 + resolution: "@babel/runtime@npm:7.22.15" dependencies: regenerator-runtime: ^0.14.0 - checksum: a5cd6683a8fcdb8065cb1677f221e22f6c67ec8f15ad1d273b180b93ab3bd86c66da2c48f500d4e72d8d2cfa85ff4872a3f350e5aa3855630036af5da765c001 + checksum: 793296df1e41599a935a3d77ec01eb6088410d3fd4dbe4e92f06c6b7bb2f8355024e6d78621a3a35f44e0e23b0b59107f23d585384df4f3123256a1e1492040e languageName: node linkType: hard @@ -3464,7 +3464,6 @@ __metadata: "@types/http-errors": ^2.0.0 "@types/luxon": ^3.0.0 "@types/minimist": ^1.2.0 - "@types/mock-fs": ^4.13.0 "@types/morgan": ^1.9.0 "@types/node-forge": ^1.3.0 "@types/pg": ^8.6.6 @@ -3497,7 +3496,6 @@ __metadata: luxon: ^3.0.0 minimatch: ^5.0.0 minimist: ^1.2.5 - mock-fs: ^5.2.0 morgan: ^1.10.0 msw: ^1.0.0 mysql2: ^2.2.5 @@ -3622,6 +3620,7 @@ __metadata: "@backstage/config": "workspace:^" "@backstage/errors": "workspace:^" "@backstage/types": "workspace:^" + "@opentelemetry/api": ^1.3.0 "@types/cron": ^2.0.0 "@types/luxon": ^3.0.0 cron: ^2.0.0 @@ -3644,24 +3643,27 @@ __metadata: "@backstage/backend-plugin-api": "workspace:^" "@backstage/cli": "workspace:^" "@backstage/config": "workspace:^" + "@backstage/errors": "workspace:^" "@backstage/plugin-auth-node": "workspace:^" "@backstage/types": "workspace:^" "@types/supertest": ^2.0.8 better-sqlite3: ^8.0.0 express: ^4.17.1 + fs-extra: ^10.0.1 knex: ^2.0.0 msw: ^1.0.0 mysql2: ^2.2.5 pg: ^8.3.0 supertest: ^6.1.3 testcontainers: ^8.1.2 + textextensions: ^5.16.0 uuid: ^8.0.0 peerDependencies: "@types/jest": "*" languageName: unknown linkType: soft -"@backstage/catalog-client@workspace:^, @backstage/catalog-client@workspace:packages/catalog-client": +"@backstage/catalog-client@^1.4.4, @backstage/catalog-client@workspace:^, @backstage/catalog-client@workspace:packages/catalog-client": version: 0.0.0-use.local resolution: "@backstage/catalog-client@workspace:packages/catalog-client" dependencies: @@ -3673,7 +3675,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/catalog-model@^1.1.5, @backstage/catalog-model@^1.4.1, @backstage/catalog-model@workspace:^, @backstage/catalog-model@workspace:packages/catalog-model": +"@backstage/catalog-model@^1.1.5, @backstage/catalog-model@^1.4.2, @backstage/catalog-model@workspace:^, @backstage/catalog-model@workspace:packages/catalog-model": version: 0.0.0-use.local resolution: "@backstage/catalog-model@workspace:packages/catalog-model" dependencies: @@ -3795,6 +3797,7 @@ __metadata: cross-fetch: ^3.1.5 cross-spawn: ^7.0.3 css-loader: ^6.5.1 + ctrlc-windows: ^2.1.0 del: ^7.0.0 diff: ^5.0.0 esbuild: ^0.19.0 @@ -3921,7 +3924,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/config@^1.0.6, @backstage/config@^1.0.7, @backstage/config@workspace:^, @backstage/config@workspace:packages/config": +"@backstage/config@^1.0.6, @backstage/config@^1.0.7, @backstage/config@^1.1.0, @backstage/config@workspace:^, @backstage/config@workspace:packages/config": version: 0.0.0-use.local resolution: "@backstage/config@workspace:packages/config" dependencies: @@ -3953,6 +3956,7 @@ __metadata: "@types/zen-observable": ^0.8.0 history: ^5.0.0 i18next: ^22.4.15 + lodash: ^4.17.21 msw: ^1.0.0 prop-types: ^15.7.2 react-router-beta: "npm:react-router@6.0.0-beta.0" @@ -3969,15 +3973,121 @@ __metadata: languageName: unknown linkType: soft -"@backstage/core-components@^0.13.4, @backstage/core-components@workspace:^, @backstage/core-components@workspace:packages/core-components": +"@backstage/core-components@npm:^0.12.3": + version: 0.12.5 + resolution: "@backstage/core-components@npm:0.12.5" + dependencies: + "@backstage/config": ^1.0.7 + "@backstage/core-plugin-api": ^1.5.0 + "@backstage/errors": ^1.1.5 + "@backstage/theme": ^0.2.18 + "@backstage/version-bridge": ^1.0.3 + "@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": ^20.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.4.1 + react-helmet: 6.1.0 + react-hook-form: ^7.12.2 + react-markdown: ^8.0.0 + react-sparklines: ^1.7.0 + react-syntax-highlighter: ^15.4.5 + react-text-truncate: ^0.19.0 + react-use: ^17.3.2 + react-virtualized-auto-sizer: ^1.0.6 + react-window: ^1.8.6 + remark-gfm: ^3.0.1 + zen-observable: ^0.10.0 + zod: ~3.18.0 + peerDependencies: + "@types/react": ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 + react-dom: ^16.13.1 || ^17.0.0 + react-router-dom: 6.0.0-beta.0 || ^6.3.0 + checksum: 8308c1b90247911f6cf22963b530cef169287f508ff29d159d0c83758134dd43bd5acd2113350690a46a02246bc05dca975bcc38325000aefb1c93c80e2f19c7 + languageName: node + linkType: hard + +"@backstage/core-components@npm:^0.13.5": + version: 0.13.5 + resolution: "@backstage/core-components@npm:0.13.5" + dependencies: + "@backstage/config": ^1.1.0 + "@backstage/core-plugin-api": ^1.6.0 + "@backstage/errors": ^1.2.2 + "@backstage/theme": ^0.4.2 + "@backstage/version-bridge": ^1.0.5 + "@date-io/core": ^1.3.13 + "@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.61 + "@react-hookz/web": ^20.0.0 + "@types/react": ^16.13.1 || ^17.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 + linkify-react: 4.1.1 + linkifyjs: 4.1.1 + lodash: ^4.17.21 + pluralize: ^8.0.0 + prop-types: ^15.7.2 + qs: ^6.9.4 + rc-progress: 3.5.1 + react-helmet: 6.1.0 + react-hook-form: ^7.12.2 + react-idle-timer: 5.6.2 + react-markdown: ^8.0.0 + react-sparklines: ^1.7.0 + react-syntax-highlighter: ^15.4.5 + react-text-truncate: ^0.19.0 + react-use: ^17.3.2 + react-virtualized-auto-sizer: ^1.0.11 + react-window: ^1.8.6 + remark-gfm: ^3.0.1 + zen-observable: ^0.10.0 + zod: ^3.21.4 + peerDependencies: + react: ^16.13.1 || ^17.0.0 + react-dom: ^16.13.1 || ^17.0.0 + react-router-dom: 6.0.0-beta.0 || ^6.3.0 + checksum: f1c9290fd1358561c9a1098200cdf1d2dc16117aebf4010759f122b0a638acb50a89faa24988ad4a854ace59a74606329550c59fc98ab6281feb4b4f5bfe52c0 + languageName: node + linkType: hard + +"@backstage/core-components@workspace:^, @backstage/core-components@workspace:packages/core-components": version: 0.0.0-use.local resolution: "@backstage/core-components@workspace:packages/core-components" dependencies: + "@backstage/catalog-model": "workspace:^" "@backstage/cli": "workspace:^" "@backstage/config": "workspace:^" "@backstage/core-app-api": "workspace:^" "@backstage/core-plugin-api": "workspace:^" "@backstage/errors": "workspace:^" + "@backstage/plugin-catalog-react": "workspace:^" "@backstage/test-utils": "workspace:^" "@backstage/theme": "workspace:^" "@backstage/version-bridge": "workspace:^" @@ -4044,57 +4154,27 @@ __metadata: languageName: unknown linkType: soft -"@backstage/core-components@npm:^0.12.3": - version: 0.12.5 - resolution: "@backstage/core-components@npm:0.12.5" +"@backstage/core-plugin-api@npm:^1.3.0, @backstage/core-plugin-api@npm:^1.5.0, @backstage/core-plugin-api@npm:^1.6.0": + version: 1.6.0 + resolution: "@backstage/core-plugin-api@npm:1.6.0" dependencies: - "@backstage/config": ^1.0.7 - "@backstage/core-plugin-api": ^1.5.0 - "@backstage/errors": ^1.1.5 - "@backstage/theme": ^0.2.18 - "@backstage/version-bridge": ^1.0.3 - "@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": ^20.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.4.1 - react-helmet: 6.1.0 - react-hook-form: ^7.12.2 - react-markdown: ^8.0.0 - react-sparklines: ^1.7.0 - react-syntax-highlighter: ^15.4.5 - react-text-truncate: ^0.19.0 - react-use: ^17.3.2 - react-virtualized-auto-sizer: ^1.0.6 - react-window: ^1.8.6 - remark-gfm: ^3.0.1 - zen-observable: ^0.10.0 - zod: ~3.18.0 - peerDependencies: + "@backstage/config": ^1.1.0 + "@backstage/types": ^1.1.1 + "@backstage/version-bridge": ^1.0.5 "@types/react": ^16.13.1 || ^17.0.0 + history: ^5.0.0 + i18next: ^22.4.15 + prop-types: ^15.7.2 + zen-observable: ^0.10.0 + peerDependencies: react: ^16.13.1 || ^17.0.0 react-dom: ^16.13.1 || ^17.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 - checksum: 8308c1b90247911f6cf22963b530cef169287f508ff29d159d0c83758134dd43bd5acd2113350690a46a02246bc05dca975bcc38325000aefb1c93c80e2f19c7 + checksum: 540deb91d3c143ce1c3736359c3301af64fbd6eccbaae61bfc96f4e180654e7eb025bb1d4ff5be62b7ea3d6dac7ed617e4dba0c176cfdbf865400fde0f987ddb languageName: node linkType: hard -"@backstage/core-plugin-api@^1.3.0, @backstage/core-plugin-api@^1.5.0, @backstage/core-plugin-api@^1.5.3, @backstage/core-plugin-api@workspace:^, @backstage/core-plugin-api@workspace:packages/core-plugin-api": +"@backstage/core-plugin-api@workspace:^, @backstage/core-plugin-api@workspace:packages/core-plugin-api": version: 0.0.0-use.local resolution: "@backstage/core-plugin-api@workspace:packages/core-plugin-api" dependencies: @@ -4180,7 +4260,24 @@ __metadata: languageName: unknown linkType: soft -"@backstage/errors@^1.1.5, @backstage/errors@workspace:^, @backstage/errors@workspace:packages/errors": +"@backstage/e2e-test-utils@workspace:*, @backstage/e2e-test-utils@workspace:packages/e2e-test-utils": + version: 0.0.0-use.local + resolution: "@backstage/e2e-test-utils@workspace:packages/e2e-test-utils" + dependencies: + "@backstage/cli": "workspace:^" + "@backstage/cli-node": "workspace:^" + "@manypkg/get-packages": ^1.1.3 + "@types/fs-extra": ^9.0.1 + fs-extra: ^10.1.0 + peerDependencies: + "@playwright/test": ^1.32.3 + peerDependenciesMeta: + "@playwright/test": + optional: true + languageName: unknown + linkType: soft + +"@backstage/errors@^1.1.5, @backstage/errors@^1.2.2, @backstage/errors@workspace:^, @backstage/errors@workspace:packages/errors": version: 0.0.0-use.local resolution: "@backstage/errors@workspace:packages/errors" dependencies: @@ -4213,9 +4310,13 @@ __metadata: "@backstage/core-plugin-api": "workspace:^" "@backstage/frontend-plugin-api": "workspace:^" "@backstage/plugin-graphiql": "workspace:^" + "@backstage/test-utils": "workspace:^" + "@backstage/theme": "workspace:^" "@backstage/types": "workspace:^" "@material-ui/core": ^4.12.4 + "@material-ui/icons": ^4.11.3 "@testing-library/jest-dom": ^5.10.1 + "@testing-library/react": ^12.1.3 "@types/react": ^16.13.1 || ^17.0.0 lodash: ^4.17.21 peerDependencies: @@ -4264,7 +4365,29 @@ __metadata: languageName: unknown linkType: soft -"@backstage/integration-react@^1.1.18, @backstage/integration-react@workspace:^, @backstage/integration-react@workspace:packages/integration-react": +"@backstage/integration-react@npm:^1.1.19": + version: 1.1.19 + resolution: "@backstage/integration-react@npm:1.1.19" + dependencies: + "@backstage/config": ^1.1.0 + "@backstage/core-components": ^0.13.5 + "@backstage/core-plugin-api": ^1.6.0 + "@backstage/integration": ^1.7.0 + "@backstage/theme": ^0.4.2 + "@material-ui/core": ^4.12.2 + "@material-ui/icons": ^4.9.1 + "@material-ui/lab": 4.0.0-alpha.61 + "@types/react": ^16.13.1 || ^17.0.0 + react-use: ^17.2.4 + peerDependencies: + react: ^16.13.1 || ^17.0.0 + react-dom: ^16.13.1 || ^17.0.0 + react-router-dom: 6.0.0-beta.0 || ^6.3.0 + checksum: 8ef2b46bf91b71351aa4b114de147d130e0298d8849cf2fa358ac1559c2026ffbfad10b15f6fa4bf94c7bbb4f4419766c6c66b77d2859fe184a43351f1f5df81 + languageName: node + linkType: hard + +"@backstage/integration-react@workspace:^, @backstage/integration-react@workspace:packages/integration-react": version: 0.0.0-use.local resolution: "@backstage/integration-react@workspace:packages/integration-react" dependencies: @@ -4293,6 +4416,23 @@ __metadata: languageName: unknown linkType: soft +"@backstage/integration@npm:^1.7.0": + version: 1.7.0 + resolution: "@backstage/integration@npm:1.7.0" + dependencies: + "@azure/identity": ^3.2.1 + "@backstage/config": ^1.1.0 + "@backstage/errors": ^1.2.2 + "@octokit/auth-app": ^4.0.0 + "@octokit/rest": ^19.0.3 + cross-fetch: ^3.1.5 + git-url-parse: ^13.0.0 + lodash: ^4.17.21 + luxon: ^3.0.0 + checksum: f02516b7bdb7adb0516b49b90802e588f09c43b4db66bcce68314518c46b9c6fb8ca76ac7a55d4a80cdd414bb6876475b42eb6256b2efda9824ad3667ffa8f54 + languageName: node + linkType: hard + "@backstage/integration@workspace:^, @backstage/integration@workspace:packages/integration": version: 0.0.0-use.local resolution: "@backstage/integration@workspace:packages/integration" @@ -4365,6 +4505,7 @@ __metadata: "@backstage/core-components": "workspace:^" "@backstage/core-plugin-api": "workspace:^" "@backstage/dev-utils": "workspace:^" + "@backstage/frontend-plugin-api": "workspace:^" "@backstage/integration-react": "workspace:^" "@backstage/plugin-adr-common": "workspace:^" "@backstage/plugin-catalog-react": "workspace:^" @@ -5627,7 +5768,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-catalog-common@^1.0.10, @backstage/plugin-catalog-common@workspace:^, @backstage/plugin-catalog-common@workspace:plugins/catalog-common": +"@backstage/plugin-catalog-common@^1.0.10, @backstage/plugin-catalog-common@^1.0.16, @backstage/plugin-catalog-common@workspace:^, @backstage/plugin-catalog-common@workspace:plugins/catalog-common": version: 0.0.0-use.local resolution: "@backstage/plugin-catalog-common@workspace:plugins/catalog-common" dependencies: @@ -5764,7 +5905,44 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-catalog-react@^1.2.4, @backstage/plugin-catalog-react@^1.8.3, @backstage/plugin-catalog-react@workspace:^, @backstage/plugin-catalog-react@workspace:plugins/catalog-react": +"@backstage/plugin-catalog-react@npm:^1.2.4, @backstage/plugin-catalog-react@npm:^1.8.4": + version: 1.8.4 + resolution: "@backstage/plugin-catalog-react@npm:1.8.4" + dependencies: + "@backstage/catalog-client": ^1.4.4 + "@backstage/catalog-model": ^1.4.2 + "@backstage/core-components": ^0.13.5 + "@backstage/core-plugin-api": ^1.6.0 + "@backstage/errors": ^1.2.2 + "@backstage/integration": ^1.7.0 + "@backstage/plugin-catalog-common": ^1.0.16 + "@backstage/plugin-permission-common": ^0.7.8 + "@backstage/plugin-permission-react": ^0.4.15 + "@backstage/theme": ^0.4.2 + "@backstage/types": ^1.1.1 + "@backstage/version-bridge": ^1.0.5 + "@material-ui/core": ^4.12.2 + "@material-ui/icons": ^4.9.1 + "@material-ui/lab": 4.0.0-alpha.61 + "@react-hookz/web": ^23.0.0 + "@types/react": ^16.13.1 || ^17.0.0 + classnames: ^2.2.6 + jwt-decode: ^3.1.0 + lodash: ^4.17.21 + material-ui-popup-state: ^1.9.3 + qs: ^6.9.4 + react-use: ^17.2.4 + yaml: ^2.0.0 + zen-observable: ^0.10.0 + peerDependencies: + react: ^16.13.1 || ^17.0.0 + react-dom: ^16.13.1 || ^17.0.0 + react-router-dom: 6.0.0-beta.0 || ^6.3.0 + checksum: 6434741a60e4f53604a958c121d283d3d8b2756e1013d3a9b32659ae41b58359cbc3bee0791a95a35c847f43a76de9f9d2ea1f8e5fa6697adfc9115b5042a57e + languageName: node + linkType: hard + +"@backstage/plugin-catalog-react@workspace:^, @backstage/plugin-catalog-react@workspace:plugins/catalog-react": version: 0.0.0-use.local resolution: "@backstage/plugin-catalog-react@workspace:plugins/catalog-react" dependencies: @@ -5853,6 +6031,7 @@ __metadata: "@backstage/core-plugin-api": "workspace:^" "@backstage/dev-utils": "workspace:^" "@backstage/errors": "workspace:^" + "@backstage/frontend-plugin-api": "workspace:^" "@backstage/integration-react": "workspace:^" "@backstage/plugin-catalog-common": "workspace:^" "@backstage/plugin-catalog-react": "workspace:^" @@ -6197,7 +6376,7 @@ __metadata: "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 - "@types/pluralize": ^0.0.30 + "@types/pluralize": ^0.0.31 "@types/react": ^16.13.1 || ^17.0.0 "@types/recharts": ^1.8.14 "@types/regression": ^2.0.0 @@ -6637,6 +6816,7 @@ __metadata: "@backstage/core-plugin-api": "workspace:^" "@backstage/dev-utils": "workspace:^" "@backstage/errors": "workspace:^" + "@backstage/frontend-plugin-api": "workspace:^" "@backstage/plugin-catalog": "workspace:^" "@backstage/plugin-catalog-react": "workspace:^" "@backstage/plugin-explore-common": "workspace:^" @@ -7125,6 +7305,24 @@ __metadata: languageName: unknown linkType: soft +"@backstage/plugin-home-react@npm:^0.1.3": + version: 0.1.3 + resolution: "@backstage/plugin-home-react@npm:0.1.3" + dependencies: + "@backstage/core-components": ^0.13.5 + "@backstage/core-plugin-api": ^1.6.0 + "@material-ui/core": ^4.12.2 + "@material-ui/icons": ^4.9.1 + "@rjsf/utils": 5.13.0 + "@types/react": ^16.13.1 || ^17.0.0 + peerDependencies: + react: ^16.13.1 || ^17.0.0 + react-dom: ^16.13.1 || ^17.0.0 + react-router-dom: 6.0.0-beta.0 || ^6.3.0 + checksum: e87c9fd44c65aa1a768555812f32f42b1d2dc7ab1097c283cae37105d1f17a7b1b198c85d39d72258551015161f317c8e4538a652f6e8ebe9800c3a365f6ebc3 + languageName: node + linkType: hard + "@backstage/plugin-home-react@workspace:^, @backstage/plugin-home-react@workspace:plugins/home-react": version: 0.0.0-use.local resolution: "@backstage/plugin-home-react@workspace:plugins/home-react" @@ -7153,7 +7351,39 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-home@^0.5.7, @backstage/plugin-home@workspace:^, @backstage/plugin-home@workspace:plugins/home": +"@backstage/plugin-home@npm:^0.5.8": + version: 0.5.8 + resolution: "@backstage/plugin-home@npm:0.5.8" + dependencies: + "@backstage/catalog-model": ^1.4.2 + "@backstage/config": ^1.1.0 + "@backstage/core-components": ^0.13.5 + "@backstage/core-plugin-api": ^1.6.0 + "@backstage/plugin-catalog-react": ^1.8.4 + "@backstage/plugin-home-react": ^0.1.3 + "@backstage/theme": ^0.4.2 + "@material-ui/core": ^4.12.2 + "@material-ui/icons": ^4.9.1 + "@material-ui/lab": 4.0.0-alpha.61 + "@rjsf/core-v5": "npm:@rjsf/core@5.13.0" + "@rjsf/material-ui-v5": "npm:@rjsf/material-ui@5.13.0" + "@rjsf/utils": 5.13.0 + "@rjsf/validator-ajv8": 5.13.0 + "@types/react": ^16.13.1 || ^17.0.0 + lodash: ^4.17.21 + react-grid-layout: ^1.3.4 + react-resizable: ^3.0.4 + react-use: ^17.2.4 + zod: ^3.21.4 + peerDependencies: + react: ^16.13.1 || ^17.0.0 + react-dom: ^16.13.1 || ^17.0.0 + react-router-dom: 6.0.0-beta.0 || ^6.3.0 + checksum: 4f895b3a7e7f61149ba7b8fd6ec998d1f83b6e5262073893c5863fe79c46e5e2f52b43346f310733e04815aaebd82b8a13d34616e8d0848f60f87b1fb3193d60 + languageName: node + linkType: hard + +"@backstage/plugin-home@workspace:^, @backstage/plugin-home@workspace:plugins/home": version: 0.0.0-use.local resolution: "@backstage/plugin-home@workspace:plugins/home" dependencies: @@ -7168,6 +7398,7 @@ __metadata: "@backstage/plugin-home-react": "workspace:^" "@backstage/test-utils": "workspace:^" "@backstage/theme": "workspace:^" + "@backstage/types": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 "@material-ui/lab": 4.0.0-alpha.61 @@ -7178,10 +7409,12 @@ __metadata: "@testing-library/dom": ^8.0.0 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 + "@testing-library/react-hooks": ^8.0.1 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 "@types/react-grid-layout": ^1.3.2 lodash: ^4.17.21 + luxon: ^3.4.3 msw: ^1.0.0 react-grid-layout: ^1.3.4 react-resizable: ^3.0.4 @@ -7410,14 +7643,105 @@ __metadata: languageName: unknown linkType: soft +"@backstage/plugin-kubernetes-cluster@workspace:^, @backstage/plugin-kubernetes-cluster@workspace:plugins/kubernetes-cluster": + version: 0.0.0-use.local + resolution: "@backstage/plugin-kubernetes-cluster@workspace:plugins/kubernetes-cluster" + dependencies: + "@backstage/catalog-model": "workspace:^" + "@backstage/cli": "workspace:^" + "@backstage/config": "workspace:^" + "@backstage/core-app-api": "workspace:^" + "@backstage/core-components": "workspace:^" + "@backstage/core-plugin-api": "workspace:^" + "@backstage/dev-utils": "workspace:^" + "@backstage/errors": "workspace:^" + "@backstage/plugin-catalog-react": "workspace:^" + "@backstage/plugin-kubernetes-common": "workspace:^" + "@backstage/plugin-kubernetes-react": "workspace:^" + "@backstage/test-utils": "workspace:^" + "@backstage/theme": "workspace:^" + "@kubernetes-models/apimachinery": ^1.1.0 + "@kubernetes-models/base": ^4.0.1 + "@material-ui/core": ^4.12.2 + "@material-ui/icons": ^4.9.1 + "@material-ui/lab": 4.0.0-alpha.61 + "@testing-library/dom": ^8.0.0 + "@testing-library/jest-dom": ^5.10.1 + "@testing-library/react": ^12.1.3 + "@testing-library/react-hooks": ^8.0.0 + "@testing-library/user-event": ^14.0.0 + "@types/node": ^16.11.26 + "@types/react": ^16.13.1 || ^17.0.0 + cronstrue: ^2.2.0 + js-yaml: ^4.0.0 + kubernetes-models: ^4.1.0 + lodash: ^4.17.21 + luxon: ^3.0.0 + msw: ^1.0.0 + react-use: ^17.2.4 + peerDependencies: + react: ^16.13.1 || ^17.0.0 + react-dom: ^16.13.1 || ^17.0.0 + react-router-dom: 6.0.0-beta.0 || ^6.3.0 + languageName: unknown + linkType: soft + "@backstage/plugin-kubernetes-common@workspace:^, @backstage/plugin-kubernetes-common@workspace:plugins/kubernetes-common": version: 0.0.0-use.local resolution: "@backstage/plugin-kubernetes-common@workspace:plugins/kubernetes-common" dependencies: "@backstage/catalog-model": "workspace:^" "@backstage/cli": "workspace:^" + "@backstage/core-app-api": "workspace:^" + "@backstage/core-plugin-api": "workspace:^" + "@backstage/errors": "workspace:^" "@backstage/plugin-permission-common": "workspace:^" + "@backstage/test-utils": "workspace:^" + "@backstage/types": "workspace:^" "@kubernetes/client-node": 0.18.1 + kubernetes-models: ^4.3.1 + lodash: ^4.17.21 + luxon: ^3.0.0 + msw: ^1.3.1 + languageName: unknown + linkType: soft + +"@backstage/plugin-kubernetes-react@workspace:^, @backstage/plugin-kubernetes-react@workspace:plugins/kubernetes-react": + version: 0.0.0-use.local + resolution: "@backstage/plugin-kubernetes-react@workspace:plugins/kubernetes-react" + dependencies: + "@backstage/catalog-model": "workspace:^" + "@backstage/cli": "workspace:^" + "@backstage/core-app-api": "workspace:^" + "@backstage/core-components": "workspace:^" + "@backstage/core-plugin-api": "workspace:^" + "@backstage/errors": "workspace:^" + "@backstage/plugin-kubernetes-common": "workspace:^" + "@backstage/test-utils": "workspace:^" + "@backstage/types": "workspace:^" + "@kubernetes-models/apimachinery": ^1.1.0 + "@kubernetes-models/base": ^4.0.1 + "@kubernetes/client-node": ^0.19.0 + "@material-ui/core": ^4.9.13 + "@material-ui/icons": ^4.11.3 + "@material-ui/lab": ^4.0.0-alpha.61 + "@testing-library/jest-dom": ^5.10.1 + "@testing-library/react": ^12.1.3 + "@testing-library/react-hooks": ^8.0.1 + "@types/react": ^16.13.1 || ^17.0.0 + cronstrue: ^2.32.0 + jest-websocket-mock: ^2.5.0 + js-yaml: ^4.1.0 + kubernetes-models: ^4.3.1 + lodash: ^4.17.21 + luxon: ^3.0.0 + msw: ^1.3.1 + react-use: ^17.4.0 + xterm: ^5.3.0 + xterm-addon-attach: ^0.9.0 + xterm-addon-fit: ^0.8.0 + peerDependencies: + react: ^16.13.1 || ^17.0.0 languageName: unknown linkType: soft @@ -7435,6 +7759,7 @@ __metadata: "@backstage/errors": "workspace:^" "@backstage/plugin-catalog-react": "workspace:^" "@backstage/plugin-kubernetes-common": "workspace:^" + "@backstage/plugin-kubernetes-react": "workspace:^" "@backstage/test-utils": "workspace:^" "@backstage/theme": "workspace:^" "@backstage/types": "workspace:^" @@ -7701,6 +8026,7 @@ __metadata: resolution: "@backstage/plugin-nomad-backend@workspace:plugins/nomad-backend" dependencies: "@backstage/backend-common": "workspace:^" + "@backstage/backend-plugin-api": "workspace:^" "@backstage/cli": "workspace:^" "@backstage/config": "workspace:^" "@backstage/errors": "workspace:^" @@ -7869,6 +8195,7 @@ __metadata: "@testing-library/react-hooks": ^8.0.1 "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 + lodash: ^4.17.21 msw: ^1.0.0 p-limit: ^3.1.0 pluralize: ^8.0.0 @@ -8010,7 +8337,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-permission-common@workspace:^, @backstage/plugin-permission-common@workspace:plugins/permission-common": +"@backstage/plugin-permission-common@^0.7.8, @backstage/plugin-permission-common@workspace:^, @backstage/plugin-permission-common@workspace:plugins/permission-common": version: 0.0.0-use.local resolution: "@backstage/plugin-permission-common@workspace:plugins/permission-common" dependencies: @@ -8048,6 +8375,25 @@ __metadata: languageName: unknown linkType: soft +"@backstage/plugin-permission-react@npm:^0.4.15": + version: 0.4.15 + resolution: "@backstage/plugin-permission-react@npm:0.4.15" + dependencies: + "@backstage/config": ^1.1.0 + "@backstage/core-plugin-api": ^1.6.0 + "@backstage/plugin-permission-common": ^0.7.8 + "@types/react": ^16.13.1 || ^17.0.0 + cross-fetch: ^3.1.5 + react-use: ^17.2.4 + swr: ^2.0.0 + peerDependencies: + react: ^16.13.1 || ^17.0.0 + react-dom: ^16.13.1 || ^17.0.0 + react-router-dom: 6.0.0-beta.0 || ^6.3.0 + checksum: 5f11264a7d46bee0924b9a00133e756e38d3cce5ce842104546963e08b8bfc6445e28ac4b2b75878fd5407631353e964e5f0b399bc958a76aaa732741b80a52a + languageName: node + linkType: hard + "@backstage/plugin-permission-react@workspace:^, @backstage/plugin-permission-react@workspace:plugins/permission-react": version: 0.0.0-use.local resolution: "@backstage/plugin-permission-react@workspace:plugins/permission-react" @@ -8075,6 +8421,7 @@ __metadata: resolution: "@backstage/plugin-playlist-backend@workspace:plugins/playlist-backend" dependencies: "@backstage/backend-common": "workspace:^" + "@backstage/backend-plugin-api": "workspace:^" "@backstage/backend-test-utils": "workspace:^" "@backstage/catalog-client": "workspace:^" "@backstage/catalog-model": "workspace:^" @@ -8790,6 +9137,8 @@ __metadata: "@backstage/core-app-api": "workspace:^" "@backstage/core-components": "workspace:^" "@backstage/core-plugin-api": "workspace:^" + "@backstage/frontend-app-api": "workspace:^" + "@backstage/frontend-plugin-api": "workspace:^" "@backstage/plugin-search-common": "workspace:^" "@backstage/test-utils": "workspace:^" "@backstage/theme": "workspace:^" @@ -8826,6 +9175,7 @@ __metadata: "@backstage/core-plugin-api": "workspace:^" "@backstage/dev-utils": "workspace:^" "@backstage/errors": "workspace:^" + "@backstage/frontend-plugin-api": "workspace:^" "@backstage/plugin-catalog-react": "workspace:^" "@backstage/plugin-search-common": "workspace:^" "@backstage/plugin-search-react": "workspace:^" @@ -8922,11 +9272,12 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-sonarqube-backend@workspace:plugins/sonarqube-backend": +"@backstage/plugin-sonarqube-backend@workspace:^, @backstage/plugin-sonarqube-backend@workspace:plugins/sonarqube-backend": version: 0.0.0-use.local resolution: "@backstage/plugin-sonarqube-backend@workspace:plugins/sonarqube-backend" dependencies: "@backstage/backend-common": "workspace:^" + "@backstage/backend-plugin-api": "workspace:^" "@backstage/backend-test-utils": "workspace:^" "@backstage/cli": "workspace:^" "@backstage/config": "workspace:^" @@ -9226,6 +9577,7 @@ __metadata: "@backstage/core-components": "workspace:^" "@backstage/core-plugin-api": "workspace:^" "@backstage/dev-utils": "workspace:^" + "@backstage/frontend-plugin-api": "workspace:^" "@backstage/test-utils": "workspace:^" "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 @@ -9441,6 +9793,7 @@ __metadata: "@backstage/core-plugin-api": "workspace:^" "@backstage/dev-utils": "workspace:^" "@backstage/errors": "workspace:^" + "@backstage/frontend-plugin-api": "workspace:^" "@backstage/integration": "workspace:^" "@backstage/integration-react": "workspace:^" "@backstage/plugin-catalog-react": "workspace:^" @@ -9775,7 +10128,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/theme@^0.4.1, @backstage/theme@workspace:^, @backstage/theme@workspace:packages/theme": +"@backstage/theme@^0.4.2, @backstage/theme@workspace:^, @backstage/theme@workspace:packages/theme": version: 0.0.0-use.local resolution: "@backstage/theme@workspace:packages/theme" dependencies: @@ -9804,7 +10157,7 @@ __metadata: languageName: node linkType: hard -"@backstage/types@^1.0.2, @backstage/types@workspace:^, @backstage/types@workspace:packages/types": +"@backstage/types@^1.0.2, @backstage/types@^1.1.1, @backstage/types@workspace:^, @backstage/types@workspace:packages/types": version: 0.0.0-use.local resolution: "@backstage/types@workspace:packages/types" dependencies: @@ -9815,7 +10168,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/version-bridge@^1.0.3, @backstage/version-bridge@workspace:^, @backstage/version-bridge@workspace:packages/version-bridge": +"@backstage/version-bridge@^1.0.3, @backstage/version-bridge@^1.0.5, @backstage/version-bridge@workspace:^, @backstage/version-bridge@workspace:packages/version-bridge": version: 0.0.0-use.local resolution: "@backstage/version-bridge@workspace:packages/version-bridge" dependencies: @@ -10118,16 +10471,16 @@ __metadata: linkType: hard "@codemirror/language@npm:^6.0.0": - version: 6.9.0 - resolution: "@codemirror/language@npm:6.9.0" + version: 6.9.1 + resolution: "@codemirror/language@npm:6.9.1" dependencies: "@codemirror/state": ^6.0.0 "@codemirror/view": ^6.0.0 - "@lezer/common": ^1.0.0 + "@lezer/common": ^1.1.0 "@lezer/highlight": ^1.0.0 "@lezer/lr": ^1.0.0 style-mod: ^4.0.0 - checksum: 9a897fb0f569159eeafb7dce83061b425af7244bbeae2649e0e677488548b2a02eaf0c13c0c5b4d59da55e8866e6f4dc7abe3dfaa09c13749a2fa2c0dbc0c565 + checksum: 62265f1042d2edfd3a091c408d9d0071f23889099b2f6ce8275fa910118bd2c45b8c4b29228c7be6e6d5f0e0812a522de902bc75ba8d8b2e62e42ade1692a49a languageName: node linkType: hard @@ -10182,13 +10535,13 @@ __metadata: linkType: hard "@codemirror/view@npm:^6.0.0": - version: 6.18.1 - resolution: "@codemirror/view@npm:6.18.1" + version: 6.21.0 + resolution: "@codemirror/view@npm:6.21.0" dependencies: "@codemirror/state": ^6.1.4 style-mod: ^4.1.0 w3c-keyname: ^2.2.4 - checksum: 12e350169a12a3cca059712769f81306c95b59accce8ec3c5e6deb1f2fc570baac6f64768aa04f6337bca8448d66520417ec8a4c1c456d40324758695ed9fe90 + checksum: da49d5541b137a812e1837709130b9a4502fac71b87c45d45384116a7a2b1dab556c283abb673946ba9d044a640ab9058727b85de9b7b576c44848dfbf0ed7bb languageName: node linkType: hard @@ -10208,42 +10561,6 @@ __metadata: languageName: node linkType: hard -"@cypress/request@npm:^2.88.10": - version: 2.88.10 - resolution: "@cypress/request@npm:2.88.10" - dependencies: - aws-sign2: ~0.7.0 - aws4: ^1.8.0 - caseless: ~0.12.0 - combined-stream: ~1.0.6 - extend: ~3.0.2 - forever-agent: ~0.6.1 - form-data: ~2.3.2 - http-signature: ~1.3.6 - is-typedarray: ~1.0.0 - isstream: ~0.1.2 - json-stringify-safe: ~5.0.1 - mime-types: ~2.1.19 - performance-now: ^2.1.0 - qs: ~6.5.2 - safe-buffer: ^5.1.2 - tough-cookie: ~2.5.0 - tunnel-agent: ^0.6.0 - uuid: ^8.3.2 - checksum: 69c3e3b332e9be4866a900f6bcca5d274d8cea6c99707fbcce061de8dbab11c9b1e39f4c017f6e83e6e682717781d4f6106fd6b7cf9546580fcfac353b6676cf - languageName: node - linkType: hard - -"@cypress/xvfb@npm:^1.2.4": - version: 1.2.4 - resolution: "@cypress/xvfb@npm:1.2.4" - dependencies: - debug: ^3.1.0 - lodash.once: ^4.1.1 - checksum: 7bdcdaeb1bb692ec9d9bf8ec52538aa0bead6764753f4a067a171a511807a43fab016f7285a56bef6a606c2467ff3f1365e1ad2d2d583b81beed849ee1573fd1 - languageName: node - linkType: hard - "@dabh/diagnostics@npm:^2.0.2": version: 2.0.2 resolution: "@dabh/diagnostics@npm:2.0.2" @@ -10530,9 +10847,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/android-arm64@npm:0.19.3": - version: 0.19.3 - resolution: "@esbuild/android-arm64@npm:0.19.3" +"@esbuild/android-arm64@npm:0.19.4": + version: 0.19.4 + resolution: "@esbuild/android-arm64@npm:0.19.4" conditions: os=android & cpu=arm64 languageName: node linkType: hard @@ -10551,9 +10868,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/android-arm@npm:0.19.3": - version: 0.19.3 - resolution: "@esbuild/android-arm@npm:0.19.3" +"@esbuild/android-arm@npm:0.19.4": + version: 0.19.4 + resolution: "@esbuild/android-arm@npm:0.19.4" conditions: os=android & cpu=arm languageName: node linkType: hard @@ -10565,9 +10882,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/android-x64@npm:0.19.3": - version: 0.19.3 - resolution: "@esbuild/android-x64@npm:0.19.3" +"@esbuild/android-x64@npm:0.19.4": + version: 0.19.4 + resolution: "@esbuild/android-x64@npm:0.19.4" conditions: os=android & cpu=x64 languageName: node linkType: hard @@ -10579,9 +10896,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/darwin-arm64@npm:0.19.3": - version: 0.19.3 - resolution: "@esbuild/darwin-arm64@npm:0.19.3" +"@esbuild/darwin-arm64@npm:0.19.4": + version: 0.19.4 + resolution: "@esbuild/darwin-arm64@npm:0.19.4" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard @@ -10593,9 +10910,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/darwin-x64@npm:0.19.3": - version: 0.19.3 - resolution: "@esbuild/darwin-x64@npm:0.19.3" +"@esbuild/darwin-x64@npm:0.19.4": + version: 0.19.4 + resolution: "@esbuild/darwin-x64@npm:0.19.4" conditions: os=darwin & cpu=x64 languageName: node linkType: hard @@ -10607,9 +10924,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/freebsd-arm64@npm:0.19.3": - version: 0.19.3 - resolution: "@esbuild/freebsd-arm64@npm:0.19.3" +"@esbuild/freebsd-arm64@npm:0.19.4": + version: 0.19.4 + resolution: "@esbuild/freebsd-arm64@npm:0.19.4" conditions: os=freebsd & cpu=arm64 languageName: node linkType: hard @@ -10621,9 +10938,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/freebsd-x64@npm:0.19.3": - version: 0.19.3 - resolution: "@esbuild/freebsd-x64@npm:0.19.3" +"@esbuild/freebsd-x64@npm:0.19.4": + version: 0.19.4 + resolution: "@esbuild/freebsd-x64@npm:0.19.4" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard @@ -10635,9 +10952,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-arm64@npm:0.19.3": - version: 0.19.3 - resolution: "@esbuild/linux-arm64@npm:0.19.3" +"@esbuild/linux-arm64@npm:0.19.4": + version: 0.19.4 + resolution: "@esbuild/linux-arm64@npm:0.19.4" conditions: os=linux & cpu=arm64 languageName: node linkType: hard @@ -10649,9 +10966,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-arm@npm:0.19.3": - version: 0.19.3 - resolution: "@esbuild/linux-arm@npm:0.19.3" +"@esbuild/linux-arm@npm:0.19.4": + version: 0.19.4 + resolution: "@esbuild/linux-arm@npm:0.19.4" conditions: os=linux & cpu=arm languageName: node linkType: hard @@ -10663,9 +10980,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-ia32@npm:0.19.3": - version: 0.19.3 - resolution: "@esbuild/linux-ia32@npm:0.19.3" +"@esbuild/linux-ia32@npm:0.19.4": + version: 0.19.4 + resolution: "@esbuild/linux-ia32@npm:0.19.4" conditions: os=linux & cpu=ia32 languageName: node linkType: hard @@ -10684,9 +11001,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-loong64@npm:0.19.3": - version: 0.19.3 - resolution: "@esbuild/linux-loong64@npm:0.19.3" +"@esbuild/linux-loong64@npm:0.19.4": + version: 0.19.4 + resolution: "@esbuild/linux-loong64@npm:0.19.4" conditions: os=linux & cpu=loong64 languageName: node linkType: hard @@ -10698,9 +11015,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-mips64el@npm:0.19.3": - version: 0.19.3 - resolution: "@esbuild/linux-mips64el@npm:0.19.3" +"@esbuild/linux-mips64el@npm:0.19.4": + version: 0.19.4 + resolution: "@esbuild/linux-mips64el@npm:0.19.4" conditions: os=linux & cpu=mips64el languageName: node linkType: hard @@ -10712,9 +11029,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-ppc64@npm:0.19.3": - version: 0.19.3 - resolution: "@esbuild/linux-ppc64@npm:0.19.3" +"@esbuild/linux-ppc64@npm:0.19.4": + version: 0.19.4 + resolution: "@esbuild/linux-ppc64@npm:0.19.4" conditions: os=linux & cpu=ppc64 languageName: node linkType: hard @@ -10726,9 +11043,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-riscv64@npm:0.19.3": - version: 0.19.3 - resolution: "@esbuild/linux-riscv64@npm:0.19.3" +"@esbuild/linux-riscv64@npm:0.19.4": + version: 0.19.4 + resolution: "@esbuild/linux-riscv64@npm:0.19.4" conditions: os=linux & cpu=riscv64 languageName: node linkType: hard @@ -10740,9 +11057,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-s390x@npm:0.19.3": - version: 0.19.3 - resolution: "@esbuild/linux-s390x@npm:0.19.3" +"@esbuild/linux-s390x@npm:0.19.4": + version: 0.19.4 + resolution: "@esbuild/linux-s390x@npm:0.19.4" conditions: os=linux & cpu=s390x languageName: node linkType: hard @@ -10754,9 +11071,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-x64@npm:0.19.3": - version: 0.19.3 - resolution: "@esbuild/linux-x64@npm:0.19.3" +"@esbuild/linux-x64@npm:0.19.4": + version: 0.19.4 + resolution: "@esbuild/linux-x64@npm:0.19.4" conditions: os=linux & cpu=x64 languageName: node linkType: hard @@ -10768,9 +11085,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/netbsd-x64@npm:0.19.3": - version: 0.19.3 - resolution: "@esbuild/netbsd-x64@npm:0.19.3" +"@esbuild/netbsd-x64@npm:0.19.4": + version: 0.19.4 + resolution: "@esbuild/netbsd-x64@npm:0.19.4" conditions: os=netbsd & cpu=x64 languageName: node linkType: hard @@ -10782,9 +11099,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/openbsd-x64@npm:0.19.3": - version: 0.19.3 - resolution: "@esbuild/openbsd-x64@npm:0.19.3" +"@esbuild/openbsd-x64@npm:0.19.4": + version: 0.19.4 + resolution: "@esbuild/openbsd-x64@npm:0.19.4" conditions: os=openbsd & cpu=x64 languageName: node linkType: hard @@ -10796,9 +11113,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/sunos-x64@npm:0.19.3": - version: 0.19.3 - resolution: "@esbuild/sunos-x64@npm:0.19.3" +"@esbuild/sunos-x64@npm:0.19.4": + version: 0.19.4 + resolution: "@esbuild/sunos-x64@npm:0.19.4" conditions: os=sunos & cpu=x64 languageName: node linkType: hard @@ -10810,9 +11127,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/win32-arm64@npm:0.19.3": - version: 0.19.3 - resolution: "@esbuild/win32-arm64@npm:0.19.3" +"@esbuild/win32-arm64@npm:0.19.4": + version: 0.19.4 + resolution: "@esbuild/win32-arm64@npm:0.19.4" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard @@ -10824,9 +11141,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/win32-ia32@npm:0.19.3": - version: 0.19.3 - resolution: "@esbuild/win32-ia32@npm:0.19.3" +"@esbuild/win32-ia32@npm:0.19.4": + version: 0.19.4 + resolution: "@esbuild/win32-ia32@npm:0.19.4" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard @@ -10838,9 +11155,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/win32-x64@npm:0.19.3": - version: 0.19.3 - resolution: "@esbuild/win32-x64@npm:0.19.3" +"@esbuild/win32-x64@npm:0.19.4": + version: 0.19.4 + resolution: "@esbuild/win32-x64@npm:0.19.4" conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -10937,41 +11254,41 @@ __metadata: languageName: node linkType: hard -"@floating-ui/core@npm:^1.4.1": - version: 1.4.1 - resolution: "@floating-ui/core@npm:1.4.1" +"@floating-ui/core@npm:^1.4.2": + version: 1.5.0 + resolution: "@floating-ui/core@npm:1.5.0" dependencies: - "@floating-ui/utils": ^0.1.1 - checksum: be4ab864fe17eeba5e205bd554c264b9a4895a57c573661bbf638357fa3108677fed7ba3269ec15b4da90e29274c9b626d5a15414e8d1fe691e210d02a03695c + "@floating-ui/utils": ^0.1.3 + checksum: 54b4fe26b3c228746ac5589f97303abf158b80aa5f8b99027259decd68d1c2030c4c637648ebd33dfe78a4212699453bc2bd7537fd5a594d3bd3e63d362f666f languageName: node linkType: hard -"@floating-ui/dom@npm:^1.3.0": - version: 1.5.1 - resolution: "@floating-ui/dom@npm:1.5.1" +"@floating-ui/dom@npm:^1.5.1": + version: 1.5.3 + resolution: "@floating-ui/dom@npm:1.5.3" dependencies: - "@floating-ui/core": ^1.4.1 - "@floating-ui/utils": ^0.1.1 - checksum: ddb509030978536ba7b321cf8c764ae9d0142a3b1fefb7e6bc050a5de7e825e12131fa5089009edabf7c125fb274886da211a5220fe17a71d875a7a96eb1386c + "@floating-ui/core": ^1.4.2 + "@floating-ui/utils": ^0.1.3 + checksum: 00053742064aac70957f0bd5c1542caafb3bfe9716588bfe1d409fef72a67ed5e60450d08eb492a77f78c22ed1ce4f7955873cc72bf9f9caf2b0f43ae3561c21 languageName: node linkType: hard -"@floating-ui/react-dom@npm:^2.0.1": - version: 2.0.1 - resolution: "@floating-ui/react-dom@npm:2.0.1" +"@floating-ui/react-dom@npm:^2.0.2": + version: 2.0.2 + resolution: "@floating-ui/react-dom@npm:2.0.2" dependencies: - "@floating-ui/dom": ^1.3.0 + "@floating-ui/dom": ^1.5.1 peerDependencies: react: ">=16.8.0" react-dom: ">=16.8.0" - checksum: 00fef2cf69ac2b15952e47505fd9e23f6cc5c20a26adc707862932826d1682f3c30f83c9887abfc93574fdca2d34dd2fc00271527318b1db403549cd6bc9eb00 + checksum: 4797e1f7a19c1e531ed0d578ccdcbe58970743e5a480ba30424857fc953063f36d481f8c5d69248a8f1d521b739e94bf5e1ffb35506400dea3d914f166ed2f7f languageName: node linkType: hard -"@floating-ui/utils@npm:^0.1.1": - version: 0.1.1 - resolution: "@floating-ui/utils@npm:0.1.1" - checksum: 548acdda7902f45b0afbe34e2e7f4cbff0696b95bad8c039f80936519de24ef2ec20e79902825b7815294b37f51a7c52ee86288b0688869a57cc229a164d86b4 +"@floating-ui/utils@npm:^0.1.3": + version: 0.1.4 + resolution: "@floating-ui/utils@npm:0.1.4" + checksum: e6195ded5b3a6fd38411a833605184c31f24609b08feab2615e90ccc063bf4d3965383d817642fc7e8ca5ab6a54c29c71103e874f3afb0518595c8bd3390ba16 languageName: node linkType: hard @@ -10984,30 +11301,6 @@ __metadata: languageName: node linkType: hard -"@frsource/base64@npm:1.0.17": - version: 1.0.17 - resolution: "@frsource/base64@npm:1.0.17" - checksum: a01689ef785516ff0b7460f55792685fc782f8507518768396acb9283270d50a8149774f3acd5fa690ccd5a48b5ec4ace90a491458ffdd9e9f591c6b23eb5da5 - languageName: node - linkType: hard - -"@frsource/cypress-plugin-visual-regression-diff@npm:^3.2.8": - version: 3.3.10 - resolution: "@frsource/cypress-plugin-visual-regression-diff@npm:3.3.10" - dependencies: - "@frsource/base64": 1.0.17 - glob: 8.1.0 - meta-png: 1.0.6 - move-file: 2.1.0 - pixelmatch: 5.3.0 - pngjs: 7.0.0 - sharp: 0.32.1 - peerDependencies: - cypress: ">=4.5.0" - checksum: 879954ecba8829fd870379a1f4150a511fceab4c5a5c3df8abbab54e655e6560d52d925109364ea7f2d3484467ed5e9c3e4cfaf0058c12bbfbfc21d76ed79b40 - languageName: node - linkType: hard - "@gar/promisify@npm:^1.0.1, @gar/promisify@npm:^1.1.3": version: 1.1.3 resolution: "@gar/promisify@npm:1.1.3" @@ -11951,22 +12244,6 @@ __metadata: languageName: node linkType: hard -"@hapi/hoek@npm:^9.0.0": - version: 9.0.4 - resolution: "@hapi/hoek@npm:9.0.4" - checksum: a5503ebaad5407e0c99d0656b0bbc3e9ccac9eddc9b9f66e0358a2da9a9dd173c63c9f7c5e46504a05e1fc41d853e9a19617e258d4fcbe1a4be7f9e61da83920 - languageName: node - linkType: hard - -"@hapi/topo@npm:^5.0.0": - version: 5.0.0 - resolution: "@hapi/topo@npm:5.0.0" - dependencies: - "@hapi/hoek": ^9.0.0 - checksum: 8aa81f71696f88d7daeab4547e120e43c6ab78081a4f215eec5103dd858f3122a703512cdacc43aa7e27d99607345165acfeb2ee69e556e63afd50c5c57a36c3 - languageName: node - linkType: hard - "@humanwhocodes/config-array@npm:^0.11.11": version: 0.11.11 resolution: "@humanwhocodes/config-array@npm:0.11.11" @@ -12014,20 +12291,6 @@ __metadata: languageName: node linkType: hard -"@internal/plugin-catalog-customized@workspace:^, @internal/plugin-catalog-customized@workspace:plugins/catalog-customized": - version: 0.0.0-use.local - resolution: "@internal/plugin-catalog-customized@workspace:plugins/catalog-customized" - dependencies: - "@backstage/plugin-catalog": "workspace:^" - "@backstage/plugin-catalog-react": "workspace:^" - "@types/react": ^16.13.1 || ^17.0.0 - peerDependencies: - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 - react-router-dom: 6.0.0-beta.0 || ^6.3.0 - languageName: unknown - linkType: soft - "@internal/plugin-todo-list-backend@workspace:plugins/example-todo-list-backend": version: 0.0.0-use.local resolution: "@internal/plugin-todo-list-backend@workspace:plugins/example-todo-list-backend" @@ -12554,11 +12817,11 @@ __metadata: linkType: hard "@keyv/redis@npm:^2.5.3": - version: 2.7.0 - resolution: "@keyv/redis@npm:2.7.0" + version: 2.7.1 + resolution: "@keyv/redis@npm:2.7.1" dependencies: ioredis: ^5.3.2 - checksum: 2bf16d99f54fa5177c375eb170f46076715e6a17fd65840d10638e441af8a4dd065927a18b45abb9531746ddab54f865884347c80f7e188c981a40f8245269ab + checksum: 917547d9f6a3af2d0c355c9c78cac9392a8f3d7f2cc379d42ae158189da346cf0c831708cbb530496fda91dfeb4be2bad207ce154ef2205c2b8ce48b2e43a0fc languageName: node linkType: hard @@ -12624,6 +12887,32 @@ __metadata: languageName: node linkType: hard +"@kubernetes/client-node@npm:^0.19.0": + version: 0.19.0 + resolution: "@kubernetes/client-node@npm:0.19.0" + dependencies: + "@types/js-yaml": ^4.0.1 + "@types/node": ^20.1.1 + "@types/request": ^2.47.1 + "@types/ws": ^8.5.3 + byline: ^5.0.0 + isomorphic-ws: ^5.0.0 + js-yaml: ^4.1.0 + jsonpath-plus: ^7.2.0 + openid-client: ^5.3.0 + request: ^2.88.0 + rfc4648: ^1.3.0 + stream-buffers: ^3.0.2 + tar: ^6.1.11 + tslib: ^2.4.1 + ws: ^8.11.0 + dependenciesMeta: + openid-client: + optional: true + checksum: d29ccfb562ac51a81f74de570eb832d150be6b73ba887ae1be682df9a34c3ab846d4d4ba74f0a9f0e0ce4da573f949ba712115e1d0513148cdf683a22d729e7f + languageName: node + linkType: hard + "@leichtgewicht/ip-codec@npm:^2.0.1": version: 2.0.3 resolution: "@leichtgewicht/ip-codec@npm:2.0.3" @@ -12631,10 +12920,10 @@ __metadata: languageName: node linkType: hard -"@lezer/common@npm:^1.0.0": - version: 1.0.0 - resolution: "@lezer/common@npm:1.0.0" - checksum: 0ba652b39f9ff073a6a8a3376a74279f2c2d2ccdd4d2bb57c7b607341dbdbf64baf9c23a196314f09349d175623bc73a6a0b6a0eeb2cc63f3a1190fd631f7c31 +"@lezer/common@npm:^1.0.0, @lezer/common@npm:^1.1.0": + version: 1.1.0 + resolution: "@lezer/common@npm:1.1.0" + checksum: 93c208a44d1c0bdf7407853ba7c4ddcedf1c52d1b82170813d83b9bd6301aa23587405ac54332fe39ce8bc37f706936ab237ceb4d3d535d1dead650153b6474c languageName: node linkType: hard @@ -12797,7 +13086,7 @@ __metadata: languageName: node linkType: hard -"@material-ui/icons@npm:^4.11.2, @material-ui/icons@npm:^4.9.1": +"@material-ui/icons@npm:^4.11.2, @material-ui/icons@npm:^4.11.3, @material-ui/icons@npm:^4.9.1": version: 4.11.3 resolution: "@material-ui/icons@npm:4.11.3" dependencies: @@ -12856,7 +13145,7 @@ __metadata: languageName: node linkType: hard -"@material-ui/lab@npm:4.0.0-alpha.61, @material-ui/lab@npm:^4.0.0-alpha.57, @material-ui/lab@npm:^4.0.0-alpha.60": +"@material-ui/lab@npm:4.0.0-alpha.61, @material-ui/lab@npm:^4.0.0-alpha.57, @material-ui/lab@npm:^4.0.0-alpha.60, @material-ui/lab@npm:^4.0.0-alpha.61": version: 4.0.0-alpha.61 resolution: "@material-ui/lab@npm:4.0.0-alpha.61" dependencies: @@ -13125,19 +13414,17 @@ __metadata: languageName: node linkType: hard -"@mui/base@npm:5.0.0-beta.14": - version: 5.0.0-beta.14 - resolution: "@mui/base@npm:5.0.0-beta.14" +"@mui/base@npm:5.0.0-beta.17": + version: 5.0.0-beta.17 + resolution: "@mui/base@npm:5.0.0-beta.17" dependencies: - "@babel/runtime": ^7.22.10 - "@emotion/is-prop-valid": ^1.2.1 - "@floating-ui/react-dom": ^2.0.1 + "@babel/runtime": ^7.22.15 + "@floating-ui/react-dom": ^2.0.2 "@mui/types": ^7.2.4 - "@mui/utils": ^5.14.8 + "@mui/utils": ^5.14.11 "@popperjs/core": ^2.11.8 clsx: ^2.0.0 prop-types: ^15.8.1 - react-is: ^18.2.0 peerDependencies: "@types/react": ^17.0.0 || ^18.0.0 react: ^17.0.0 || ^18.0.0 @@ -13145,27 +13432,27 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 3e5c980edb285d4fbf1f9f6c08b237a502e6c444222e0165e98e4e25787de7663d6905536b8e8a7a0888571daaa75fcad01534c8f8ea8ba30451cad82d1b85cc + checksum: 96ffb85864fc796783514e089c0011ebcc5174705082dc98197ab035dfb287427069c0338e662a4680951849dfbe7a5231f4f6f2aee710af05c07e8578f93310 languageName: node linkType: hard -"@mui/core-downloads-tracker@npm:^5.14.8": - version: 5.14.8 - resolution: "@mui/core-downloads-tracker@npm:5.14.8" - checksum: b8322994d7c05426008c3426f7ce4bb0a1dfd633429af704cc9e164655007fc446ba21bf6b00af8fa1b9a9cb4c1757d72c7554e13cceadc575af7d44344da38c +"@mui/core-downloads-tracker@npm:^5.14.11": + version: 5.14.11 + resolution: "@mui/core-downloads-tracker@npm:5.14.11" + checksum: f3e7594c93d4cf5e3649336eef2b57842c171f3deb6890c03be7eccb88d3ac276aac1ab3ad409d124d16468314018778e2dbb92a62ac34c7f44b2813c47f29fb languageName: node linkType: hard "@mui/material@npm:^5.12.2": - version: 5.14.8 - resolution: "@mui/material@npm:5.14.8" + version: 5.14.11 + resolution: "@mui/material@npm:5.14.11" dependencies: - "@babel/runtime": ^7.22.10 - "@mui/base": 5.0.0-beta.14 - "@mui/core-downloads-tracker": ^5.14.8 - "@mui/system": ^5.14.8 + "@babel/runtime": ^7.22.15 + "@mui/base": 5.0.0-beta.17 + "@mui/core-downloads-tracker": ^5.14.11 + "@mui/system": ^5.14.11 "@mui/types": ^7.2.4 - "@mui/utils": ^5.14.8 + "@mui/utils": ^5.14.11 "@types/react-transition-group": ^4.4.6 clsx: ^2.0.0 csstype: ^3.1.2 @@ -13185,16 +13472,16 @@ __metadata: optional: true "@types/react": optional: true - checksum: 2db4eceb6a2b51e2f429082206b5c4194f894bc6831cf5348d301b910e5e2b1a62565cad00a244100434899307c20134832ab2e85dd56bef4dd210d87496e136 + checksum: 350d642773d4b19d5b9deac956203dafe89cd005ba8cd6017d1ab0e97ba45ca230050249f34a17f0f00efe466162d47487f160159bebe3e52af1b34dd28579d0 languageName: node linkType: hard -"@mui/private-theming@npm:^5.14.8": - version: 5.14.8 - resolution: "@mui/private-theming@npm:5.14.8" +"@mui/private-theming@npm:^5.14.11": + version: 5.14.11 + resolution: "@mui/private-theming@npm:5.14.11" dependencies: - "@babel/runtime": ^7.22.10 - "@mui/utils": ^5.14.8 + "@babel/runtime": ^7.22.15 + "@mui/utils": ^5.14.11 prop-types: ^15.8.1 peerDependencies: "@types/react": ^17.0.0 || ^18.0.0 @@ -13202,15 +13489,15 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 3d8c4b768ee81d03c739acfa7d99450423b9267a1a2219171f247b1823350426452514f0cc646f4d48f113db396b5488c48132fe54a5db8646e101514b764d96 + checksum: a5d461ae9679b1f3b79f529c51c055e03d84421812bb12110d735fbc5528ae188900488b32aa1b860cb978ac6dd0cb9f54a10e2ff214e853e969ef5c1ed87e84 languageName: node linkType: hard -"@mui/styled-engine@npm:^5.14.8": - version: 5.14.8 - resolution: "@mui/styled-engine@npm:5.14.8" +"@mui/styled-engine@npm:^5.14.11": + version: 5.14.11 + resolution: "@mui/styled-engine@npm:5.14.11" dependencies: - "@babel/runtime": ^7.22.10 + "@babel/runtime": ^7.22.15 "@emotion/cache": ^11.11.0 csstype: ^3.1.2 prop-types: ^15.8.1 @@ -13223,19 +13510,19 @@ __metadata: optional: true "@emotion/styled": optional: true - checksum: 12d626a42fa15cc315172775a076cf6f71afc999123bd290cbda3855de8c607f8fbf0a3daa7a391e67a83ad824c6e7eb21e57121a448a527b3bf9b494a7bd852 + checksum: 0a593f967ab56c32c611eae4a83bc23c4ab3a8931e76a6e553ed18230c2f4e9e912d519fe2f0a24970ff154c198634903f134eb54f00ceebde138a73b953622f languageName: node linkType: hard -"@mui/system@npm:^5.14.8": - version: 5.14.8 - resolution: "@mui/system@npm:5.14.8" +"@mui/system@npm:^5.14.11": + version: 5.14.11 + resolution: "@mui/system@npm:5.14.11" dependencies: - "@babel/runtime": ^7.22.10 - "@mui/private-theming": ^5.14.8 - "@mui/styled-engine": ^5.14.8 + "@babel/runtime": ^7.22.15 + "@mui/private-theming": ^5.14.11 + "@mui/styled-engine": ^5.14.11 "@mui/types": ^7.2.4 - "@mui/utils": ^5.14.8 + "@mui/utils": ^5.14.11 clsx: ^2.0.0 csstype: ^3.1.2 prop-types: ^15.8.1 @@ -13251,7 +13538,7 @@ __metadata: optional: true "@types/react": optional: true - checksum: d630b4253caa971ad0bcb35cef1165ff689bfcadb806eb3b26eddce4d6c1bcdeb9781ccaea87f9950bff308ac302514766880f63c4bbdcdf28619f66d974797c + checksum: c3d0e1a09a9638663a6467452a7725593e9de6f9620e199add1080db42a7affaca39f52a1b6a52fb75d708f3e30336946babb2a8d1d43fab81c6a1fe3e420b21 languageName: node linkType: hard @@ -13267,18 +13554,21 @@ __metadata: languageName: node linkType: hard -"@mui/utils@npm:^5.14.8": - version: 5.14.8 - resolution: "@mui/utils@npm:5.14.8" +"@mui/utils@npm:^5.14.11": + version: 5.14.11 + resolution: "@mui/utils@npm:5.14.11" dependencies: - "@babel/runtime": ^7.22.10 + "@babel/runtime": ^7.22.15 "@types/prop-types": ^15.7.5 - "@types/react-is": ^18.2.1 prop-types: ^15.8.1 react-is: ^18.2.0 peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 react: ^17.0.0 || ^18.0.0 - checksum: 2fb29c9d7908a47276b4f4a31a7e76d5a7d437afe95d2c0d6cd9c07f04beea89857f763c4f5c546fe243539d9986181815bfded42e516077122ed373d11a7ebf + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 84e640dea3589ea7edb7d8f33748d83d561d4ef413c4d3e2216ddf9c0842d8b04d162e3fa5ea59f03846934f17fb446ed8464e318dd4e2e299e3b44b06637d76 languageName: node linkType: hard @@ -14208,6 +14498,17 @@ __metadata: languageName: node linkType: hard +"@playwright/test@npm:^1.32.3": + version: 1.38.1 + resolution: "@playwright/test@npm:1.38.1" + dependencies: + playwright: 1.38.1 + bin: + playwright: cli.js + checksum: c5ec0b23261fe1ef163b6234f69263bc10e7e5a3fb676c7773ffc70b87459a7ab225f57c03b9de649475771638a04c2e00d9b2739304a4dcf5d3edf20a7a4a82 + languageName: node + linkType: hard + "@pmmmwh/react-refresh-webpack-plugin@npm:^0.5.7": version: 0.5.11 resolution: "@pmmmwh/react-refresh-webpack-plugin@npm:0.5.11" @@ -14477,14 +14778,14 @@ __metadata: linkType: hard "@roadiehq/backstage-plugin-buildkite@npm:^2.0.8": - version: 2.1.14 - resolution: "@roadiehq/backstage-plugin-buildkite@npm:2.1.14" + version: 2.1.15 + resolution: "@roadiehq/backstage-plugin-buildkite@npm:2.1.15" dependencies: - "@backstage/catalog-model": ^1.4.1 - "@backstage/core-components": ^0.13.4 - "@backstage/core-plugin-api": ^1.5.3 - "@backstage/plugin-catalog-react": ^1.8.3 - "@backstage/theme": ^0.4.1 + "@backstage/catalog-model": ^1.4.2 + "@backstage/core-components": ^0.13.5 + "@backstage/core-plugin-api": ^1.6.0 + "@backstage/plugin-catalog-react": ^1.8.4 + "@backstage/theme": ^0.4.2 "@material-ui/core": ^4.12.1 "@material-ui/icons": ^4.11.2 "@material-ui/lab": 4.0.0-alpha.57 @@ -14496,20 +14797,20 @@ __metadata: react-dom: ^16.13.1 || ^17.0.0 react-router: 6.0.0-beta.0 || ^6.3.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 - checksum: 938fa38d6199a1c5199eb47851ddc0edb2f0d3064fa189baf104ff820096700cb95843c499353efc77b10c1fc721aa2a32b0146c1d3df1bea31f5af61dfd250b + checksum: 421a3e444b6c5945748d0842bc777efc9fe0e968dad3c59cdc0cbbcd841752bcf47d757f2fc307fa1245da884adfeb3e478cd23b2bb318f621e05ffa7c6ec21b languageName: node linkType: hard "@roadiehq/backstage-plugin-github-insights@npm:^2.0.5": - version: 2.3.20 - resolution: "@roadiehq/backstage-plugin-github-insights@npm:2.3.20" + version: 2.3.21 + resolution: "@roadiehq/backstage-plugin-github-insights@npm:2.3.21" dependencies: - "@backstage/catalog-model": ^1.4.1 - "@backstage/core-components": ^0.13.4 - "@backstage/core-plugin-api": ^1.5.3 - "@backstage/integration-react": ^1.1.18 - "@backstage/plugin-catalog-react": ^1.8.3 - "@backstage/theme": ^0.4.1 + "@backstage/catalog-model": ^1.4.2 + "@backstage/core-components": ^0.13.5 + "@backstage/core-plugin-api": ^1.6.0 + "@backstage/integration-react": ^1.1.19 + "@backstage/plugin-catalog-react": ^1.8.4 + "@backstage/theme": ^0.4.2 "@date-io/core": 2.10.7 "@material-ui/core": ^4.11.0 "@material-ui/icons": ^4.9.1 @@ -14524,19 +14825,19 @@ __metadata: react: ^16.13.1 || ^17.0.0 react-dom: ^16.13.1 || ^17.0.0 react-router: 6.0.0-beta.0 || ^6.3.0 - checksum: 187483c88f7a34757cb9cc6b9bac343bfd1853e634957f71049fe448b03a1e631456f1bc31be3aa91c41976a812ae24e522fc374faf33507e3db80fc1e54cdd2 + checksum: edb0ecee1778e0bacd1eff395aa723fef35338253a7f8e91ab93b5755b9ebac27e49e1768ee13163ade74edf0b0f620ab31b693674c746c3c1e35e1185f46636 languageName: node linkType: hard "@roadiehq/backstage-plugin-github-pull-requests@npm:^2.2.7": - version: 2.5.15 - resolution: "@roadiehq/backstage-plugin-github-pull-requests@npm:2.5.15" + version: 2.5.16 + resolution: "@roadiehq/backstage-plugin-github-pull-requests@npm:2.5.16" dependencies: - "@backstage/catalog-model": ^1.4.1 - "@backstage/core-components": ^0.13.4 - "@backstage/core-plugin-api": ^1.5.3 - "@backstage/plugin-catalog-react": ^1.8.3 - "@backstage/plugin-home": ^0.5.7 + "@backstage/catalog-model": ^1.4.2 + "@backstage/core-components": ^0.13.5 + "@backstage/core-plugin-api": ^1.6.0 + "@backstage/plugin-catalog-react": ^1.8.4 + "@backstage/plugin-home": ^0.5.8 "@material-ui/core": ^4.11.0 "@material-ui/icons": ^4.9.1 "@material-ui/lab": ^4.0.0-alpha.60 @@ -14553,19 +14854,19 @@ __metadata: react: ^16.13.1 || ^17.0.0 react-dom: ^16.13.1 || ^17.0.0 react-router: 6.0.0-beta.0 || ^6.3.0 - checksum: 3332a560f8741536ab12ff1e14567e739aa6f60767d8eb0a2e5b9873b54947b0cdaac7c44cb5bb3156dc8b2a7d88d33ee20191c8920bfe8f67b87857dfda2780 + checksum: cb35e64d4df6f81829cd238e3b06b84453ad9231a30a0a4698ebb9d408445af0bfeb59d27bcc5d818013735f2f4d44a89ff9824258ff1565274c524c3ae905cc languageName: node linkType: hard "@roadiehq/backstage-plugin-travis-ci@npm:^2.0.5": - version: 2.1.14 - resolution: "@roadiehq/backstage-plugin-travis-ci@npm:2.1.14" + version: 2.1.15 + resolution: "@roadiehq/backstage-plugin-travis-ci@npm:2.1.15" dependencies: - "@backstage/catalog-model": ^1.4.1 - "@backstage/core-components": ^0.13.4 - "@backstage/core-plugin-api": ^1.5.3 - "@backstage/plugin-catalog-react": ^1.8.3 - "@backstage/theme": ^0.4.1 + "@backstage/catalog-model": ^1.4.2 + "@backstage/core-components": ^0.13.5 + "@backstage/core-plugin-api": ^1.6.0 + "@backstage/plugin-catalog-react": ^1.8.4 + "@backstage/theme": ^0.4.2 "@material-ui/core": ^4.11.3 "@material-ui/icons": ^4.11.2 "@material-ui/lab": 4.0.0-alpha.57 @@ -14579,7 +14880,7 @@ __metadata: react-dom: ^16.13.1 || ^17.0.0 react-router: 6.0.0-beta.0 || ^6.3.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 - checksum: f6e297460aa2dccd3ac5b639838a253017229ecf6ec03541702ccb33f93ec15327894e35f7dfa565bc58c137abfd94129a858d43b2b861283370a003b2685dda + checksum: f285fa074049bb1d03adc3e04467a3700c3651550fc3304038c9169438e1bd3e12790309be9a86cfb76a97f53925165d6b91ab4d81985ce5bb2faa97e5b10b00 languageName: node linkType: hard @@ -14766,29 +15067,6 @@ __metadata: languageName: node linkType: hard -"@sideway/address@npm:^4.1.3": - version: 4.1.4 - resolution: "@sideway/address@npm:4.1.4" - dependencies: - "@hapi/hoek": ^9.0.0 - checksum: b9fca2a93ac2c975ba12e0a6d97853832fb1f4fb02393015e012b47fa916a75ca95102d77214b2a29a2784740df2407951af8c5dde054824c65577fd293c4cdb - languageName: node - linkType: hard - -"@sideway/formula@npm:^3.0.0": - version: 3.0.1 - resolution: "@sideway/formula@npm:3.0.1" - checksum: e4beeebc9dbe2ff4ef0def15cec0165e00d1612e3d7cea0bc9ce5175c3263fc2c818b679bd558957f49400ee7be9d4e5ac90487e1625b4932e15c4aa7919c57a - languageName: node - linkType: hard - -"@sideway/pinpoint@npm:^2.0.0": - version: 2.0.0 - resolution: "@sideway/pinpoint@npm:2.0.0" - checksum: 0f4491e5897fcf5bf02c46f5c359c56a314e90ba243f42f0c100437935daa2488f20482f0f77186bd6bf43345095a95d8143ecf8b1f4d876a7bc0806aba9c3d2 - languageName: node - linkType: hard - "@sinclair/typebox@npm:^0.24.1": version: 0.24.42 resolution: "@sinclair/typebox@npm:0.24.42" @@ -16264,91 +16542,92 @@ __metadata: languageName: node linkType: hard -"@swc/core-darwin-arm64@npm:1.3.84": - version: 1.3.84 - resolution: "@swc/core-darwin-arm64@npm:1.3.84" +"@swc/core-darwin-arm64@npm:1.3.90": + version: 1.3.90 + resolution: "@swc/core-darwin-arm64@npm:1.3.90" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@swc/core-darwin-x64@npm:1.3.84": - version: 1.3.84 - resolution: "@swc/core-darwin-x64@npm:1.3.84" +"@swc/core-darwin-x64@npm:1.3.90": + version: 1.3.90 + resolution: "@swc/core-darwin-x64@npm:1.3.90" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@swc/core-linux-arm-gnueabihf@npm:1.3.84": - version: 1.3.84 - resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.84" +"@swc/core-linux-arm-gnueabihf@npm:1.3.90": + version: 1.3.90 + resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.90" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@swc/core-linux-arm64-gnu@npm:1.3.84": - version: 1.3.84 - resolution: "@swc/core-linux-arm64-gnu@npm:1.3.84" +"@swc/core-linux-arm64-gnu@npm:1.3.90": + version: 1.3.90 + resolution: "@swc/core-linux-arm64-gnu@npm:1.3.90" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-arm64-musl@npm:1.3.84": - version: 1.3.84 - resolution: "@swc/core-linux-arm64-musl@npm:1.3.84" +"@swc/core-linux-arm64-musl@npm:1.3.90": + version: 1.3.90 + resolution: "@swc/core-linux-arm64-musl@npm:1.3.90" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@swc/core-linux-x64-gnu@npm:1.3.84": - version: 1.3.84 - resolution: "@swc/core-linux-x64-gnu@npm:1.3.84" +"@swc/core-linux-x64-gnu@npm:1.3.90": + version: 1.3.90 + resolution: "@swc/core-linux-x64-gnu@npm:1.3.90" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-x64-musl@npm:1.3.84": - version: 1.3.84 - resolution: "@swc/core-linux-x64-musl@npm:1.3.84" +"@swc/core-linux-x64-musl@npm:1.3.90": + version: 1.3.90 + resolution: "@swc/core-linux-x64-musl@npm:1.3.90" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@swc/core-win32-arm64-msvc@npm:1.3.84": - version: 1.3.84 - resolution: "@swc/core-win32-arm64-msvc@npm:1.3.84" +"@swc/core-win32-arm64-msvc@npm:1.3.90": + version: 1.3.90 + resolution: "@swc/core-win32-arm64-msvc@npm:1.3.90" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@swc/core-win32-ia32-msvc@npm:1.3.84": - version: 1.3.84 - resolution: "@swc/core-win32-ia32-msvc@npm:1.3.84" +"@swc/core-win32-ia32-msvc@npm:1.3.90": + version: 1.3.90 + resolution: "@swc/core-win32-ia32-msvc@npm:1.3.90" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@swc/core-win32-x64-msvc@npm:1.3.84": - version: 1.3.84 - resolution: "@swc/core-win32-x64-msvc@npm:1.3.84" +"@swc/core-win32-x64-msvc@npm:1.3.90": + version: 1.3.90 + resolution: "@swc/core-win32-x64-msvc@npm:1.3.90" conditions: os=win32 & cpu=x64 languageName: node linkType: hard "@swc/core@npm:^1.3.46": - version: 1.3.84 - resolution: "@swc/core@npm:1.3.84" + version: 1.3.90 + resolution: "@swc/core@npm:1.3.90" dependencies: - "@swc/core-darwin-arm64": 1.3.84 - "@swc/core-darwin-x64": 1.3.84 - "@swc/core-linux-arm-gnueabihf": 1.3.84 - "@swc/core-linux-arm64-gnu": 1.3.84 - "@swc/core-linux-arm64-musl": 1.3.84 - "@swc/core-linux-x64-gnu": 1.3.84 - "@swc/core-linux-x64-musl": 1.3.84 - "@swc/core-win32-arm64-msvc": 1.3.84 - "@swc/core-win32-ia32-msvc": 1.3.84 - "@swc/core-win32-x64-msvc": 1.3.84 - "@swc/types": ^0.1.4 + "@swc/core-darwin-arm64": 1.3.90 + "@swc/core-darwin-x64": 1.3.90 + "@swc/core-linux-arm-gnueabihf": 1.3.90 + "@swc/core-linux-arm64-gnu": 1.3.90 + "@swc/core-linux-arm64-musl": 1.3.90 + "@swc/core-linux-x64-gnu": 1.3.90 + "@swc/core-linux-x64-musl": 1.3.90 + "@swc/core-win32-arm64-msvc": 1.3.90 + "@swc/core-win32-ia32-msvc": 1.3.90 + "@swc/core-win32-x64-msvc": 1.3.90 + "@swc/counter": ^0.1.1 + "@swc/types": ^0.1.5 peerDependencies: "@swc/helpers": ^0.5.0 dependenciesMeta: @@ -16375,7 +16654,14 @@ __metadata: peerDependenciesMeta: "@swc/helpers": optional: true - checksum: dee45823923c29dde579ed1121c4392c937826d575c87f62399ba7a0b27cacfeb05da97b65cf49a721a50127bb1e22ca5c07defa784ec2a47fed33e3498ef1b9 + checksum: f8ced5187068dc73445c135065c6492f0ac559d0f7720c2482aa9663c87bd015f3d2abef6ee7b2f817280a5e8dd0946c59cce7e1499180644fbc948a9e3823ab + languageName: node + linkType: hard + +"@swc/counter@npm:^0.1.1": + version: 0.1.1 + resolution: "@swc/counter@npm:0.1.1" + checksum: bb974babd493ba01c0d4a95ab610c3fc15fbf609c08cb0342798e485f57ecc0950abbf84e07124e63c5fe610b492d9a8dd03701d3b9ef7329d9e8bf3cc44980f languageName: node linkType: hard @@ -16400,10 +16686,10 @@ __metadata: languageName: node linkType: hard -"@swc/types@npm:^0.1.4": - version: 0.1.4 - resolution: "@swc/types@npm:0.1.4" - checksum: 9b09de7dca8e4b19bfb43f9e332c771855158cb761d26000807fe858447ecbc5342a6c257b26d9aa5497f7138fc58913693e2bee222e5042e0e8f57c2979ae66 +"@swc/types@npm:^0.1.5": + version: 0.1.5 + resolution: "@swc/types@npm:0.1.5" + checksum: 6aee11f62d3d805a64848e0bd5f0e0e615f958e327a9e1260056c368d7d28764d89e38bd8005a536c9bf18afbcd303edd84099d60df34a2975d62540f61df13b languageName: node linkType: hard @@ -16452,7 +16738,6 @@ __metadata: "@backstage/cli-common": "workspace:^" "@backstage/config": "workspace:^" "@backstage/plugin-techdocs-node": "workspace:^" - "@frsource/cypress-plugin-visual-regression-diff": ^3.2.8 "@types/commander": ^2.12.2 "@types/dockerode": ^3.3.0 "@types/fs-extra": ^9.0.6 @@ -16461,7 +16746,6 @@ __metadata: "@types/serve-handler": ^6.1.0 "@types/webpack-env": ^1.15.3 commander: ^9.1.0 - cypress: ^10.0.0 dockerode: ^3.3.1 find-process: ^1.4.5 fs-extra: ^10.0.1 @@ -16478,19 +16762,7 @@ __metadata: languageName: unknown linkType: soft -"@testing-library/cypress@npm:^9.0.0": - version: 9.0.0 - resolution: "@testing-library/cypress@npm:9.0.0" - dependencies: - "@babel/runtime": ^7.14.6 - "@testing-library/dom": ^8.1.0 - peerDependencies: - cypress: ^12.0.0 - checksum: fbd24e8f0b8a60279b336de5f6bc0e7ad6fb31316eacab5128dacc7fccde1eb40935b90f2c3bddc7d814115fe3965c6dbf011785448cd15b5a5b0bc40ef5bb4c - languageName: node - linkType: hard - -"@testing-library/dom@npm:^8.0.0, @testing-library/dom@npm:^8.1.0": +"@testing-library/dom@npm:^8.0.0": version: 8.20.1 resolution: "@testing-library/dom@npm:8.20.1" dependencies: @@ -16658,11 +16930,11 @@ __metadata: linkType: hard "@types/archiver@npm:^5.1.0, @types/archiver@npm:^5.3.1": - version: 5.3.2 - resolution: "@types/archiver@npm:5.3.2" + version: 5.3.3 + resolution: "@types/archiver@npm:5.3.3" dependencies: "@types/readdir-glob": "*" - checksum: 9db5b4fdc1740fa07d08340ed827598cc6eda97406ac18a06a158670c7124d4120650a3b9cd660e9e39b42f033cf8f052566da32681e8ad91163473df88a3c4c + checksum: e660465ac9a622570ddbad86a306c7234c3272cb28eafe9c3ad7229f06e499dfadae9f0cb0caf41443318eea559b75ef662ea276ae64f19695e72018dae37ee7 languageName: node linkType: hard @@ -16688,11 +16960,11 @@ __metadata: linkType: hard "@types/aws4@npm:^1.5.1": - version: 1.11.3 - resolution: "@types/aws4@npm:1.11.3" + version: 1.11.4 + resolution: "@types/aws4@npm:1.11.4" dependencies: "@types/node": "*" - checksum: 4c10ca4d7de26e031e81fd67387df51323ebea81c441330a5a733f4bace854d61b8e880ea8fbe3678f2e6e081d510cbc6b623864646519fbb4ab130a8b138a46 + checksum: 8b2576843488b31fdb080369eaff6af539ded60feab4eeeb429481ec0c209c0a7a8d7011747eb71e1b2bc86a455b105dd91fe86add5c2aa1584b6f4821fbf0e7 languageName: node linkType: hard @@ -16747,15 +17019,15 @@ __metadata: linkType: hard "@types/body-parser-xml@npm:^2.0.2": - version: 2.0.2 - resolution: "@types/body-parser-xml@npm:2.0.2" + version: 2.0.3 + resolution: "@types/body-parser-xml@npm:2.0.3" dependencies: "@types/body-parser": "*" "@types/connect": "*" "@types/express-serve-static-core": "*" "@types/node": "*" "@types/xml2js": "*" - checksum: ddac93399bc85b7402193004954215b9152374cd3e0e54e6f500ea71e8bf962ff091300a265551832c863e63539af1a2d9483838073ff43362d0bdf867802a50 + checksum: 96b8067706b5709b88a2fa20563742363c7b81bf17007bcbbd54536e83d29ca2cfe104a742bd14070a99a2772026b8d595e283cf6a4b87f7ca47390a5a95dc31 languageName: node linkType: hard @@ -16987,9 +17259,9 @@ __metadata: linkType: hard "@types/d3-force@npm:^3.0.0": - version: 3.0.5 - resolution: "@types/d3-force@npm:3.0.5" - checksum: 09aa0e999841f69b34296fa92273b5b251c50f74c1b7ec2bdef7a3a7fd2d756467e4ede7cc0dcfc4151c04bde0f3feaa48d9b669c38620fb51cee2d7faa01e24 + version: 3.0.6 + resolution: "@types/d3-force@npm:3.0.6" + checksum: 092d7a4efc1bef06de4a087e1bdb609e21588429ba2ce978785bb13e1ed7371dd08692408379d9582e03ed945c6cf117dff3b3ed1dd2141d94aac9e12994498d languageName: node linkType: hard @@ -17026,27 +17298,27 @@ __metadata: linkType: hard "@types/d3-selection@npm:*, @types/d3-selection@npm:^3.0.1": - version: 3.0.6 - resolution: "@types/d3-selection@npm:3.0.6" - checksum: 01f9f3a41b98280947109911bcc6ebffff5c8c3e617695979c04ef9beef445a8cdc48a9fbdb3c9cff45a7345e83e8a5d6b346d7ceedca6ebc11dfd9717dbff6b + version: 3.0.7 + resolution: "@types/d3-selection@npm:3.0.7" + checksum: 715a0c7a78732650ae70b3487b3b6432b063482c1937bcd52c8b7a201563103170fdaa1f8c0ace882062521ac009f07fefb41198c8c43c5d3c518f8368c459d6 languageName: node linkType: hard "@types/d3-shape@npm:^1": - version: 1.3.8 - resolution: "@types/d3-shape@npm:1.3.8" + version: 1.3.9 + resolution: "@types/d3-shape@npm:1.3.9" dependencies: "@types/d3-path": ^1 - checksum: a7f78a3f0be1215b512efb636ba381768ab4104ef9b72b7fcc2ab9810e7d6fc2ee062f3103ef99236f4462deabac60d2fd96375315ec7ad33278757918c94592 + checksum: a4df0c09df4f97a017fbb229a096af6e25fe84e331dfb8c9b1f248a7f3df6f07c871879fabb31050cbec78f34127397a8134a16f2a2359ff681ec846cf886754 languageName: node linkType: hard "@types/d3-shape@npm:^3.0.1, @types/d3-shape@npm:^3.1.0": - version: 3.1.2 - resolution: "@types/d3-shape@npm:3.1.2" + version: 3.1.3 + resolution: "@types/d3-shape@npm:3.1.3" dependencies: "@types/d3-path": "*" - checksum: 17399a78872aa89cab600cb7977405136a72798dbbb59a4b3684012c2a2ffb9b62720cceaaedc412088b7da086518a6722c909e03cb81e3e238569722feb60f9 + checksum: ad17781ab4ce4b796954b86de7e14566c731726d39a1db7d73eaf50668a71e996d715450a0ff9f2720755e1b8643c3e88d47d45101a75c9d4ddbef51a636f6a0 languageName: node linkType: hard @@ -17065,19 +17337,19 @@ __metadata: linkType: hard "@types/d3-zoom@npm:^3.0.1": - version: 3.0.4 - resolution: "@types/d3-zoom@npm:3.0.4" + version: 3.0.5 + resolution: "@types/d3-zoom@npm:3.0.5" dependencies: "@types/d3-interpolate": "*" "@types/d3-selection": "*" - checksum: 6330b8411822b979ab0fd5a7a7755295377b4dfc61fd8f925d97e5b388e3dd604b455c0009b0eda3320c14c4ea367f740a04991a71d35befdca5f75218492a68 + checksum: acff15a30b2b81a99b46692c7aacc110c635a272e8d7e87af6aa5a01ebe9ebcafcaf475399d79ec73461a5ef037041dade49a6371d7587b759710123539b81b0 languageName: node linkType: hard "@types/dagre@npm:^0.7.44": - version: 0.7.49 - resolution: "@types/dagre@npm:0.7.49" - checksum: cb27683074f8c89c073d0b7b549692b67ddae7225a2b6f9586d75c11598f7bd32d9246ecb184017a55592e7daaf63e4d33dcbc56ca4c3999cf34352460ddf772 + version: 0.7.50 + resolution: "@types/dagre@npm:0.7.50" + checksum: a128048b5202c501a4595bbc17288aafbef90f3535e79385ddaf0842237e69aa5998dbc12bc2867244eefe3fb6c5026d9785bfdedea46d813f006066e06e8f44 languageName: node linkType: hard @@ -17091,9 +17363,9 @@ __metadata: linkType: hard "@types/diff@npm:^5.0.0": - version: 5.0.3 - resolution: "@types/diff@npm:5.0.3" - checksum: d8a7d4de12f1aba0bd0c17b0b0d1e45c83824d3d6cc65763fbad371cd8315361a7e16fbae3f260a83bfdf30cebe1c876b42cec4518698055bc430fb09db1cbc8 + version: 5.0.5 + resolution: "@types/diff@npm:5.0.5" + checksum: 5f093341d5488cd33079400d4b2ff463dfd4f589bf0a54fbb25f7c87a7bdc16bd1e6125f252c081fa9a3ad44fc78b156c0a5f38bd8128edceb40ba084e051885 languageName: node linkType: hard @@ -17108,12 +17380,12 @@ __metadata: linkType: hard "@types/dockerode@npm:^3.3.0, @types/dockerode@npm:^3.3.8": - version: 3.3.19 - resolution: "@types/dockerode@npm:3.3.19" + version: 3.3.20 + resolution: "@types/dockerode@npm:3.3.20" dependencies: "@types/docker-modem": "*" "@types/node": "*" - checksum: 96d6cd3811a778d12382432413c3b0a935912c175ca939c77aaa0db2630c205daf14d5fa52e458a6fd44355c444f4fa1bd821e0364d4d0b6388061b5fe889431 + checksum: cb2d7a923cfec9d92b69694e613f0becbea627d4d9d919ab349f28ea81d8f5fa71aa437d89b4bc5291a5edb7a07c643ccff2139e2d7ab92a58235d0b05d2a48d languageName: node linkType: hard @@ -17170,9 +17442,9 @@ __metadata: linkType: hard "@types/event-source-polyfill@npm:^1.0.0": - version: 1.0.1 - resolution: "@types/event-source-polyfill@npm:1.0.1" - checksum: 37f3ccc40e2fc43230047c3323f8bfc55f6ed40aee8c61af7f6b702a923be5615362cf3241f5a536f9c64932309a2184a0181bb48e105a94b968b8321cae1c60 + version: 1.0.2 + resolution: "@types/event-source-polyfill@npm:1.0.2" + checksum: f0813edfee0af768e6e0994b48f9f618df7a5d9023c383a8f35e9e805dec560222dc40fc583d5f1404977febb7353c27c1d0606c67d948a2d18634c18ae437a9 languageName: node linkType: hard @@ -17184,35 +17456,35 @@ __metadata: linkType: hard "@types/express-serve-static-core@npm:*, @types/express-serve-static-core@npm:^4.17.30, @types/express-serve-static-core@npm:^4.17.33, @types/express-serve-static-core@npm:^4.17.5": - version: 4.17.36 - resolution: "@types/express-serve-static-core@npm:4.17.36" + version: 4.17.37 + resolution: "@types/express-serve-static-core@npm:4.17.37" dependencies: "@types/node": "*" "@types/qs": "*" "@types/range-parser": "*" "@types/send": "*" - checksum: 410b13cbd663f18c0f8729e7f2ff54d960d96de76ebbae7cadb612972f85cc66c54051e00d32f11aa230c0a683d81a6d6fc7f7e4e383a95c0801494c517f36e1 + checksum: 2dab1380e45eb44e56ecc1be1c42c4b897364d2f2a08e03ca28fbcb1e6866e390217385435813711c046f9acd684424d088855dc32825d5cbecf72c60ecd037f languageName: node linkType: hard "@types/express-session@npm:^1.17.2": - version: 1.17.7 - resolution: "@types/express-session@npm:1.17.7" + version: 1.17.8 + resolution: "@types/express-session@npm:1.17.8" dependencies: "@types/express": "*" - checksum: 4764eafaf4e26842e891e83fa9fee30b92cc3724d91987aac3a658322f9a69fb544dae24fc3aba6e15fe9575ed862760ebecd7ff97a947afb695284967434a65 + checksum: e1af8797b321ce05e0732c58aa982f00ab34b6edb337c289092e66c789ae1bbb4ca14d2caa0e0ff02522047402bcff828873b035e2785fb92f2381a0eb34240c languageName: node linkType: hard "@types/express@npm:*, @types/express@npm:^4.17.13, @types/express@npm:^4.17.17, @types/express@npm:^4.17.6": - version: 4.17.17 - resolution: "@types/express@npm:4.17.17" + version: 4.17.18 + resolution: "@types/express@npm:4.17.18" dependencies: "@types/body-parser": "*" "@types/express-serve-static-core": ^4.17.33 "@types/qs": "*" "@types/serve-static": "*" - checksum: 0196dacc275ac3ce89d7364885cb08e7fb61f53ca101f65886dbf1daf9b7eb05c0943e2e4bbd01b0cc5e50f37e0eea7e4cbe97d0304094411ac73e1b7998f4da + checksum: 8c178da4f0edff1f006d871fbdc3f849620986ff10bad252f3dfd45b57554e26aaa28c602285df028930d5216e257a06fbaf795070f8bb42f7d87e3b689cba50 languageName: node linkType: hard @@ -17308,9 +17580,9 @@ __metadata: linkType: hard "@types/http-errors@npm:^2.0.0": - version: 2.0.1 - resolution: "@types/http-errors@npm:2.0.1" - checksum: 3bb0c50b0a652e679a84c30cd0340d696c32ef6558518268c238840346c077f899315daaf1c26c09c57ddd5dc80510f2a7f46acd52bf949e339e35ed3ee9654f + version: 2.0.2 + resolution: "@types/http-errors@npm:2.0.2" + checksum: d7f14045240ac4b563725130942b8e5c8080bfabc724c8ff3f166ea928ff7ae02c5194763bc8f6aaf21897e8a44049b0492493b9de3e058247e58fdfe0f86692 languageName: node linkType: hard @@ -17393,20 +17665,20 @@ __metadata: linkType: hard "@types/jenkins@npm:^0.23.1": - version: 0.23.3 - resolution: "@types/jenkins@npm:0.23.3" + version: 0.23.4 + resolution: "@types/jenkins@npm:0.23.4" dependencies: "@types/node": "*" - checksum: bfe05038e2a170ebaf92b9dedef436450b2cfd107551bda8e02f1af69db14c2108d6da797c869305cf402dc174af4da0130c156a3812deb315b32e7eb9a50136 + checksum: 378af85d2f7c3da13cb04098837224551d5d048e6a7b87e78aea8c5e4385f8a1b2cdabd592bb7a6eaa0d46a27eb840c3aa3baa35f1f0449f7f03b8eb527c8562 languageName: node linkType: hard "@types/jest-when@npm:^3.5.0": - version: 3.5.2 - resolution: "@types/jest-when@npm:3.5.2" + version: 3.5.3 + resolution: "@types/jest-when@npm:3.5.3" dependencies: "@types/jest": "*" - checksum: 106230dd71ee266bbd7620ab339a7305054e56ba7638f0eff9f222e67a959df0ad68a7f0108156c50f7005881bae59cd5c38b3760c101d060cdb3dac9cd77ee2 + checksum: 5dc2661ad570b80b8f97d7dabc50a0229f21818eefc73024b88a70216c2666f56bd97769fef565263d7242878f8187531bb14427dcb06709e9b98a1671668e9d languageName: node linkType: hard @@ -17431,11 +17703,11 @@ __metadata: linkType: hard "@types/jquery@npm:^3.3.34": - version: 3.5.19 - resolution: "@types/jquery@npm:3.5.19" + version: 3.5.20 + resolution: "@types/jquery@npm:3.5.20" dependencies: "@types/sizzle": "*" - checksum: 0298e53a353089e2abae4be2f660b5f2bfb4797464623701c5c2f2c911317b554f1887c2c3d587d0f724d70a3fb5e31907bf7fa5d96df33af07e2842660ef52a + checksum: 9bd69faea3d60f52d3029a87b890003042a9dcf4f538c23ac2c11b3bd0e0ccd86b281d5ba3028d1b02df67c69266b8dc0ef0a35696ae174515ecf34523a0287b languageName: node linkType: hard @@ -17454,19 +17726,19 @@ __metadata: linkType: hard "@types/js-yaml@npm:^4.0.0, @types/js-yaml@npm:^4.0.1": - version: 4.0.5 - resolution: "@types/js-yaml@npm:4.0.5" - checksum: 7dcac8c50fec31643cc9d6444b5503239a861414cdfaa7ae9a38bc22597c4d850c4b8cec3d82d73b3fbca408348ce223b0408d598b32e094470dfffc6d486b4d + version: 4.0.6 + resolution: "@types/js-yaml@npm:4.0.6" + checksum: d4439ec2cc830d355c2a1d7508f49888931b2cfe59d786d27621edd530bf06314b1dceeaa759e21f9b035a0ff623a0ca306752ebb73df9485c02abe045bd962c languageName: node linkType: hard "@types/jscodeshift@npm:^0.11.0": - version: 0.11.6 - resolution: "@types/jscodeshift@npm:0.11.6" + version: 0.11.7 + resolution: "@types/jscodeshift@npm:0.11.7" dependencies: ast-types: ^0.14.1 recast: ^0.20.3 - checksum: 418d34488f74e711b37fcfce5129df3494d7fd30e852b3e80ff659ef0b1a4a83911e62883a10d7e1111316b569fa91a5a6a6d22fee86c2d69db829e25b534b27 + checksum: c6b81d537dca08c24db76e5e75d6056ef7c5b7651aebc319277321e2f2421984cc237ac71593dec374e49f9eae28c22150a37de3a572f141d55382c193091899 languageName: node linkType: hard @@ -17482,18 +17754,18 @@ __metadata: linkType: hard "@types/json-schema-merge-allof@npm:^0.6.0": - version: 0.6.1 - resolution: "@types/json-schema-merge-allof@npm:0.6.1" + version: 0.6.2 + resolution: "@types/json-schema-merge-allof@npm:0.6.2" dependencies: "@types/json-schema": "*" - checksum: 4d3648e9bf6f554f09c28955ea44b9d98c25e17e1aeb0fa3d62ea06729ec0ef16ca1b2bf1b7e12d86a6a3ea72a8eac50f34adca50984bcb9007a67b2fe9eb82b + checksum: 2be8f35eb47cb6f2344c15625010edd0983d258b0eba76e4193a1e80a3b3334bcb7efe1060594a8420cdcb092201e5ad3d78442f7af2edc548661c19c9a65440 languageName: node linkType: hard "@types/json-schema@npm:*, @types/json-schema@npm:^7.0.11, @types/json-schema@npm:^7.0.4, @types/json-schema@npm:^7.0.5, @types/json-schema@npm:^7.0.6, @types/json-schema@npm:^7.0.7, @types/json-schema@npm:^7.0.8, @types/json-schema@npm:^7.0.9": - version: 7.0.12 - resolution: "@types/json-schema@npm:7.0.12" - checksum: 00239e97234eeb5ceefb0c1875d98ade6e922bfec39dd365ec6bd360b5c2f825e612ac4f6e5f1d13601b8b30f378f15e6faa805a3a732f4a1bbe61915163d293 + version: 7.0.13 + resolution: "@types/json-schema@npm:7.0.13" + checksum: 345df21a678fa72fb389f35f33de77833d09d4a142bb2bcb27c18690efa4cf70fc2876e43843cefb3fbdb9fcb12cd3e970a90936df30f53bbee899865ff605ab languageName: node linkType: hard @@ -17581,9 +17853,9 @@ __metadata: linkType: hard "@types/lodash@npm:^4.14.151, @types/lodash@npm:^4.14.173, @types/lodash@npm:^4.14.175": - version: 4.14.198 - resolution: "@types/lodash@npm:4.14.198" - checksum: b290e4480707151bcec738bca40527915defe52a0d8e26c83685c674163a265e1a88cb2ee56b0fb587a89819d0cd5df86ada836aec3e9c2e4bf516e7d348d524 + version: 4.14.199 + resolution: "@types/lodash@npm:4.14.199" + checksum: e68d1fcbbfce953ed87b296a628573f62939227bcda0c934954e862b421e8a34c5e71cad6fea27b9980567909e6a4698f09025692958e36d64ea9ed99ec6fb2e languageName: node linkType: hard @@ -17619,9 +17891,9 @@ __metadata: linkType: hard "@types/marked@npm:^4.0.0": - version: 4.3.1 - resolution: "@types/marked@npm:4.3.1" - checksum: eb6891b925d53ea53057f088b28f9232016499e62639cbb4a67f7d34f288ec6a8e40aae4836dbd06bd0fc3c541fca1175cd50d9e8d405547b6be7b7781e6a2a5 + version: 4.3.2 + resolution: "@types/marked@npm:4.3.2" + checksum: c1107079d6c368dd60a668a41aa2101d006cad404b6eb4af6723d419dc869b278928fb769825f11d0d311a8cf437428992729c8a47253b6a3894a6326b1ee4d9 languageName: node linkType: hard @@ -17642,9 +17914,9 @@ __metadata: linkType: hard "@types/mime-types@npm:^2.1.0": - version: 2.1.1 - resolution: "@types/mime-types@npm:2.1.1" - checksum: 106b5d556add46446a579ad25ff15d6b421851790d887edcad558c90c1e64b1defc72bfbaf4b08f208916e21d9cc45cdb951d77be51268b18221544cfe054a3c + version: 2.1.2 + resolution: "@types/mime-types@npm:2.1.2" + checksum: 9e3c78f1c63211e0450901212566a046da68d4438a5e543333ec9b0be3259bd5d01532734dc51ead40104889b98d12c7663b65212a318aafad3e34c98204e9e1 languageName: node linkType: hard @@ -17670,27 +17942,27 @@ __metadata: linkType: hard "@types/minimist@npm:^1.2.0": - version: 1.2.2 - resolution: "@types/minimist@npm:1.2.2" - checksum: b8da83c66eb4aac0440e64674b19564d9d86c80ae273144db9681e5eeff66f238ade9515f5006ffbfa955ceff8b89ad2bd8ec577d7caee74ba101431fb07045d + version: 1.2.3 + resolution: "@types/minimist@npm:1.2.3" + checksum: 666ea4f8c39dcbdfbc3171fe6b3902157c845cc9cb8cee33c10deb706cda5e0cc80f98ace2d6d29f6774b0dc21180c96cd73c592a1cbefe04777247c7ba0e84b languageName: node linkType: hard "@types/mock-fs@npm:^4.10.0, @types/mock-fs@npm:^4.13.0": - version: 4.13.1 - resolution: "@types/mock-fs@npm:4.13.1" + version: 4.13.2 + resolution: "@types/mock-fs@npm:4.13.2" dependencies: "@types/node": "*" - checksum: a5fcf8212daa270e6aa560019a4bd28a66e6fa49c55c1373746d5894f4aa1aafa5588335194953cf014de3c77df6be67a041fb6638ead7124307370985880b6c + checksum: 726975ae51f7b4068bb059c633ae28a1d85595d3036c235d3f9c9dc3a9c519dc6b811713af1b686807e80a484a6ec47a742a11b4ada32a6e74eee6538a9f4658 languageName: node linkType: hard "@types/morgan@npm:^1.9.0": - version: 1.9.5 - resolution: "@types/morgan@npm:1.9.5" + version: 1.9.6 + resolution: "@types/morgan@npm:1.9.6" dependencies: "@types/node": "*" - checksum: f98deb4c7f2ad6049ad34ed7b0f0d427546bdf2358011070af9d597de1b0a03b38cc10cfe65ef2e7673e569c384303d949e76df701acefe288d547f614142973 + checksum: 6525248325a74342f929c958be69c0840c8f3a288e003a8904319cae92e531f17a8aa2700701e66775adcca7f9506dd630fec2f95dc04a3e73add04fde42aab8 languageName: node linkType: hard @@ -17711,38 +17983,38 @@ __metadata: linkType: hard "@types/ndjson@npm:^2.0.1": - version: 2.0.1 - resolution: "@types/ndjson@npm:2.0.1" + version: 2.0.2 + resolution: "@types/ndjson@npm:2.0.2" dependencies: "@types/node": "*" "@types/through": "*" - checksum: d7e5ef9d43424851d1d3e1b223c0d6508bf283c4a769eb08312a96b1e6e60011b3454a5599dbecfdad4128f7c9c6c1b5b4abfabe29bb5065d412dead1c20f9e8 + checksum: 2f4d60229a01dadd4ed1d7df923223788cc4517a15d0fc07b56b3dbdefb567646334e173d7f976a8a7ce7b85df74bf78fd8805f41bdd9ebd8d135310f472a2cb languageName: node linkType: hard "@types/node-fetch@npm:^2.5.0, @types/node-fetch@npm:^2.5.12, @types/node-fetch@npm:^2.5.7, @types/node-fetch@npm:^2.6.1": - version: 2.6.4 - resolution: "@types/node-fetch@npm:2.6.4" + version: 2.6.5 + resolution: "@types/node-fetch@npm:2.6.5" dependencies: "@types/node": "*" - form-data: ^3.0.0 - checksum: f3e1d881bb42269e676ecaf49f0e096ab345e22823a2b2d071d60619414817fe02df48a31a8d05adb23054028a2a65521bdb3906ceb763ab6d3339c8d8775058 + form-data: ^4.0.0 + checksum: 686ee0d52bb82d73f82c0da0bb025d4af1ba7bd8df4edd09336f6179eb838b6d4b5f0a524677a8faec2b00918d1b08a1690d50fa592c9741a5df6a8041a52495 languageName: node linkType: hard "@types/node-forge@npm:^1.3.0": - version: 1.3.5 - resolution: "@types/node-forge@npm:1.3.5" + version: 1.3.6 + resolution: "@types/node-forge@npm:1.3.6" dependencies: "@types/node": "*" - checksum: b93dae2639ab166d8703567285538f14a53fbe9199b02c1e3752d147260be4a8be5257246558a81fc3eee3c5880704039a6aa22c4415aeb06758aad0391ac39c + checksum: 5fe97ce83937c51215a52eb8c9d5c4458abbca2b3cfd91a65142f20fd4a2830ed10ab1a8c860efc55ff36553f939a75c4a6d5c243ed6e24e55a005c9bddeaf43 languageName: node linkType: hard -"@types/node@npm:*, @types/node@npm:>=12.12.47, @types/node@npm:>=13.7.0": - version: 20.6.0 - resolution: "@types/node@npm:20.6.0" - checksum: 52611801af5cf151c6fac1963aa4a8a8ca2e388a9e9ed82b01b70bca762088ded5b32cc789c5564220d5d7dccba2b8dd34446a3d4fc74736805e1f2cf262e29d +"@types/node@npm:*, @types/node@npm:>=12.12.47, @types/node@npm:>=13.7.0, @types/node@npm:^20.1.1": + version: 20.6.5 + resolution: "@types/node@npm:20.6.5" + checksum: b849e849cf7631458a65c5019c81962028e306d8c4455a48422277b240f5a7eb8a1f1dafa60306bd4c773b77263bb8b05c074b1026e868bd137bb2022cf63ea2 languageName: node linkType: hard @@ -17753,13 +18025,6 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:^14.14.31": - version: 14.18.59 - resolution: "@types/node@npm:14.18.59" - checksum: 6a2a5a5c07b9150bad47b821deb723ab72d33beae8b7b75a10787550236e6428d547806ba3103c86918b849b790bfaef0b165650213d807792effcfb7181be10 - languageName: node - linkType: hard - "@types/node@npm:^15.6.1": version: 15.14.9 resolution: "@types/node@npm:15.14.9" @@ -17767,17 +18032,17 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:^16.9.2": - version: 16.18.43 - resolution: "@types/node@npm:16.18.43" - checksum: a3ae424834818d1aa53d05e9de954b4559aaa9c02294e654403d9bd2a2b1db608c328755970071369a0c85159a6f2969502e1b9c7e1f29d2629ca677c33c8bdb +"@types/node@npm:^16.11.26, @types/node@npm:^16.9.2": + version: 16.18.54 + resolution: "@types/node@npm:16.18.54" + checksum: 208e8fc64f605e9cd55ab5e620a0fd019d8fe5629e3e3c5de869a149b731ab0fac5720c516dccc0ecc834ac27df754723dfe6554551663f016ba5096ea8851df languageName: node linkType: hard "@types/node@npm:^18.11.17, @types/node@npm:^18.17.8": - version: 18.17.8 - resolution: "@types/node@npm:18.17.8" - checksum: ebb71526368c9c58f03e2c2408bfda4aa686c13d84226e2c9b48d9c4aee244fb82e672aaf4aa8ccb6e4993b4274d5f4b2b3d52d0a2e57ab187ae653903376411 + version: 18.17.18 + resolution: "@types/node@npm:18.17.18" + checksum: 59cbd906363d37017fe9ba0c08c1446e440d4d977459609c5f90b8fb7eb41f273ce8af30c5a5b5d599d7de934c1b3702bc9fc27caf8d2270e5cdb659c5232991 languageName: node linkType: hard @@ -17796,9 +18061,9 @@ __metadata: linkType: hard "@types/nunjucks@npm:^3.1.4": - version: 3.2.3 - resolution: "@types/nunjucks@npm:3.2.3" - checksum: f4263a39f0bafb701fe75a088cf2100f0fe717ab29c53d13eb60fea77e945f8cfdabfb84bd6ce85fd11586f90aa36539cf5bd489166edcf56a189a0407d481a2 + version: 3.2.4 + resolution: "@types/nunjucks@npm:3.2.4" + checksum: d154c6cc98320b6b9f48892eb4238f961b0196e24eb98252f9dceaa0b17bf70cd480a11d4ffda9f419d2570abf6d96524ebd3193b101f0fcf73c65af3e56d064 languageName: node linkType: hard @@ -17826,43 +18091,43 @@ __metadata: linkType: hard "@types/passport-auth0@npm:^1.0.5": - version: 1.0.5 - resolution: "@types/passport-auth0@npm:1.0.5" + version: 1.0.7 + resolution: "@types/passport-auth0@npm:1.0.7" dependencies: "@types/express": "*" "@types/passport": "*" - checksum: b86b69a182864cae6877c0f16a1d62e24a394dc9cde8e7285a29aef89d52fbb555b899e061157bfd52420dcbccd6fd9b189155e5367a22763b0b2813cbb28354 + checksum: 75b17c3424054a8b0238905088a7c34efab771a0bccc5ce0270d5c6f238ba859fb7354531c0df4f39e7b2c28f10090f9c260ffc42773211fc216a9acbf11170a languageName: node linkType: hard "@types/passport-github2@npm:^1.2.4": - version: 1.2.5 - resolution: "@types/passport-github2@npm:1.2.5" + version: 1.2.6 + resolution: "@types/passport-github2@npm:1.2.6" dependencies: "@types/express": "*" "@types/passport": "*" "@types/passport-oauth2": "*" - checksum: a4f1851edb91a2502136b7e76dd10fd3c52aebec938ff21ffa2ade40b1f62d0e7f65991c80589f5cfa40b6cba04bf0b8ea46db6942975bf5918fa4690f681235 + checksum: 72d1c8bc335d0d7f329372ac8bc7edb22c8bea151d4438d876036b6b768f4d12c8de305abbc25b650f373b902bae250008cb185074d2d78da49d15e981208d81 languageName: node linkType: hard "@types/passport-google-oauth20@npm:^2.0.3": - version: 2.0.11 - resolution: "@types/passport-google-oauth20@npm:2.0.11" + version: 2.0.12 + resolution: "@types/passport-google-oauth20@npm:2.0.12" dependencies: "@types/express": "*" "@types/passport": "*" "@types/passport-oauth2": "*" - checksum: 5e87a0bf40d77ce863dbcea4ae1cd6bccc663282593c9b6ce83b0e2d5d6c56ed9dc0275a04f5d81832f03b3a477fd47d17fd9b3ee22ceb69ca445ab0b0d326d7 + checksum: e73fff5b7e3191ab1a3633b05b4463d656ef658fe0612bc33517a1df81c8a1f019c91dcbd244233320f9eb133892b589dcb6a6348082e85e45aa5c6ed034d191 languageName: node linkType: hard "@types/passport-microsoft@npm:^1.0.0": - version: 1.0.0 - resolution: "@types/passport-microsoft@npm:1.0.0" + version: 1.0.1 + resolution: "@types/passport-microsoft@npm:1.0.1" dependencies: "@types/passport-oauth2": "*" - checksum: d7c8b439b18cddcf707ea0c575748ecb344b6fb3c78a847aaad83246abf081c8b485efa86a3788cd5f49f4ca84a1444d813697a433fab9d04f35fb67d628cb23 + checksum: eec44ee6e14448b89434503a438021df6738513fa705b42a6d979a6b817ce89f939996a5d30707a64bca700dbc7c6ae52f1010ad2e986bb7ccd9f935d2114c9e languageName: node linkType: hard @@ -17878,56 +18143,56 @@ __metadata: linkType: hard "@types/passport-saml@npm:^1.1.3": - version: 1.1.3 - resolution: "@types/passport-saml@npm:1.1.3" + version: 1.1.4 + resolution: "@types/passport-saml@npm:1.1.4" dependencies: "@types/express": "*" "@types/passport": "*" - checksum: 1d0abc04b1f19c043f9dd311248d3d98b00b311ed6d2cfa6cb17ef0954d0b403de4ccca4f1be192cbfda92105eb799c7963da6f39e4542ca254b06d5c467ed4a + checksum: 2a71d64c72b0f6cf4cafcc21138f5c925cc9bc375a0dd7ece664e8b1254dd4a704566632bafa3e16032821a7f010de4023169589b643a3b952709cde228a8c8c languageName: node linkType: hard "@types/passport-strategy@npm:^0.2.35": - version: 0.2.35 - resolution: "@types/passport-strategy@npm:0.2.35" + version: 0.2.36 + resolution: "@types/passport-strategy@npm:0.2.36" dependencies: "@types/express": "*" "@types/passport": "*" - checksum: e5949063ad8977ce1f7cf2a5df6bc379c4d43a959c9946bfed6570ef379c6c12d1713212a29b3b5aafc631c5ebe9bfe082116f3e75ca1bf45d79dd889671532d + checksum: 7f626eb6a12110c1ce64dd5d5181fc0795e77d60123872e33f6fa1c02a2a19451207eaf03543232241a1d70bfe0318f2ffeef88f6309d7cbaa43d2bf6ec1d1e8 languageName: node linkType: hard "@types/passport@npm:*, @types/passport@npm:^1.0.3": - version: 1.0.12 - resolution: "@types/passport@npm:1.0.12" + version: 1.0.13 + resolution: "@types/passport@npm:1.0.13" dependencies: "@types/express": "*" - checksum: 2bce41b248566d8c2aeafcb38f105e3521d42a572e92da9edc5eb669f1b3cb02e5911c9d124191f67d432b677562a885b6ad7f56320c712df1e87ba7619eb8a4 + checksum: 84330bedb330302ffd92b009b9b88eb20d3c66b659b383badb9aa3035612b40b47052153858b2498a95d9979d668443bdee3182345819cb18635dfb7f24c109c languageName: node linkType: hard "@types/pg@npm:^8.6.6": - version: 8.10.2 - resolution: "@types/pg@npm:8.10.2" + version: 8.10.3 + resolution: "@types/pg@npm:8.10.3" dependencies: "@types/node": "*" pg-protocol: "*" pg-types: ^4.0.1 - checksum: 49da89f64cec1bd12a3fbc0c72b17d685c2fee579726a529f62fcab395dbc5696d80455073409947a577164b3c53a90181a331e4a5d9357679f724d4ce37f4b9 + checksum: 05a12be3f18cc67728e3aee5a7426f065351ca991e351d2e7a0562c5d9063425d67fe88fd35108834e0fa1f5624032fefbf371cf8f3cc47230a666aa953425b9 languageName: node linkType: hard "@types/ping@npm:^0.4.1": - version: 0.4.1 - resolution: "@types/ping@npm:0.4.1" - checksum: 9b94837fe66df70558c5a42b0e0c8371b4950ab56b96c42c8df809ff2cf52477dd0a7e01d2e6b38af8bb6683b3dcb54587960b96b4b1f3d40fdb529aea348ad0 + version: 0.4.2 + resolution: "@types/ping@npm:0.4.2" + checksum: 4ea20f8c04d6d52ac9d4a551af03b940c273616fc647d9905197400f920f744c5224ee6913ef26b845633e8e44ebab4195e4fd71daf271090336f303069b7fef languageName: node linkType: hard -"@types/pluralize@npm:^0.0.30": - version: 0.0.30 - resolution: "@types/pluralize@npm:0.0.30" - checksum: 7a9a4a24aac1f74bd63e592a824ebec114486e0635a94496e92aa37fa388fac585be108d3ccfc7b2c490963679ec4900fbf394d22fa6cbf419f22cc499ab5a29 +"@types/pluralize@npm:^0.0.31": + version: 0.0.31 + resolution: "@types/pluralize@npm:0.0.31" + checksum: 950d52d8f6709cdb7001336942fba0a63bf54b45695391fc2244d03db69b0eb6f187f80519d74941f5ce1dfa900d3975f2ed52e98b1f63a79045f5c085832beb languageName: node linkType: hard @@ -17939,9 +18204,9 @@ __metadata: linkType: hard "@types/prop-types@npm:*, @types/prop-types@npm:^15.0.0, @types/prop-types@npm:^15.7.3, @types/prop-types@npm:^15.7.5": - version: 15.7.5 - resolution: "@types/prop-types@npm:15.7.5" - checksum: 5b43b8b15415e1f298243165f1d44390403bb2bd42e662bca3b5b5633fdd39c938e91b7fce3a9483699db0f7a715d08cef220c121f723a634972fdf596aec980 + version: 15.7.8 + resolution: "@types/prop-types@npm:15.7.8" + checksum: 61dfad79da8b1081c450bab83b77935df487ae1cdd4660ec7df6be8e74725c15fa45cf486ce057addc956ca4ae78300b97091e2a25061133d1b9a1440bc896ae languageName: node linkType: hard @@ -17978,11 +18243,11 @@ __metadata: linkType: hard "@types/react-dom@npm:^17": - version: 17.0.20 - resolution: "@types/react-dom@npm:17.0.20" + version: 17.0.21 + resolution: "@types/react-dom@npm:17.0.21" dependencies: "@types/react": ^17 - checksum: 525439fb14a033fc5dbe74711ecc50ec82273a528df9656594066a6219401e975101dafffd15d9a1a57a9442d52ea0c92eaacae09554dde27cd792e773f67467 + checksum: a2e3f068c1374601856b63bc57f3f436cf6270c1ba5c5cef0776def6de296c8bdd31c39b5be9e9e77f4652e923bef1e71ae377a2b038f4a81bfd0fec8d10d0d0 languageName: node linkType: hard @@ -17996,20 +18261,11 @@ __metadata: linkType: hard "@types/react-helmet@npm:^6.1.0": - version: 6.1.6 - resolution: "@types/react-helmet@npm:6.1.6" + version: 6.1.7 + resolution: "@types/react-helmet@npm:6.1.7" dependencies: "@types/react": "*" - checksum: 81560c56bfe854b6a43aee31360862588ac875d1177b975da5ce049ac9aa2f7c98dcde65d4397bfaa04e468f40cf3ab2975a2ef966a69d64a60493422898698d - languageName: node - linkType: hard - -"@types/react-is@npm:^18.2.1": - version: 18.2.1 - resolution: "@types/react-is@npm:18.2.1" - dependencies: - "@types/react": "*" - checksum: b44c3262efa2c68fa6fe2beb9ef86170b18305469461a3f97aa14943cc033cb21a26944f718bdb6434eea6e8f7fcba251c4f45b65b897a3fcf751b5a6003cf82 + checksum: d5ee8343f10f8746a022249c6401493baa73241a90b5002b59e8a6ce31650b9e1ab38d398eba5564af026f68eda107c8fcdca01fc046a163a96dc422710f6a77 languageName: node linkType: hard @@ -18026,11 +18282,11 @@ __metadata: linkType: hard "@types/react-sparklines@npm:^1.7.0": - version: 1.7.2 - resolution: "@types/react-sparklines@npm:1.7.2" + version: 1.7.3 + resolution: "@types/react-sparklines@npm:1.7.3" dependencies: "@types/react": "*" - checksum: e0e8479c256731c3fe9405a5d3061f81838f8708bc585203afa89ff81f266f06f5b497b1db77e6a488d6073de623c4093afd9cbf3626bb7c89f996632749c281 + checksum: 4bcdc526ba2bab1354c8add8a01e10c42203950edfeda70d304a50b51f299c27432a8c8a7bbfce1a860a2b72bbfaf867bafe1b01f877cdaaae54e4ed209554f0 languageName: node linkType: hard @@ -18044,11 +18300,11 @@ __metadata: linkType: hard "@types/react-text-truncate@npm:^0.14.0": - version: 0.14.1 - resolution: "@types/react-text-truncate@npm:0.14.1" + version: 0.14.2 + resolution: "@types/react-text-truncate@npm:0.14.2" dependencies: "@types/react": "*" - checksum: 6b5ffb04b41fbe88c63ff7e8ff815fa7e3e52d128a5ccbc134fc412da6b6904dc55a34891aa4769cb5f9b958f48288475f500281cc1f3d74450610a3ec657491 + checksum: 714b8dade2cd149b3a353c6914065f8aaf2e8d01c21fc1e92afe9e9cf19b037c6a9c34c9100a8009848a6d8747fbd0f4c3b2fe4676b0afa35e347b2fecc92811 languageName: node linkType: hard @@ -18080,22 +18336,22 @@ __metadata: linkType: hard "@types/react-window@npm:^1.8.5": - version: 1.8.5 - resolution: "@types/react-window@npm:1.8.5" + version: 1.8.6 + resolution: "@types/react-window@npm:1.8.6" dependencies: "@types/react": "*" - checksum: 5f519e1402300d11b6e6595223feb6499f3227e38da166cbc565773cd7f71862abcf855b7835d391b5119fcfacdfba79d73a965b45f60a293fc1ff25986319ed + checksum: 3084190ab50a84d8499a6df574ad67474566cd7aeeb8fc6ce82a7a13421fd39e21a059c51f9d12f38e5ac52eb9d65f6184e3fb6cb62841e93b197b7401b36e35 languageName: node linkType: hard "@types/react@npm:^17": - version: 17.0.65 - resolution: "@types/react@npm:17.0.65" + version: 17.0.67 + resolution: "@types/react@npm:17.0.67" dependencies: "@types/prop-types": "*" "@types/scheduler": "*" csstype: ^3.0.2 - checksum: bb862f0f97a49e690cd5c62743307d17398ee62b87bbb2c85c1b01cb992244c0aef4ecdedaab0e8d33c6315d5a8f067cf90e7f1c366b8819678c59204e202932 + checksum: eb4915fc7d24e19fe6e98dfe98ade377423b1263e7dc001beda41b0298152fb5a410a55dde5def5ec0838156239a48e778d522da03d319ae5ecea80d455da604 languageName: node linkType: hard @@ -18109,28 +18365,28 @@ __metadata: linkType: hard "@types/recharts@npm:^1.8.14, @types/recharts@npm:^1.8.15": - version: 1.8.24 - resolution: "@types/recharts@npm:1.8.24" + version: 1.8.25 + resolution: "@types/recharts@npm:1.8.25" dependencies: "@types/d3-shape": ^1 "@types/react": "*" - checksum: 1341e5472bf62a83ab98648bc5c14a9a81fba16af9255203ef12a21caa21a988fac3198d9771703394eb876d4fbefb42e818865e35ecfe0d105aee1d1164aa6e + checksum: b2ab1596f391b70e349ae5f6fc6b29c16f6298f1151747aff84b3380f4644c4e087a489ca55325dc627794317f8e677c9906ab75d2e270c79e45da976a347af5 languageName: node linkType: hard "@types/recursive-readdir@npm:^2.2.0": - version: 2.2.1 - resolution: "@types/recursive-readdir@npm:2.2.1" + version: 2.2.2 + resolution: "@types/recursive-readdir@npm:2.2.2" dependencies: "@types/node": "*" - checksum: 9e8d5ecb98c009016bf65f1b7cc1f997847dc64634e1c4209fae10718a1fcecd3c3a72c4bae66cbc9973165da5e4e7f5b4cda8793b3a5cefca8c05963f6dbf82 + checksum: ed7f73d11354c7df7c5296a73500ace0b9874083c9f9cce4c5a294bb6c9b11f92d25c08a23bdc991f0537358d31e2ae3943169d42fe739ff54ecfddf9ff6b420 languageName: node linkType: hard "@types/regression@npm:^2.0.0": - version: 2.0.2 - resolution: "@types/regression@npm:2.0.2" - checksum: 28ae464c5ffda1698cecf1b1c2e21ed016ae1d71623c7f40bc5404aa55569cca03ac33d29737805059851cc734946027b006858d13a642e12240267c96d49299 + version: 2.0.3 + resolution: "@types/regression@npm:2.0.3" + checksum: 774ef76911225b61c44946573b54ab710401d0e65b9433aa7014c701272167c47e818d4c9809284514881837c2159cd47aad6b290f00f8581920f2c7a146a512 languageName: node linkType: hard @@ -18182,12 +18438,12 @@ __metadata: linkType: hard "@types/rollup-plugin-peer-deps-external@npm:^2.2.0": - version: 2.2.1 - resolution: "@types/rollup-plugin-peer-deps-external@npm:2.2.1" + version: 2.2.2 + resolution: "@types/rollup-plugin-peer-deps-external@npm:2.2.2" dependencies: "@types/node": "*" rollup: ^0.63.4 - checksum: d6bf4ca92e8b09ca35c0397b89a8b8368bb3d1448a5b82a39ab18886f4b4a3d73f197ed49470e10350b2b5ddc892d4050c5e01ac6247fc63321a5ac9fc6f7363 + checksum: a821911276d1882cf30c9650abc3c1cf7b29490ecacfdd537663a4de32b42ff7171bcd69568ce1b256191ad1d2937b1de839d1db85538769787986a5877273e2 languageName: node linkType: hard @@ -18201,11 +18457,11 @@ __metadata: linkType: hard "@types/sanitize-html@npm:^2.6.2": - version: 2.9.0 - resolution: "@types/sanitize-html@npm:2.9.0" + version: 2.9.1 + resolution: "@types/sanitize-html@npm:2.9.1" dependencies: htmlparser2: ^8.0.0 - checksum: b60f42b740bbfb1b1434ce8b43925a38ecc608b60aa654fd009d2e22e33f324b61d370768c55bd2fd98e03de08518ffa8911d61606c483526fb931bb8b59d1b0 + checksum: 381db8e3f22876e8f6aa8f0997af73c71220c8398545d809ebd4e25d33480e73642b8c143a87d87bba504a43ab58d70a724c60eb3fd8fde31a813b682730c98f languageName: node linkType: hard @@ -18217,9 +18473,9 @@ __metadata: linkType: hard "@types/semver@npm:^7.3.12, @types/semver@npm:^7.3.8, @types/semver@npm:^7.5.0": - version: 7.5.2 - resolution: "@types/semver@npm:7.5.2" - checksum: 743aa8a2b58e20b329c19bd2459152cb049d12fafab7279b90ac11e0f268c97efbcb606ea0c681cca03f79015381b40d9b1244349b354270bec3f939ed49f6e9 + version: 7.5.3 + resolution: "@types/semver@npm:7.5.3" + checksum: 349fdd1ab6c213bac5c991bac766bd07b8b12e63762462bb058740dcd2eb09c8193d068bb226f134661275f2022976214c0e727a4e5eb83ec1b131127c980d3e languageName: node linkType: hard @@ -18234,11 +18490,11 @@ __metadata: linkType: hard "@types/serve-handler@npm:^6.1.0": - version: 6.1.1 - resolution: "@types/serve-handler@npm:6.1.1" + version: 6.1.2 + resolution: "@types/serve-handler@npm:6.1.2" dependencies: "@types/node": "*" - checksum: f519f83b18d7dea80f188f387a56dfe30fe944196849c470902fabf9db344c083c470f67e3362ad3f2294512950bc55924282c5c7a911ec8d507c37c6861d8ce + checksum: 6b206cba18bf77b938e340e1015c631d92b492918ba78dfdff57590a25da8c4bc63fba90f43d763f854c5aa523b243c283ba84d14cfeb1841795337c8b978bd6 languageName: node linkType: hard @@ -18286,14 +18542,7 @@ __metadata: languageName: node linkType: hard -"@types/sinonjs__fake-timers@npm:8.1.1": - version: 8.1.1 - resolution: "@types/sinonjs__fake-timers@npm:8.1.1" - checksum: ca09d54d47091d87020824a73f026300fa06b17cd9f2f9b9387f28b549364b141ef194ee28db762f6588de71d8febcd17f753163cb7ea116b8387c18e80ebd5c - languageName: node - linkType: hard - -"@types/sizzle@npm:*, @types/sizzle@npm:^2.3.2": +"@types/sizzle@npm:*": version: 2.3.2 resolution: "@types/sizzle@npm:2.3.2" checksum: 783b6382934d8f12f2e21220a01c4557150f07abd18336f392664fb74ceaa9a9d59b7c859c0b82fd3f15b6484774cd0d493261fe64c78ee399bf198a8fe8d89d @@ -18364,11 +18613,11 @@ __metadata: linkType: hard "@types/supertest@npm:^2.0.12, @types/supertest@npm:^2.0.8": - version: 2.0.12 - resolution: "@types/supertest@npm:2.0.12" + version: 2.0.13 + resolution: "@types/supertest@npm:2.0.13" dependencies: "@types/superagent": "*" - checksum: f0e2b44f86bec2f708d6a3d0cb209055b487922040773049b0f8c6b557af52d4b5fa904e17dfaa4ce6e610172206bbec7b62420d158fa57b6ffc2de37b1730d3 + checksum: fe66be8e16626f254dc9d9691706942689f47a84edf7d3baaeadd6d4d576dbf915ee70cebdd7034015e83fa91fcd2dcff1cd0252514e4c510619817a183b5b4f languageName: node linkType: hard @@ -18382,11 +18631,11 @@ __metadata: linkType: hard "@types/swagger-ui-react@npm:^4.18.0": - version: 4.18.0 - resolution: "@types/swagger-ui-react@npm:4.18.0" + version: 4.18.1 + resolution: "@types/swagger-ui-react@npm:4.18.1" dependencies: "@types/react": "*" - checksum: fa946a76ece76cdbaf8d8dc2945d690787f67b29a9ed14d95b706b8a7fca2d4161a62eeda74ce81c09b872c23b788f86dab36607e891744c91f425b92e302cef + checksum: 33c5e9aeccaf6591bd8f59489f8ef50b941daf491f08ba00cb1f26140a756b00ecd6a84fcf0171cdb068134e52c3877bdac571357e12f224ae7fc5979aeedb6f languageName: node linkType: hard @@ -18505,20 +18754,20 @@ __metadata: linkType: hard "@types/webpack-env@npm:^1.15.2, @types/webpack-env@npm:^1.15.3": - version: 1.18.1 - resolution: "@types/webpack-env@npm:1.18.1" - checksum: 3173c069763e51a96565d602af7e6dac9d772ae4aa6f26cac187cbf599a7f0b88f790b4b050b9dbdb0485daed3061b4a337863f3b8ce66f8a4e51f75ad387c6a + version: 1.18.2 + resolution: "@types/webpack-env@npm:1.18.2" + checksum: 883908ade827d35a10efc574fb6f2728a7c520d4296cf1507633ac7457204ccd697bc6c8cadac99bc5d96074a6109c658ebfde59f42ba5ba0fdfffc538892b0f languageName: node linkType: hard "@types/webpack@npm:^5.28.0": - version: 5.28.2 - resolution: "@types/webpack@npm:5.28.2" + version: 5.28.3 + resolution: "@types/webpack@npm:5.28.3" dependencies: "@types/node": "*" tapable: ^2.2.0 webpack: ^5 - checksum: 0b147aaaaa8992417a5ed65af83eb0df9b5247c38ab482f3c844495935a29c474cb21bc865ca36052c353034f40d14c8d232f0c831fdc1a6956baa985d7b1135 + checksum: 8452528f7ff61eb5e53d9d1dc08c05c648af2d850e14debf49141859b72798ea2d91f2892f849d7fa97e208fef7ae82960eea24b1019cb072b4713b515e74bfc languageName: node linkType: hard @@ -18573,18 +18822,18 @@ __metadata: linkType: hard "@types/yarnpkg__lockfile@npm:^1.1.4": - version: 1.1.6 - resolution: "@types/yarnpkg__lockfile@npm:1.1.6" - checksum: c0983d88c479f7b00a66d927fda9f8972e072745d5d16922cf381807aa6e88553319bb9f2b21b58f9e1ebea1a198a22d4da3111d93c81288589371ebb00d65f5 + version: 1.1.7 + resolution: "@types/yarnpkg__lockfile@npm:1.1.7" + checksum: f7d898bfa7a75440ecc57a72d5297c9ce1566d10996004a61765bc79fa82f0c6c82df892442343e983602956f04f0943249902b9e4c09af472873382d0029b21 languageName: node linkType: hard -"@types/yauzl@npm:^2.10.0, @types/yauzl@npm:^2.9.1": - version: 2.10.0 - resolution: "@types/yauzl@npm:2.10.0" +"@types/yauzl@npm:^2.10.0": + version: 2.10.1 + resolution: "@types/yauzl@npm:2.10.1" dependencies: "@types/node": "*" - checksum: 55d27ae5d346ea260e40121675c24e112ef0247649073848e5d4e03182713ae4ec8142b98f61a1c6cbe7d3b72fa99bbadb65d8b01873e5e605cdc30f1ff70ef2 + checksum: 3377916a2d493cb2422b167fb7dfff8cb3ea045a9489dab4955858719bf7fe6808e5f6a51ee819904fb7f623f7ac092b87f9d6a857ea1214a45070d19c8b3d7e languageName: node linkType: hard @@ -18786,9 +19035,9 @@ __metadata: languageName: node linkType: hard -"@uiw/codemirror-extensions-basic-setup@npm:4.21.13": - version: 4.21.13 - resolution: "@uiw/codemirror-extensions-basic-setup@npm:4.21.13" +"@uiw/codemirror-extensions-basic-setup@npm:4.21.18": + version: 4.21.18 + resolution: "@uiw/codemirror-extensions-basic-setup@npm:4.21.18" dependencies: "@codemirror/autocomplete": ^6.0.0 "@codemirror/commands": ^6.0.0 @@ -18805,19 +19054,19 @@ __metadata: "@codemirror/search": ">=6.0.0" "@codemirror/state": ">=6.0.0" "@codemirror/view": ">=6.0.0" - checksum: 94a1ef335ed12fd1eb201e3d94892824d16a01d5a531c1962ed3b9a2d379dc3261abb4647208254a5a69763467b8a4f677ae0201fc8e67e5b60b1da9b12bae34 + checksum: c643eebc45e2067080c46e28fdb4ac40043e5890f4862bd45fe5bf816894b6c118ea901ca9ba1dce8862877622ebd793db6ec220491506355ed562a0dc0c4507 languageName: node linkType: hard "@uiw/react-codemirror@npm:^4.9.3": - version: 4.21.13 - resolution: "@uiw/react-codemirror@npm:4.21.13" + version: 4.21.18 + resolution: "@uiw/react-codemirror@npm:4.21.18" dependencies: "@babel/runtime": ^7.18.6 "@codemirror/commands": ^6.1.0 "@codemirror/state": ^6.1.1 "@codemirror/theme-one-dark": ^6.0.0 - "@uiw/codemirror-extensions-basic-setup": 4.21.13 + "@uiw/codemirror-extensions-basic-setup": 4.21.18 codemirror: ^6.0.0 peerDependencies: "@babel/runtime": ">=7.11.0" @@ -18827,7 +19076,7 @@ __metadata: codemirror: ">=6.0.0" react: ">=16.8.0" react-dom: ">=16.8.0" - checksum: 5e8dafa3837eeb4a6909f463f92ac2dd4143a5db79bf03b3d1782759940e7de6fc459ac60d9f01c9ce2e37771e83d4894e236810a788b38eebf1f312659f2764 + checksum: ef3897e9901b98fd981d4b9db2ae8702aa7ffda4cf5cab3286963580606a6dde38e77a4314c12574b6f5f251d62b62e59f0a1a445009b5927b8500f4b5fd795c languageName: node linkType: hard @@ -19548,13 +19797,6 @@ __metadata: languageName: node linkType: hard -"arch@npm:^2.2.0": - version: 2.2.0 - resolution: "arch@npm:2.2.0" - checksum: e21b7635029fe8e9cdd5a026f9a6c659103e63fff423834323cdf836a1bb240a72d0c39ca8c470f84643385cf581bd8eda2cad8bf493e27e54bd9783abe9101f - languageName: node - linkType: hard - "archiver-utils@npm:^2.1.0": version: 2.1.0 resolution: "archiver-utils@npm:2.1.0" @@ -19615,13 +19857,6 @@ __metadata: languageName: node linkType: hard -"arg@npm:^5.0.2": - version: 5.0.2 - resolution: "arg@npm:5.0.2" - checksum: 6c69ada1a9943d332d9e5382393e897c500908d91d5cb735a01120d5f71daf1b339b7b8980cbeaba8fd1afc68e658a739746179e4315a26e8a28951ff9930078 - languageName: node - linkType: hard - "argparse@npm:^1.0.10, argparse@npm:^1.0.7, argparse@npm:~1.0.9": version: 1.0.10 resolution: "argparse@npm:1.0.10" @@ -20536,14 +20771,7 @@ __metadata: languageName: node linkType: hard -"blob-util@npm:^2.0.2": - version: 2.0.2 - resolution: "blob-util@npm:2.0.2" - checksum: d543e6b92e4ca715ca33c78e89a07a2290d43e5b2bc897d7ec588c5c7bbf59df93e45225ac0c9258aa6ce4320358990f99c9288f1c48280f8ec5d7a2e088d19b - languageName: node - linkType: hard - -"bluebird@npm:3.7.2, bluebird@npm:^3.5.5, bluebird@npm:^3.7.2": +"bluebird@npm:^3.5.5, bluebird@npm:^3.7.2": version: 3.7.2 resolution: "bluebird@npm:3.7.2" checksum: 869417503c722e7dc54ca46715f70e15f4d9c602a423a02c825570862d12935be59ed9c7ba34a9b31f186c017c23cac6b54e35446f8353059c101da73eac22ef @@ -20868,7 +21096,7 @@ __metadata: languageName: node linkType: hard -"buffer@npm:^5.2.1, buffer@npm:^5.5.0, buffer@npm:^5.6.0": +"buffer@npm:^5.5.0": version: 5.7.1 resolution: "buffer@npm:5.7.1" dependencies: @@ -21033,13 +21261,6 @@ __metadata: languageName: node linkType: hard -"cachedir@npm:^2.3.0": - version: 2.3.0 - resolution: "cachedir@npm:2.3.0" - checksum: ec90cb0f2e6336e266aa748dbadf3da9e0b20e843e43f1591acab7a3f1451337dc2f26cb9dd833ae8cfefeffeeb43ef5b5ff62782a685f4e3c2305dd98482fcb - languageName: node - linkType: hard - "call-bind@npm:^1.0.0, call-bind@npm:^1.0.2": version: 1.0.2 resolution: "call-bind@npm:1.0.2" @@ -21326,13 +21547,6 @@ __metadata: languageName: node linkType: hard -"check-more-types@npm:2.24.0, check-more-types@npm:^2.24.0": - version: 2.24.0 - resolution: "check-more-types@npm:2.24.0" - checksum: b09080ec3404d20a4b0ead828994b2e5913236ef44ed3033a27062af0004cf7d2091fbde4b396bf13b7ce02fb018bc9960b48305e6ab2304cd82d73ed7a51ef4 - languageName: node - linkType: hard - "check-types@npm:^11.1.1": version: 11.1.2 resolution: "check-types@npm:11.1.2" @@ -21479,19 +21693,6 @@ __metadata: languageName: node linkType: hard -"cli-table3@npm:~0.6.1": - version: 0.6.1 - resolution: "cli-table3@npm:0.6.1" - dependencies: - colors: 1.4.0 - string-width: ^4.2.0 - dependenciesMeta: - colors: - optional: true - checksum: 956e175f8eb019c26465b9f1e51121c08d8978e2aab04be7f8520ea8a4e67906fcbd8516dfb77e386ae3730ef0281aa21a65613dffbfa3d62969263252bd25a9 - languageName: node - linkType: hard - "cli-table@npm:^0.3.1": version: 0.3.6 resolution: "cli-table@npm:0.3.6" @@ -21811,7 +22012,7 @@ __metadata: languageName: node linkType: hard -"color@npm:^4.0.1, color@npm:^4.2.3": +"color@npm:^4.0.1": version: 4.2.3 resolution: "color@npm:4.2.3" dependencies: @@ -21849,13 +22050,6 @@ __metadata: languageName: node linkType: hard -"colors@npm:1.4.0": - version: 1.4.0 - resolution: "colors@npm:1.4.0" - checksum: 98aa2c2418ad87dedf25d781be69dc5fc5908e279d9d30c34d8b702e586a0474605b3a189511482b9d5ed0d20c867515d22749537f7bc546256c6014f3ebdcec - languageName: node - linkType: hard - "colors@npm:~1.2.1": version: 1.2.5 resolution: "colors@npm:1.2.5" @@ -21980,7 +22174,7 @@ __metadata: languageName: node linkType: hard -"common-tags@npm:1.8.2, common-tags@npm:^1.8.0": +"common-tags@npm:1.8.2": version: 1.8.2 resolution: "common-tags@npm:1.8.2" checksum: 767a6255a84bbc47df49a60ab583053bb29a7d9687066a18500a516188a062c4e4cd52de341f22de0b07062e699b1b8fe3cfa1cb55b241cb9301aeb4f45b4dff @@ -22512,21 +22706,21 @@ __metadata: linkType: hard "cron@npm:^2.0.0": - version: 2.4.3 - resolution: "cron@npm:2.4.3" + version: 2.4.4 + resolution: "cron@npm:2.4.4" dependencies: "@types/luxon": ~3.3.0 luxon: ~3.3.0 - checksum: cb0ad49653b37ba125f8670ca92150ce515493512b1b8a5e08086d22bec9c54dc6d8926fcdb49ea5783f6699862ca5fdc532a440ce33c3228f9b3d565010db2f + checksum: e7dbc39c7c747b4fb198c3e62737bcc049ec8edb2b150eee17d39256982c6688f48b50b72e9b869b18feb186ab5081bcd8b82ad1ef79d9b7a13df499aaa77084 languageName: node linkType: hard -"cronstrue@npm:^2.2.0": - version: 2.31.0 - resolution: "cronstrue@npm:2.31.0" +"cronstrue@npm:^2.2.0, cronstrue@npm:^2.32.0": + version: 2.32.0 + resolution: "cronstrue@npm:2.32.0" bin: cronstrue: bin/cli.js - checksum: 8001433f65751ccd471497be14924dfecd6b91992d615ec7de1fec978792e4a3ab977d05874bea7b6a478dc786ea775554735126c79c8bbe3c94535f20ebebab + checksum: a0925e256583122792fe2f3b92cd49b954ab3e4466c7569a9148b9981db8a389faca139d4eb215142e7b67438a5562219956c56041ed0b8b046b798e72a357a8 languageName: node linkType: hard @@ -22542,15 +22736,6 @@ __metadata: languageName: node linkType: hard -"cross-fetch@npm:3.1.5": - version: 3.1.5 - resolution: "cross-fetch@npm:3.1.5" - dependencies: - node-fetch: 2.6.7 - checksum: f6b8c6ee3ef993ace6277fd789c71b6acf1b504fd5f5c7128df4ef2f125a429e29cd62dc8c127523f04a5f2fa4771ed80e3f3d9695617f441425045f505cf3bb - languageName: node - linkType: hard - "cross-fetch@npm:^3.1.3, cross-fetch@npm:^3.1.5, cross-fetch@npm:^3.1.8 <4": version: 3.1.8 resolution: "cross-fetch@npm:3.1.8" @@ -22918,55 +23103,10 @@ __metadata: languageName: node linkType: hard -"cypress@npm:^10.0.0": - version: 10.11.0 - resolution: "cypress@npm:10.11.0" - dependencies: - "@cypress/request": ^2.88.10 - "@cypress/xvfb": ^1.2.4 - "@types/node": ^14.14.31 - "@types/sinonjs__fake-timers": 8.1.1 - "@types/sizzle": ^2.3.2 - arch: ^2.2.0 - blob-util: ^2.0.2 - bluebird: ^3.7.2 - buffer: ^5.6.0 - cachedir: ^2.3.0 - chalk: ^4.1.0 - check-more-types: ^2.24.0 - cli-cursor: ^3.1.0 - cli-table3: ~0.6.1 - commander: ^5.1.0 - common-tags: ^1.8.0 - dayjs: ^1.10.4 - debug: ^4.3.2 - enquirer: ^2.3.6 - eventemitter2: 6.4.7 - execa: 4.1.0 - executable: ^4.1.1 - extract-zip: 2.0.1 - figures: ^3.2.0 - fs-extra: ^9.1.0 - getos: ^3.2.1 - is-ci: ^3.0.0 - is-installed-globally: ~0.4.0 - lazy-ass: ^1.6.0 - listr2: ^3.8.3 - lodash: ^4.17.21 - log-symbols: ^4.0.0 - minimist: ^1.2.6 - ospath: ^1.2.2 - pretty-bytes: ^5.6.0 - proxy-from-env: 1.0.0 - request-progress: ^3.0.0 - semver: ^7.3.2 - supports-color: ^8.1.1 - tmp: ~0.2.1 - untildify: ^4.0.0 - yauzl: ^2.10.0 - bin: - cypress: bin/cypress - checksum: 938cc6a20f7eeace5c8e850d234904ee1651cbb36d94666fe600cf17ce964e73d4f7d8d944aab677491702a57364e6aceeb4fe8bcbd96147ff5e2b575a956fb2 +"ctrlc-windows@npm:^2.1.0": + version: 2.1.0 + resolution: "ctrlc-windows@npm:2.1.0" + checksum: 0f0582ba9516290d3e90ea7b91710f8b9b110e1ed29b7c84ebd44c16368b2553722b86a17226120ca3ea0ef679ac3596f48104cc113cfb7c3d07260f6c92e38b languageName: node linkType: hard @@ -23218,13 +23358,6 @@ __metadata: languageName: node linkType: hard -"dayjs@npm:^1.10.4": - version: 1.10.4 - resolution: "dayjs@npm:1.10.4" - checksum: d248d6aa1e04f8577a94978e5194c1023347bc08b7c2766d4a4d50b0b69382d3f4fd912b9fcb64ffad4ee2947d53cd8e5d707f49b14817eb7810959d8d95c938 - languageName: node - linkType: hard - "debounce@npm:^1.1.0, debounce@npm:^1.2.0": version: 1.2.1 resolution: "debounce@npm:1.2.1" @@ -23253,7 +23386,7 @@ __metadata: languageName: node linkType: hard -"debug@npm:^3.1.0, debug@npm:^3.2.7": +"debug@npm:^3.2.7": version: 3.2.7 resolution: "debug@npm:3.2.7" dependencies: @@ -23546,7 +23679,7 @@ __metadata: languageName: node linkType: hard -"detect-libc@npm:^2.0.0, detect-libc@npm:^2.0.1": +"detect-libc@npm:^2.0.0": version: 2.0.1 resolution: "detect-libc@npm:2.0.1" checksum: ccb05fcabbb555beb544d48080179c18523a343face9ee4e1a86605a8715b4169f94d663c21a03c310ac824592f2ba9a5270218819bb411ad7be578a527593d7 @@ -23580,13 +23713,6 @@ __metadata: languageName: node linkType: hard -"devtools-protocol@npm:0.0.1036444": - version: 0.0.1036444 - resolution: "devtools-protocol@npm:0.0.1036444" - checksum: 6975c8def95a5e1a4207d6deb05322e335d6a37bdaa3e589cbd5bde40fbbe3ab0df2cfedb1b3ad2785401f208c150fd489a6a065a4624b56e4c0c4c1bfd89172 - languageName: node - linkType: hard - "dezalgo@npm:^1.0.0, dezalgo@npm:^1.0.4": version: 1.0.4 resolution: "dezalgo@npm:1.0.4" @@ -23908,7 +24034,7 @@ __metadata: languageName: node linkType: hard -"duplexer@npm:^0.1.2, duplexer@npm:~0.1.1": +"duplexer@npm:^0.1.2": version: 0.1.2 resolution: "duplexer@npm:0.1.2" checksum: 62ba61a830c56801db28ff6305c7d289b6dc9f859054e8c982abd8ee0b0a14d2e9a8e7d086ffee12e868d43e2bbe8a964be55ddbd8c8957714c87373c7a4f9b0 @@ -23946,7 +24072,6 @@ __metadata: mysql2: ^2.2.5 nodemon: ^3.0.1 pgtools: ^1.0.0 - puppeteer: ^17.0.0 tree-kill: ^1.2.2 ts-node: ^10.0.0 bin: @@ -24127,7 +24252,7 @@ __metadata: languageName: node linkType: hard -"enquirer@npm:^2.3.0, enquirer@npm:^2.3.6": +"enquirer@npm:^2.3.0": version: 2.3.6 resolution: "enquirer@npm:2.3.6" dependencies: @@ -24606,31 +24731,31 @@ __metadata: linkType: hard "esbuild@npm:^0.19.0": - version: 0.19.3 - resolution: "esbuild@npm:0.19.3" + version: 0.19.4 + resolution: "esbuild@npm:0.19.4" dependencies: - "@esbuild/android-arm": 0.19.3 - "@esbuild/android-arm64": 0.19.3 - "@esbuild/android-x64": 0.19.3 - "@esbuild/darwin-arm64": 0.19.3 - "@esbuild/darwin-x64": 0.19.3 - "@esbuild/freebsd-arm64": 0.19.3 - "@esbuild/freebsd-x64": 0.19.3 - "@esbuild/linux-arm": 0.19.3 - "@esbuild/linux-arm64": 0.19.3 - "@esbuild/linux-ia32": 0.19.3 - "@esbuild/linux-loong64": 0.19.3 - "@esbuild/linux-mips64el": 0.19.3 - "@esbuild/linux-ppc64": 0.19.3 - "@esbuild/linux-riscv64": 0.19.3 - "@esbuild/linux-s390x": 0.19.3 - "@esbuild/linux-x64": 0.19.3 - "@esbuild/netbsd-x64": 0.19.3 - "@esbuild/openbsd-x64": 0.19.3 - "@esbuild/sunos-x64": 0.19.3 - "@esbuild/win32-arm64": 0.19.3 - "@esbuild/win32-ia32": 0.19.3 - "@esbuild/win32-x64": 0.19.3 + "@esbuild/android-arm": 0.19.4 + "@esbuild/android-arm64": 0.19.4 + "@esbuild/android-x64": 0.19.4 + "@esbuild/darwin-arm64": 0.19.4 + "@esbuild/darwin-x64": 0.19.4 + "@esbuild/freebsd-arm64": 0.19.4 + "@esbuild/freebsd-x64": 0.19.4 + "@esbuild/linux-arm": 0.19.4 + "@esbuild/linux-arm64": 0.19.4 + "@esbuild/linux-ia32": 0.19.4 + "@esbuild/linux-loong64": 0.19.4 + "@esbuild/linux-mips64el": 0.19.4 + "@esbuild/linux-ppc64": 0.19.4 + "@esbuild/linux-riscv64": 0.19.4 + "@esbuild/linux-s390x": 0.19.4 + "@esbuild/linux-x64": 0.19.4 + "@esbuild/netbsd-x64": 0.19.4 + "@esbuild/openbsd-x64": 0.19.4 + "@esbuild/sunos-x64": 0.19.4 + "@esbuild/win32-arm64": 0.19.4 + "@esbuild/win32-ia32": 0.19.4 + "@esbuild/win32-x64": 0.19.4 dependenciesMeta: "@esbuild/android-arm": optional: true @@ -24678,7 +24803,7 @@ __metadata: optional: true bin: esbuild: bin/esbuild - checksum: f998ba82b1bbf0f3036201dc2cb94f92aff887b7552738ea3e4dd6f386f87740ef76aabae2fc1c4b91a519354d390f6d9fd89eb71e26882983f6fbaf75369206 + checksum: 024309a16365b020815a30e9a3a9354894a391cf1adbfad7f44a975cf161ab5e961619b30e1ec8ea02994631d71e6b38831119be69f8ccb610c32bbe21addc79 languageName: node linkType: hard @@ -24886,17 +25011,6 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-cypress@npm:^2.10.3": - version: 2.14.0 - resolution: "eslint-plugin-cypress@npm:2.14.0" - dependencies: - globals: ^13.20.0 - peerDependencies: - eslint: ">= 3.2.1" - checksum: 3fa118a757aebb1aa6b419b2944744796aa4fa3cc1e2e19fa97777fd6792fba12b5ae117bf19bf7e7d9a1abdd48398cfba9ca6f2c62fd690a2108a9a02f3f2ae - languageName: node - linkType: hard - "eslint-plugin-deprecation@npm:^1.3.2": version: 1.5.0 resolution: "eslint-plugin-deprecation@npm:1.5.0" @@ -25258,21 +25372,6 @@ __metadata: languageName: node linkType: hard -"event-stream@npm:=3.3.4": - version: 3.3.4 - resolution: "event-stream@npm:3.3.4" - dependencies: - duplexer: ~0.1.1 - from: ~0 - map-stream: ~0.1.0 - pause-stream: 0.0.11 - split: 0.3 - stream-combiner: ~0.0.4 - through: ~2.3.1 - checksum: 80b467820b6daf824d9fb4345d2daf115a056e5c104463f2e98534e92d196a27f2df5ea2aa085624db26f4c45698905499e881d13bc7c01f7a13eac85be72a22 - languageName: node - linkType: hard - "event-target-polyfill@npm:^0.0.3": version: 0.0.3 resolution: "event-target-polyfill@npm:0.0.3" @@ -25287,7 +25386,7 @@ __metadata: languageName: node linkType: hard -"eventemitter2@npm:6.4.7, eventemitter2@npm:^6.4.4": +"eventemitter2@npm:^6.4.4": version: 6.4.7 resolution: "eventemitter2@npm:6.4.7" checksum: 1b36a77e139d6965ebf3a36c01fa00c089ae6b80faa1911e52888f40b3a7057b36a2cc45dcd1ad87cda3798fe7b97a0aabcbb8175a8b96092a23bb7d0f039e66 @@ -25354,6 +25453,7 @@ __metadata: "@backstage/plugin-azure-devops": "workspace:^" "@backstage/plugin-azure-sites": "workspace:^" "@backstage/plugin-badges": "workspace:^" + "@backstage/plugin-catalog": "workspace:^" "@backstage/plugin-catalog-common": "workspace:^" "@backstage/plugin-catalog-graph": "workspace:^" "@backstage/plugin-catalog-import": "workspace:^" @@ -25407,7 +25507,6 @@ __metadata: "@backstage/plugin-user-settings": "workspace:^" "@backstage/test-utils": "workspace:^" "@backstage/theme": "workspace:^" - "@internal/plugin-catalog-customized": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 "@material-ui/lab": 4.0.0-alpha.61 @@ -25417,7 +25516,6 @@ __metadata: "@roadiehq/backstage-plugin-github-insights": ^2.0.5 "@roadiehq/backstage-plugin-github-pull-requests": ^2.2.7 "@roadiehq/backstage-plugin-travis-ci": ^2.0.5 - "@testing-library/cypress": ^9.0.0 "@testing-library/dom": ^8.0.0 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 @@ -25428,8 +25526,6 @@ __metadata: "@types/zen-observable": ^0.8.0 app-next-example-plugin: "workspace:^" cross-env: ^7.0.0 - cypress: ^10.0.0 - eslint-plugin-cypress: ^2.10.3 history: ^5.0.0 lodash: ^4.17.21 prop-types: ^15.7.2 @@ -25438,7 +25534,6 @@ __metadata: react-router: ^6.3.0 react-router-dom: ^6.3.0 react-use: ^17.2.4 - start-server-and-test: ^1.10.11 zen-observable: ^0.10.0 languageName: unknown linkType: soft @@ -25469,6 +25564,7 @@ __metadata: "@backstage/plugin-azure-devops": "workspace:^" "@backstage/plugin-azure-sites": "workspace:^" "@backstage/plugin-badges": "workspace:^" + "@backstage/plugin-catalog": "workspace:^" "@backstage/plugin-catalog-common": "workspace:^" "@backstage/plugin-catalog-graph": "workspace:^" "@backstage/plugin-catalog-import": "workspace:^" @@ -25491,6 +25587,7 @@ __metadata: "@backstage/plugin-jenkins": "workspace:^" "@backstage/plugin-kafka": "workspace:^" "@backstage/plugin-kubernetes": "workspace:^" + "@backstage/plugin-kubernetes-cluster": "workspace:^" "@backstage/plugin-lighthouse": "workspace:^" "@backstage/plugin-linguist": "workspace:^" "@backstage/plugin-linguist-common": "workspace:^" @@ -25523,17 +25620,16 @@ __metadata: "@backstage/plugin-user-settings": "workspace:^" "@backstage/test-utils": "workspace:^" "@backstage/theme": "workspace:^" - "@internal/plugin-catalog-customized": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 "@material-ui/lab": 4.0.0-alpha.61 "@octokit/rest": ^19.0.3 "@oriflame/backstage-plugin-score-card": ^0.7.0 + "@playwright/test": ^1.32.3 "@roadiehq/backstage-plugin-buildkite": ^2.0.8 "@roadiehq/backstage-plugin-github-insights": ^2.0.5 "@roadiehq/backstage-plugin-github-pull-requests": ^2.2.7 "@roadiehq/backstage-plugin-travis-ci": ^2.0.5 - "@testing-library/cypress": ^9.0.0 "@testing-library/dom": ^8.0.0 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 @@ -25543,8 +25639,6 @@ __metadata: "@types/react-dom": "*" "@types/zen-observable": ^0.8.0 cross-env: ^7.0.0 - cypress: ^10.0.0 - eslint-plugin-cypress: ^2.10.3 history: ^5.0.0 prop-types: ^15.7.2 react: ^17.0.2 @@ -25552,7 +25646,6 @@ __metadata: react-router: ^6.3.0 react-router-dom: ^6.3.0 react-use: ^17.2.4 - start-server-and-test: ^1.10.11 zen-observable: ^0.10.0 languageName: unknown linkType: soft @@ -25578,10 +25671,12 @@ __metadata: "@backstage/plugin-kubernetes-backend": "workspace:^" "@backstage/plugin-lighthouse-backend": "workspace:^" "@backstage/plugin-linguist-backend": "workspace:^" + "@backstage/plugin-nomad-backend": "workspace:^" "@backstage/plugin-permission-backend": "workspace:^" "@backstage/plugin-permission-backend-module-allow-all-policy": "workspace:^" "@backstage/plugin-permission-common": "workspace:^" "@backstage/plugin-permission-node": "workspace:^" + "@backstage/plugin-playlist-backend": "workspace:^" "@backstage/plugin-proxy-backend": "workspace:^" "@backstage/plugin-scaffolder-backend": "workspace:^" "@backstage/plugin-search-backend": "workspace:^" @@ -25589,6 +25684,7 @@ __metadata: "@backstage/plugin-search-backend-module-explore": "workspace:^" "@backstage/plugin-search-backend-module-techdocs": "workspace:^" "@backstage/plugin-search-backend-node": "workspace:^" + "@backstage/plugin-sonarqube-backend": "workspace:^" "@backstage/plugin-techdocs-backend": "workspace:^" "@backstage/plugin-todo-backend": "workspace:^" languageName: unknown @@ -25676,40 +25772,6 @@ __metadata: languageName: unknown linkType: soft -"execa@npm:4.1.0": - version: 4.1.0 - resolution: "execa@npm:4.1.0" - dependencies: - cross-spawn: ^7.0.0 - get-stream: ^5.0.0 - human-signals: ^1.1.1 - is-stream: ^2.0.0 - merge-stream: ^2.0.0 - npm-run-path: ^4.0.0 - onetime: ^5.1.0 - signal-exit: ^3.0.2 - strip-final-newline: ^2.0.0 - checksum: e30d298934d9c52f90f3847704fd8224e849a081ab2b517bbc02f5f7732c24e56a21f14cb96a08256deffeb2d12b2b7cb7e2b014a12fb36f8d3357e06417ed55 - languageName: node - linkType: hard - -"execa@npm:5.1.1, execa@npm:^5.0.0": - version: 5.1.1 - resolution: "execa@npm:5.1.1" - dependencies: - cross-spawn: ^7.0.3 - get-stream: ^6.0.0 - human-signals: ^2.1.0 - is-stream: ^2.0.0 - merge-stream: ^2.0.0 - npm-run-path: ^4.0.1 - onetime: ^5.1.2 - signal-exit: ^3.0.3 - strip-final-newline: ^2.0.0 - checksum: fba9022c8c8c15ed862847e94c252b3d946036d7547af310e344a527e59021fd8b6bb0723883ea87044dc4f0201f949046993124a42ccb0855cae5bf8c786343 - languageName: node - linkType: hard - "execa@npm:7.2.0": version: 7.2.0 resolution: "execa@npm:7.2.0" @@ -25727,12 +25789,20 @@ __metadata: languageName: node linkType: hard -"executable@npm:^4.1.1": - version: 4.1.1 - resolution: "executable@npm:4.1.1" +"execa@npm:^5.0.0": + version: 5.1.1 + resolution: "execa@npm:5.1.1" dependencies: - pify: ^2.2.0 - checksum: f01927ce59bccec804e171bf859a26e362c1f50aa9ebc69f7cafdcce3859d29d4b6267fd47237c18b0a1830614bd3f0ee14b7380d9bad18a4e7af9b5f0b6984f + cross-spawn: ^7.0.3 + get-stream: ^6.0.0 + human-signals: ^2.1.0 + is-stream: ^2.0.0 + merge-stream: ^2.0.0 + npm-run-path: ^4.0.1 + onetime: ^5.1.2 + signal-exit: ^3.0.3 + strip-final-newline: ^2.0.0 + checksum: fba9022c8c8c15ed862847e94c252b3d946036d7547af310e344a527e59021fd8b6bb0723883ea87044dc4f0201f949046993124a42ccb0855cae5bf8c786343 languageName: node linkType: hard @@ -25936,23 +26006,6 @@ __metadata: languageName: node linkType: hard -"extract-zip@npm:2.0.1": - version: 2.0.1 - resolution: "extract-zip@npm:2.0.1" - dependencies: - "@types/yauzl": ^2.9.1 - debug: ^4.1.1 - get-stream: ^5.1.0 - yauzl: ^2.10.0 - dependenciesMeta: - "@types/yauzl": - optional: true - bin: - extract-zip: cli.js - checksum: 8cbda9debdd6d6980819cc69734d874ddd71051c9fe5bde1ef307ebcedfe949ba57b004894b585f758b7c9eeeea0e3d87f2dda89b7d25320459c2c9643ebb635 - languageName: node - linkType: hard - "extsprintf@npm:1.3.0": version: 1.3.0 resolution: "extsprintf@npm:1.3.0" @@ -26223,7 +26276,7 @@ __metadata: languageName: node linkType: hard -"figures@npm:^3.0.0, figures@npm:^3.2.0": +"figures@npm:^3.0.0": version: 3.2.0 resolution: "figures@npm:3.2.0" dependencies: @@ -26661,13 +26714,6 @@ __metadata: languageName: node linkType: hard -"from@npm:~0": - version: 0.1.7 - resolution: "from@npm:0.1.7" - checksum: b85125b7890489656eb2e4f208f7654a93ec26e3aefaf3bbbcc0d496fc1941e4405834fcc9fe7333192aa2187905510ace70417bbf9ac6f6f4784a731d986939 - languageName: node - linkType: hard - "fromentries@npm:^1.3.1": version: 1.3.2 resolution: "fromentries@npm:1.3.2" @@ -26691,7 +26737,7 @@ __metadata: languageName: node linkType: hard -"fs-extra@npm:10.1.0, fs-extra@npm:^10.0.0, fs-extra@npm:^10.0.1": +"fs-extra@npm:10.1.0, fs-extra@npm:^10.0.0, fs-extra@npm:^10.0.1, fs-extra@npm:^10.1.0": version: 10.1.0 resolution: "fs-extra@npm:10.1.0" dependencies: @@ -26724,7 +26770,7 @@ __metadata: languageName: node linkType: hard -"fs-extra@npm:^9.0.0, fs-extra@npm:^9.1.0": +"fs-extra@npm:^9.0.0": version: 9.1.0 resolution: "fs-extra@npm:9.1.0" dependencies: @@ -26768,7 +26814,7 @@ __metadata: languageName: node linkType: hard -"fsevents@npm:^2.3.2, fsevents@npm:~2.3.2": +"fsevents@npm:2.3.2, fsevents@npm:^2.3.2, fsevents@npm:~2.3.2": version: 2.3.2 resolution: "fsevents@npm:2.3.2" dependencies: @@ -26778,7 +26824,7 @@ __metadata: languageName: node linkType: hard -"fsevents@patch:fsevents@^2.3.2#~builtin<compat/fsevents>, fsevents@patch:fsevents@~2.3.2#~builtin<compat/fsevents>": +"fsevents@patch:fsevents@2.3.2#~builtin<compat/fsevents>, fsevents@patch:fsevents@^2.3.2#~builtin<compat/fsevents>, fsevents@patch:fsevents@~2.3.2#~builtin<compat/fsevents>": version: 2.3.2 resolution: "fsevents@patch:fsevents@npm%3A2.3.2#~builtin<compat/fsevents>::version=2.3.2&hash=18f3a7" dependencies: @@ -26951,7 +26997,7 @@ __metadata: languageName: node linkType: hard -"get-stream@npm:^5.0.0, get-stream@npm:^5.1.0": +"get-stream@npm:^5.1.0": version: 5.1.0 resolution: "get-stream@npm:5.1.0" dependencies: @@ -26991,15 +27037,6 @@ __metadata: languageName: node linkType: hard -"getos@npm:^3.2.1": - version: 3.2.1 - resolution: "getos@npm:3.2.1" - dependencies: - async: ^3.2.0 - checksum: 42fd78a66d47cebd3e09de5566cc0044e034b08f4a000a310dbd89a77b02c65d8f4002554bfa495ea5bdc4fa9d515f5ac785a7cc474ba45383cc697f865eeaf1 - languageName: node - linkType: hard - "getpass@npm:^0.1.1": version: 0.1.7 resolution: "getpass@npm:0.1.7" @@ -27074,19 +27111,6 @@ __metadata: languageName: node linkType: hard -"glob@npm:8.1.0, glob@npm:^8.0.0, glob@npm:^8.0.1, glob@npm:^8.0.3": - version: 8.1.0 - resolution: "glob@npm:8.1.0" - dependencies: - fs.realpath: ^1.0.0 - inflight: ^1.0.4 - inherits: 2 - minimatch: ^5.0.1 - once: ^1.3.0 - checksum: 92fbea3221a7d12075f26f0227abac435de868dd0736a17170663783296d0dd8d3d532a5672b4488a439bf5d7fb85cdd07c11185d6cd39184f0385cbdfb86a47 - languageName: node - linkType: hard - "glob@npm:^10.2.2": version: 10.2.7 resolution: "glob@npm:10.2.7" @@ -27116,6 +27140,19 @@ __metadata: languageName: node linkType: hard +"glob@npm:^8.0.0, glob@npm:^8.0.1, glob@npm:^8.0.3": + version: 8.1.0 + resolution: "glob@npm:8.1.0" + dependencies: + fs.realpath: ^1.0.0 + inflight: ^1.0.4 + inherits: 2 + minimatch: ^5.0.1 + once: ^1.3.0 + checksum: 92fbea3221a7d12075f26f0227abac435de868dd0736a17170663783296d0dd8d3d532a5672b4488a439bf5d7fb85cdd07c11185d6cd39184f0385cbdfb86a47 + languageName: node + linkType: hard + "global-agent@npm:^3.0.0": version: 3.0.0 resolution: "global-agent@npm:3.0.0" @@ -27130,15 +27167,6 @@ __metadata: languageName: node linkType: hard -"global-dirs@npm:^3.0.0": - version: 3.0.0 - resolution: "global-dirs@npm:3.0.0" - dependencies: - ini: 2.0.0 - checksum: 953c17cf14bf6ee0e2100ae82a0d779934eed8a3ec5c94a7a4f37c5b3b592c31ea015fb9a15cf32484de13c79f4a814f3015152f3e1d65976cfbe47c1bfe4a88 - languageName: node - linkType: hard - "global-modules@npm:^2.0.0": version: 2.0.0 resolution: "global-modules@npm:2.0.0" @@ -27166,7 +27194,7 @@ __metadata: languageName: node linkType: hard -"globals@npm:^13.19.0, globals@npm:^13.20.0": +"globals@npm:^13.19.0": version: 13.20.0 resolution: "globals@npm:13.20.0" dependencies: @@ -27474,18 +27502,18 @@ __metadata: linkType: hard "graphql-ws@npm:^5.4.1, graphql-ws@npm:^5.9.0": - version: 5.14.0 - resolution: "graphql-ws@npm:5.14.0" + version: 5.14.1 + resolution: "graphql-ws@npm:5.14.1" peerDependencies: graphql: ">=0.11 <=16" - checksum: 7b622944823fa12a77ea490656121a77e1a1daf08114a6a0b027922113f4481d95f4fe380a5de369a51657ef777d35757dc31f63e41071c21f3e97ca47e4205a + checksum: bf6aa9446496f11e74d5fea17672050fb02f0303c6a7bf1e2692b7ea88059a18837f437e2ec8ba3cf7bb5bc2a18dddeebe9a8c6e6036914c3776297c48c1a398 languageName: node linkType: hard -"graphql@npm:^15.0.0 || ^16.0.0, graphql@npm:^16.0.0": - version: 16.8.0 - resolution: "graphql@npm:16.8.0" - checksum: d853d4085b0c911a7e2a926c3b0d379934ec61cd4329e70cdf281763102f024fd80a97db7a505b8b04fed9050cb4875f8f518150ea854557a500a0b41dcd7f4e +"graphql@npm:^16.0.0, graphql@npm:^16.8.1": + version: 16.8.1 + resolution: "graphql@npm:16.8.1" + checksum: 8d304b7b6f708c8c5cc164b06e92467dfe36aff6d4f2cf31dd19c4c2905a0e7b89edac4b7e225871131fd24e21460836b369de0c06532644d15b461d55b1ccc0 languageName: node linkType: hard @@ -28047,17 +28075,6 @@ __metadata: languageName: node linkType: hard -"http-signature@npm:~1.3.6": - version: 1.3.6 - resolution: "http-signature@npm:1.3.6" - dependencies: - assert-plus: ^1.0.0 - jsprim: ^2.0.2 - sshpk: ^1.14.1 - checksum: 10be2af4764e71fee0281392937050201ee576ac755c543f570d6d87134ce5e858663fe999a7adb3e4e368e1e356d0d7fec6b9542295b875726ff615188e7a0c - languageName: node - linkType: hard - "http2-wrapper@npm:^1.0.0-beta.5.2": version: 1.0.0-beta.5.2 resolution: "http2-wrapper@npm:1.0.0-beta.5.2" @@ -28075,7 +28092,7 @@ __metadata: languageName: node linkType: hard -"https-proxy-agent@npm:5.0.1, https-proxy-agent@npm:^5.0.0, https-proxy-agent@npm:^5.0.1": +"https-proxy-agent@npm:^5.0.0, https-proxy-agent@npm:^5.0.1": version: 5.0.1 resolution: "https-proxy-agent@npm:5.0.1" dependencies: @@ -28092,13 +28109,6 @@ __metadata: languageName: node linkType: hard -"human-signals@npm:^1.1.1": - version: 1.1.1 - resolution: "human-signals@npm:1.1.1" - checksum: d587647c9e8ec24e02821b6be7de5a0fc37f591f6c4e319b3054b43fd4c35a70a94c46fc74d8c1a43c47fde157d23acd7421f375e1c1365b09a16835b8300205 - languageName: node - linkType: hard - "human-signals@npm:^2.1.0": version: 2.1.0 resolution: "human-signals@npm:2.1.0" @@ -28393,13 +28403,6 @@ __metadata: languageName: node linkType: hard -"ini@npm:2.0.0": - version: 2.0.0 - resolution: "ini@npm:2.0.0" - checksum: e7aadc5fb2e4aefc666d74ee2160c073995a4061556b1b5b4241ecb19ad609243b9cceafe91bae49c219519394bbd31512516cb22a3b1ca6e66d869e0447e84e - languageName: node - linkType: hard - "ini@npm:^1.3.5, ini@npm:~1.3.0": version: 1.3.8 resolution: "ini@npm:1.3.8" @@ -28704,7 +28707,7 @@ __metadata: languageName: node linkType: hard -"is-ci@npm:^3.0.0, is-ci@npm:^3.0.1": +"is-ci@npm:^3.0.1": version: 3.0.1 resolution: "is-ci@npm:3.0.1" dependencies: @@ -28832,16 +28835,6 @@ __metadata: languageName: node linkType: hard -"is-installed-globally@npm:~0.4.0": - version: 0.4.0 - resolution: "is-installed-globally@npm:0.4.0" - dependencies: - global-dirs: ^3.0.0 - is-path-inside: ^3.0.2 - checksum: 3359840d5982d22e9b350034237b2cda2a12bac1b48a721912e1ab8e0631dd07d45a2797a120b7b87552759a65ba03e819f1bd63f2d7ab8657ec0b44ee0bf399 - languageName: node - linkType: hard - "is-interactive@npm:^1.0.0": version: 1.0.0 resolution: "is-interactive@npm:1.0.0" @@ -28933,7 +28926,7 @@ __metadata: languageName: node linkType: hard -"is-path-inside@npm:^3.0.2, is-path-inside@npm:^3.0.3": +"is-path-inside@npm:^3.0.3": version: 3.0.3 resolution: "is-path-inside@npm:3.0.3" checksum: abd50f06186a052b349c15e55b182326f1936c89a78bf6c8f2b707412517c097ce04bc49a0ca221787bc44e1049f51f09a2ffb63d22899051988d3a618ba13e9 @@ -29697,7 +29690,7 @@ __metadata: languageName: node linkType: hard -"jest-haste-map@npm:^29.4.3": +"jest-haste-map@npm:29.4.3": version: 29.4.3 resolution: "jest-haste-map@npm:29.4.3" dependencies: @@ -29720,6 +29713,29 @@ __metadata: languageName: node linkType: hard +"jest-haste-map@patch:jest-haste-map@npm%3A29.4.3#./.yarn/patches/jest-haste-map-npm-29.4.3-19b03fcef3.patch::locator=root%40workspace%3A.": + version: 29.4.3 + resolution: "jest-haste-map@patch:jest-haste-map@npm%3A29.4.3#./.yarn/patches/jest-haste-map-npm-29.4.3-19b03fcef3.patch::version=29.4.3&hash=1e431f&locator=root%40workspace%3A." + dependencies: + "@jest/types": ^29.4.3 + "@types/graceful-fs": ^4.1.3 + "@types/node": "*" + anymatch: ^3.0.3 + fb-watchman: ^2.0.0 + fsevents: ^2.3.2 + graceful-fs: ^4.2.9 + jest-regex-util: ^29.4.3 + jest-util: ^29.4.3 + jest-worker: ^29.4.3 + micromatch: ^4.0.4 + walker: ^1.0.8 + dependenciesMeta: + fsevents: + optional: true + checksum: a25fd71cc650acac4295172b2b84212872c4100a0b8e627e1f4b70a7e74d895a20274a4b0449aafdcb8273da055013fdc8765e55cbcf6dc46ae0351e974ed0c2 + languageName: node + linkType: hard + "jest-leak-detector@npm:^29.4.3": version: 29.4.3 resolution: "jest-leak-detector@npm:29.4.3" @@ -29994,7 +30010,7 @@ __metadata: languageName: node linkType: hard -"jest-websocket-mock@npm:^2.4.1": +"jest-websocket-mock@npm:^2.4.1, jest-websocket-mock@npm:^2.5.0": version: 2.5.0 resolution: "jest-websocket-mock@npm:2.5.0" dependencies: @@ -30098,19 +30114,6 @@ __metadata: languageName: node linkType: hard -"joi@npm:^17.7.0": - version: 17.7.0 - resolution: "joi@npm:17.7.0" - dependencies: - "@hapi/hoek": ^9.0.0 - "@hapi/topo": ^5.0.0 - "@sideway/address": ^4.1.3 - "@sideway/formula": ^3.0.0 - "@sideway/pinpoint": ^2.0.0 - checksum: 767a847936cb66787256c4351ff86e1b9e8d7383cbe81a5c827064032c2a8e8b6e938baef5ad32c4035fe4c56e537bd90aa2a952be8a0658601c920cdeb4fb3c - languageName: node - linkType: hard - "jose@npm:^4.14.4, jose@npm:^4.6.0": version: 4.14.6 resolution: "jose@npm:4.14.6" @@ -30706,18 +30709,6 @@ __metadata: languageName: node linkType: hard -"jsprim@npm:^2.0.2": - version: 2.0.2 - resolution: "jsprim@npm:2.0.2" - dependencies: - assert-plus: 1.0.0 - extsprintf: 1.3.0 - json-schema: 0.4.0 - verror: 1.10.0 - checksum: d175f6b1991e160cb0aa39bc857da780e035611986b5492f32395411879fdaf4e513d98677f08f7352dac93a16b66b8361c674b86a3fa406e2e7af6b26321838 - languageName: node - linkType: hard - "jss-camel-case@npm:^6.0.0": version: 6.1.0 resolution: "jss-camel-case@npm:6.1.0" @@ -31073,7 +31064,7 @@ __metadata: languageName: node linkType: hard -"kubernetes-models@npm:^4.1.0": +"kubernetes-models@npm:^4.1.0, kubernetes-models@npm:^4.3.1": version: 4.3.1 resolution: "kubernetes-models@npm:4.3.1" dependencies: @@ -31125,13 +31116,6 @@ __metadata: languageName: node linkType: hard -"lazy-ass@npm:1.6.0, lazy-ass@npm:^1.6.0": - version: 1.6.0 - resolution: "lazy-ass@npm:1.6.0" - checksum: 5a3ebb17915b03452320804466345382a6c25ac782ec4874fecdb2385793896cd459be2f187dc7def8899180c32ee0ab9a1aa7fe52193ac3ff3fe29bb0591729 - languageName: node - linkType: hard - "lazystream@npm:^1.0.0": version: 1.0.0 resolution: "lazystream@npm:1.0.0" @@ -31352,27 +31336,6 @@ __metadata: languageName: node linkType: hard -"listr2@npm:^3.8.3": - version: 3.14.0 - resolution: "listr2@npm:3.14.0" - dependencies: - cli-truncate: ^2.1.0 - colorette: ^2.0.16 - log-update: ^4.0.0 - p-map: ^4.0.0 - rfdc: ^1.3.0 - rxjs: ^7.5.1 - through: ^2.3.8 - wrap-ansi: ^7.0.0 - peerDependencies: - enquirer: ">= 2.3.0 < 3" - peerDependenciesMeta: - enquirer: - optional: true - checksum: fdb8b2d6bdf5df9371ebd5082bee46c6d0ca3d1e5f2b11fbb5a127839855d5f3da9d4968fce94f0a5ec67cac2459766abbb1faeef621065ebb1829b11ef9476d - languageName: node - linkType: hard - "listr2@npm:^4.0.5": version: 4.0.5 resolution: "listr2@npm:4.0.5" @@ -31645,13 +31608,6 @@ __metadata: languageName: node linkType: hard -"lodash.once@npm:^4.1.1": - version: 4.1.1 - resolution: "lodash.once@npm:4.1.1" - checksum: d768fa9f9b4e1dc6453be99b753906f58990e0c45e7b2ca5a3b40a33111e5d17f6edf2f768786e2716af90a8e78f8f91431ab8435f761fef00f9b0c256f6d245 - languageName: node - linkType: hard - "lodash.sortby@npm:^4.7.0": version: 4.7.0 resolution: "lodash.sortby@npm:4.7.0" @@ -31880,7 +31836,7 @@ __metadata: languageName: node linkType: hard -"luxon@npm:^3.0.0, luxon@npm:^3.3.0": +"luxon@npm:^3.0.0, luxon@npm:^3.3.0, luxon@npm:^3.4.3": version: 3.4.3 resolution: "luxon@npm:3.4.3" checksum: 3eade81506224d038ed24035a0cd0dd4887848d7eba9361dce9ad8ef81380596a68153240be3988721f9690c624fb449fcf8fd8c3fc0681a6a8496faf48e92a3 @@ -32057,13 +32013,6 @@ __metadata: languageName: node linkType: hard -"map-stream@npm:~0.1.0": - version: 0.1.0 - resolution: "map-stream@npm:0.1.0" - checksum: 38abbe4eb883888031e6b2fc0630bc583c99396be16b8ace5794b937b682a8a081f03e8b15bfd4914d1bc88318f0e9ac73ba3512ae65955cd449f63256ddb31d - languageName: node - linkType: hard - "markdown-it-anchor@npm:^8.4.1": version: 8.6.4 resolution: "markdown-it-anchor@npm:8.6.4" @@ -32449,13 +32398,6 @@ __metadata: languageName: node linkType: hard -"meta-png@npm:1.0.6": - version: 1.0.6 - resolution: "meta-png@npm:1.0.6" - checksum: aed14b3b53189c9d32002d76c40926bd93dd9d439bae3ad23ffb2645c375c9772c160879aa8af59ac85a2f43ae8bbe06b9648a53fe27815f4aeab238f4e9b79d - languageName: node - linkType: hard - "methods@npm:^1.0.0, methods@npm:^1.1.2, methods@npm:~1.1.2": version: 1.1.2 resolution: "methods@npm:1.1.2" @@ -33004,7 +32946,7 @@ __metadata: languageName: node linkType: hard -"minimist@npm:>=1.2.2, minimist@npm:^1.2.0, minimist@npm:^1.2.3, minimist@npm:^1.2.5, minimist@npm:^1.2.6, minimist@npm:^1.2.7": +"minimist@npm:>=1.2.2, minimist@npm:^1.2.0, minimist@npm:^1.2.3, minimist@npm:^1.2.5, minimist@npm:^1.2.6": version: 1.2.8 resolution: "minimist@npm:1.2.8" checksum: 75a6d645fb122dad29c06a7597bddea977258957ed88d7a6df59b5cd3fe4a527e253e9bbf2e783e4b73657f9098b96a5fe96ab8a113655d4109108577ecf85b0 @@ -33253,15 +33195,6 @@ __metadata: languageName: node linkType: hard -"move-file@npm:2.1.0": - version: 2.1.0 - resolution: "move-file@npm:2.1.0" - dependencies: - path-exists: ^4.0.0 - checksum: 2b92bbe047a302b593fcb2c0bf1131bb090ec80b3264569fc80d782c8ff829eecc13573943fa4d804c9747dec612ef2d1e84a5cfcf29cbc64a69ffcbb7ea09b3 - languageName: node - linkType: hard - "mri@npm:1.1.4": version: 1.1.4 resolution: "mri@npm:1.1.4" @@ -33297,9 +33230,9 @@ __metadata: languageName: node linkType: hard -"msw@npm:^1.0.0, msw@npm:^1.0.1, msw@npm:^1.2.1, msw@npm:^1.2.3": - version: 1.3.1 - resolution: "msw@npm:1.3.1" +"msw@npm:^1.0.0, msw@npm:^1.0.1, msw@npm:^1.2.1, msw@npm:^1.2.3, msw@npm:^1.3.1": + version: 1.3.2 + resolution: "msw@npm:1.3.2" dependencies: "@mswjs/cookies": ^0.2.2 "@mswjs/interceptors": ^0.17.10 @@ -33309,7 +33242,7 @@ __metadata: chalk: ^4.1.1 chokidar: ^3.4.2 cookie: ^0.4.2 - graphql: ^15.0.0 || ^16.0.0 + graphql: ^16.8.1 headers-polyfill: 3.2.5 inquirer: ^8.2.0 is-node-process: ^1.2.0 @@ -33327,7 +33260,7 @@ __metadata: optional: true bin: msw: cli/index.js - checksum: 5e3c9d2efff025ecaa55c48b0392179fb07253f26212fe884cca7cc4b5d62cebbfa937dc7249a91d432b1f64ebcce2a1e4938056264f277da62d62d072dfb883 + checksum: c2d4f7747f5806f0fd8d8cc3ca250ee1c2a7a6cd608de43f95bd072ba1fb13cdce0b52932ce9bf8f4a21b194d2815db535501e224ec8f7052593447fe1c0cb70 languageName: node linkType: hard @@ -33592,15 +33525,6 @@ __metadata: languageName: node linkType: hard -"node-addon-api@npm:^6.1.0": - version: 6.1.0 - resolution: "node-addon-api@npm:6.1.0" - dependencies: - node-gyp: latest - checksum: 3a539510e677cfa3a833aca5397300e36141aca064cdc487554f2017110709a03a95da937e98c2a14ec3c626af7b2d1b6dabe629a481f9883143d0d5bff07bf2 - languageName: node - linkType: hard - "node-cache@npm:^5.1.2": version: 5.1.2 resolution: "node-cache@npm:5.1.2" @@ -33626,20 +33550,6 @@ __metadata: languageName: node linkType: hard -"node-fetch@npm:2.6.7": - version: 2.6.7 - resolution: "node-fetch@npm:2.6.7" - dependencies: - whatwg-url: ^5.0.0 - peerDependencies: - encoding: ^0.1.0 - peerDependenciesMeta: - encoding: - optional: true - checksum: 8d816ffd1ee22cab8301c7756ef04f3437f18dace86a1dae22cf81db8ef29c0bf6655f3215cb0cdb22b420b6fe141e64b26905e7f33f9377a7fa59135ea3e10b - languageName: node - linkType: hard - "node-fetch@npm:^1.0.1": version: 1.7.3 resolution: "node-fetch@npm:1.7.3" @@ -33988,7 +33898,7 @@ __metadata: languageName: node linkType: hard -"npm-run-path@npm:^4.0.0, npm-run-path@npm:^4.0.1": +"npm-run-path@npm:^4.0.1": version: 4.0.1 resolution: "npm-run-path@npm:4.0.1" dependencies: @@ -34445,13 +34355,6 @@ __metadata: languageName: node linkType: hard -"ospath@npm:^1.2.2": - version: 1.2.2 - resolution: "ospath@npm:1.2.2" - checksum: 505f48a4f4f1c557d6c656ec985707726e3714721680139be037613e903aa8c8fa4ddd8d1342006f9b2dc0065e6e20f8b7bea2ee05354f31257044790367b347 - languageName: node - linkType: hard - "outdent@npm:^0.5.0": version: 0.5.0 resolution: "outdent@npm:0.5.0" @@ -35150,15 +35053,6 @@ __metadata: languageName: node linkType: hard -"pause-stream@npm:0.0.11": - version: 0.0.11 - resolution: "pause-stream@npm:0.0.11" - dependencies: - through: ~2.3 - checksum: 3c4a14052a638b92e0c96eb00c0d7977df7f79ea28395250c525d197f1fc02d34ce1165d5362e2e6ebbb251524b94a76f3f0d4abc39ab8b016d97449fe15583c - languageName: node - linkType: hard - "pause@npm:0.0.1": version: 0.0.1 resolution: "pause@npm:0.0.1" @@ -35356,7 +35250,7 @@ __metadata: languageName: node linkType: hard -"pify@npm:^2.2.0, pify@npm:^2.3.0": +"pify@npm:^2.3.0": version: 2.3.0 resolution: "pify@npm:2.3.0" checksum: 9503aaeaf4577acc58642ad1d25c45c6d90288596238fb68f82811c08104c800e5a7870398e9f015d82b44ecbcbef3dc3d4251a1cbb582f6e5959fe09884b2ba @@ -35433,17 +35327,6 @@ __metadata: languageName: node linkType: hard -"pixelmatch@npm:5.3.0": - version: 5.3.0 - resolution: "pixelmatch@npm:5.3.0" - dependencies: - pngjs: ^6.0.0 - bin: - pixelmatch: bin/pixelmatch - checksum: f542713d89536551181ad9ddb666a1792ba00a8632d831093232a075cb3ccac05856e7a453ed7d0a41aaef64dcb5962e8ae5cbe646dd2761790d8ee51b0a0743 - languageName: node - linkType: hard - "pkg-dir@npm:^3.0.0": version: 3.0.0 resolution: "pkg-dir@npm:3.0.0" @@ -35485,6 +35368,30 @@ __metadata: languageName: node linkType: hard +"playwright-core@npm:1.38.1": + version: 1.38.1 + resolution: "playwright-core@npm:1.38.1" + bin: + playwright-core: cli.js + checksum: 66e83fe040f309b13ad94ba39dea40ac207bfcbbc22de13141af88dbdedd64e1c4e3ce1d0cb070d4efd8050d7e579953ec3681dd8a0acf2c1cc738d9c50e545e + languageName: node + linkType: hard + +"playwright@npm:1.38.1": + version: 1.38.1 + resolution: "playwright@npm:1.38.1" + dependencies: + fsevents: 2.3.2 + playwright-core: 1.38.1 + dependenciesMeta: + fsevents: + optional: true + bin: + playwright: cli.js + checksum: 4e01d4ee52d9ccf75a80d8492829106802590721d56bff7c5957ff1f21eb3c328ee5bc3c1784a59c4b515df1b98d08ef92e4a35a807f454cd00dc481d30fadc2 + languageName: node + linkType: hard + "pluralize@npm:^8.0.0": version: 8.0.0 resolution: "pluralize@npm:8.0.0" @@ -35492,20 +35399,6 @@ __metadata: languageName: node linkType: hard -"pngjs@npm:7.0.0": - version: 7.0.0 - resolution: "pngjs@npm:7.0.0" - checksum: b19a018930d27de26229c1b3ff250b3a25d09caa22cbb0b0459987d91eb0a560a18ab5d67da45a38ed7514140f26d1db58de83c31159ec101f2bb270a3c707f1 - languageName: node - linkType: hard - -"pngjs@npm:^6.0.0": - version: 6.0.0 - resolution: "pngjs@npm:6.0.0" - checksum: ab6c285086060087097eab9fe6b5a528a24f9e79c03dea2b4fd6264ed4fdb5beff4a3257eeeaf2a9dc18249b539609c2a4e4013c567164a1f6b5ba2c974d5ecb - languageName: node - linkType: hard - "pony-cause@npm:^1.0.0": version: 1.1.1 resolution: "pony-cause@npm:1.1.1" @@ -36077,7 +35970,7 @@ __metadata: languageName: node linkType: hard -"pretty-bytes@npm:^5.3.0, pretty-bytes@npm:^5.6.0": +"pretty-bytes@npm:^5.3.0": version: 5.6.0 resolution: "pretty-bytes@npm:5.6.0" checksum: 9c082500d1e93434b5b291bd651662936b8bd6204ec9fa17d563116a192d6d86b98f6d328526b4e8d783c07d5499e2614a807520249692da9ec81564b2f439cd @@ -36165,13 +36058,6 @@ __metadata: languageName: node linkType: hard -"progress@npm:2.0.3": - version: 2.0.3 - resolution: "progress@npm:2.0.3" - checksum: f67403fe7b34912148d9252cb7481266a354bd99ce82c835f79070643bb3c6583d10dbcfda4d41e04bbc1d8437e9af0fb1e1f2135727878f5308682a579429b7 - languageName: node - linkType: hard - "prom-client@npm:^14.0.1": version: 14.2.0 resolution: "prom-client@npm:14.2.0" @@ -36357,31 +36243,13 @@ __metadata: languageName: node linkType: hard -"proxy-from-env@npm:1.0.0": - version: 1.0.0 - resolution: "proxy-from-env@npm:1.0.0" - checksum: 292e28d1de0c315958d71d8315eb546dd3cd8c8cbc2dab7c54eeb9f5c17f421771964ad0b5e1f77011bab2305bdae42e1757ce33bdb1ccc3e87732322a8efcf1 - languageName: node - linkType: hard - -"proxy-from-env@npm:1.1.0, proxy-from-env@npm:^1.1.0": +"proxy-from-env@npm:^1.1.0": version: 1.1.0 resolution: "proxy-from-env@npm:1.1.0" checksum: ed7fcc2ba0a33404958e34d95d18638249a68c430e30fcb6c478497d72739ba64ce9810a24f53a7d921d0c065e5b78e3822759800698167256b04659366ca4d4 languageName: node linkType: hard -"ps-tree@npm:1.2.0": - version: 1.2.0 - resolution: "ps-tree@npm:1.2.0" - dependencies: - event-stream: =3.3.4 - bin: - ps-tree: ./bin/ps-tree.js - checksum: e635dd00f53d30d31696cf5f95b3a8dbdf9b1aeb36d4391578ce8e8cd22949b7c5536c73b0dc18c78615ea3ddd4be96101166be59ca2e3e3cb1e2f79ba3c7f98 - languageName: node - linkType: hard - "pseudomap@npm:^1.0.2": version: 1.0.2 resolution: "pseudomap@npm:1.0.2" @@ -36448,25 +36316,6 @@ __metadata: languageName: node linkType: hard -"puppeteer@npm:^17.0.0": - version: 17.1.3 - resolution: "puppeteer@npm:17.1.3" - dependencies: - cross-fetch: 3.1.5 - debug: 4.3.4 - devtools-protocol: 0.0.1036444 - extract-zip: 2.0.1 - https-proxy-agent: 5.0.1 - progress: 2.0.3 - proxy-from-env: 1.1.0 - rimraf: 3.0.2 - tar-fs: 2.1.1 - unbzip2-stream: 1.4.3 - ws: 8.8.1 - checksum: b4518956c661df4c37690d46b9c6744d42d59d01fe3764938b4b3af8de4c94ef11a9dfa6bc261798f5e5490c6dce4d4f555f05d42c735249683da3017faf4585 - languageName: node - linkType: hard - "pure-color@npm:^1.2.0": version: 1.3.0 resolution: "pure-color@npm:1.3.0" @@ -37966,15 +37815,6 @@ __metadata: languageName: node linkType: hard -"request-progress@npm:^3.0.0": - version: 3.0.0 - resolution: "request-progress@npm:3.0.0" - dependencies: - throttleit: ^1.0.0 - checksum: 6ea1761dcc8a8b7b5894afd478c0286aa31bd69438d7050294bd4fd0d0b3e09b5cde417d38deef9c49809039c337d8744e4bb49d8632b0c3e4ffa5e8a687e0fd - languageName: node - linkType: hard - "request@npm:^2.88.0": version: 2.88.2 resolution: "request@npm:2.88.2" @@ -38269,17 +38109,6 @@ __metadata: languageName: node linkType: hard -"rimraf@npm:3.0.2, rimraf@npm:^3.0.0, rimraf@npm:^3.0.2": - version: 3.0.2 - resolution: "rimraf@npm:3.0.2" - dependencies: - glob: ^7.1.3 - bin: - rimraf: bin.js - checksum: 87f4164e396f0171b0a3386cc1877a817f572148ee13a7e113b238e48e8a9f2f31d009a92ec38a591ff1567d9662c6b67fd8818a2dbbaed74bc26a87a2a4a9a0 - languageName: node - linkType: hard - "rimraf@npm:^2.6.3": version: 2.7.1 resolution: "rimraf@npm:2.7.1" @@ -38291,6 +38120,17 @@ __metadata: languageName: node linkType: hard +"rimraf@npm:^3.0.0, rimraf@npm:^3.0.2": + version: 3.0.2 + resolution: "rimraf@npm:3.0.2" + dependencies: + glob: ^7.1.3 + bin: + rimraf: bin.js + checksum: 87f4164e396f0171b0a3386cc1877a817f572148ee13a7e113b238e48e8a9f2f31d009a92ec38a591ff1567d9662c6b67fd8818a2dbbaed74bc26a87a2a4a9a0 + languageName: node + linkType: hard + "rimraf@npm:~2.6.2": version: 2.6.3 resolution: "rimraf@npm:2.6.3" @@ -38450,11 +38290,13 @@ __metadata: "@backstage/cli": "workspace:*" "@backstage/codemods": "workspace:*" "@backstage/create-app": "workspace:*" + "@backstage/e2e-test-utils": "workspace:*" "@backstage/errors": "workspace:^" "@backstage/repo-tools": "workspace:*" "@changesets/cli": ^2.14.0 "@manypkg/get-packages": ^1.1.3 "@octokit/rest": ^19.0.3 + "@playwright/test": ^1.32.3 "@spotify/eslint-plugin": ^14.1.3 "@spotify/prettier-config": ^14.0.0 "@techdocs/cli": "workspace:*" @@ -38563,7 +38405,7 @@ __metadata: languageName: node linkType: hard -"rxjs@npm:^7.2.0, rxjs@npm:^7.5.1, rxjs@npm:^7.5.5, rxjs@npm:^7.8.0, rxjs@npm:^7.8.1": +"rxjs@npm:^7.2.0, rxjs@npm:^7.5.5, rxjs@npm:^7.8.1": version: 7.8.1 resolution: "rxjs@npm:7.8.1" dependencies: @@ -38826,7 +38668,7 @@ __metadata: languageName: node linkType: hard -"semver@npm:^7.1.1, semver@npm:^7.1.2, semver@npm:^7.1.3, semver@npm:^7.3.2, semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.3.8, semver@npm:^7.5.0, semver@npm:^7.5.3, semver@npm:~7.5.4": +"semver@npm:^7.1.1, semver@npm:^7.1.2, semver@npm:^7.1.3, semver@npm:^7.3.2, semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.3.8, semver@npm:^7.5.3, semver@npm:~7.5.4": version: 7.5.4 resolution: "semver@npm:7.5.4" dependencies: @@ -39026,23 +38868,6 @@ __metadata: languageName: node linkType: hard -"sharp@npm:0.32.1": - version: 0.32.1 - resolution: "sharp@npm:0.32.1" - dependencies: - color: ^4.2.3 - detect-libc: ^2.0.1 - node-addon-api: ^6.1.0 - node-gyp: latest - prebuild-install: ^7.1.1 - semver: ^7.5.0 - simple-get: ^4.0.1 - tar-fs: ^2.1.1 - tunnel-agent: ^0.6.0 - checksum: 99f50df380442aa8f3f952dd6f2e27634f9cab249cce47aa7f1a97c468334979ea94d71555f782aae5f5016e44b7832799f1c5ea1cb3ca975c089acd00e62e2e - languageName: node - linkType: hard - "shebang-command@npm:^1.2.0": version: 1.2.0 resolution: "shebang-command@npm:1.2.0" @@ -39565,15 +39390,6 @@ __metadata: languageName: node linkType: hard -"split@npm:0.3": - version: 0.3.3 - resolution: "split@npm:0.3.3" - dependencies: - through: 2 - checksum: 2e076634c9637cfdc54ab4387b6a243b8c33b360874a25adf6f327a5647f07cb3bf1c755d515248eb3afee4e382278d01f62c62d87263c118f28065b86f74f02 - languageName: node - linkType: hard - "split@npm:^1.0.0": version: 1.0.1 resolution: "split@npm:1.0.1" @@ -39640,7 +39456,7 @@ __metadata: languageName: node linkType: hard -"sshpk@npm:^1.14.1, sshpk@npm:^1.7.0": +"sshpk@npm:^1.7.0": version: 1.16.1 resolution: "sshpk@npm:1.16.1" dependencies: @@ -39762,26 +39578,6 @@ __metadata: languageName: node linkType: hard -"start-server-and-test@npm:^1.10.11": - version: 1.15.4 - resolution: "start-server-and-test@npm:1.15.4" - dependencies: - arg: ^5.0.2 - bluebird: 3.7.2 - check-more-types: 2.24.0 - debug: 4.3.4 - execa: 5.1.1 - lazy-ass: 1.6.0 - ps-tree: 1.2.0 - wait-on: 7.0.1 - bin: - server-test: src/bin/start.js - start-server-and-test: src/bin/start.js - start-test: src/bin/start.js - checksum: 0df9a4710ea45ddb1a9f719e0865faa8e26a973beff693dfe244ae2d914bfc6eed4d2db8529cdcad3d53658c4655356e5aca3520485a3ef4d9d9f320956b0e7d - languageName: node - linkType: hard - "statuses@npm:2.0.1": version: 2.0.1 resolution: "statuses@npm:2.0.1" @@ -39830,15 +39626,6 @@ __metadata: languageName: node linkType: hard -"stream-combiner@npm:~0.0.4": - version: 0.0.4 - resolution: "stream-combiner@npm:0.0.4" - dependencies: - duplexer: ~0.1.1 - checksum: 844b622cfe8b9de45a6007404f613b60aaf85200ab9862299066204242f89a7c8033b1c356c998aa6cfc630f6cd9eba119ec1c6dc1f93e245982be4a847aee7d - languageName: node - linkType: hard - "stream-events@npm:^1.0.5": version: 1.0.5 resolution: "stream-events@npm:1.0.5" @@ -40453,14 +40240,14 @@ __metadata: linkType: hard "swr@npm:^2.0.0": - version: 2.2.2 - resolution: "swr@npm:2.2.2" + version: 2.2.4 + resolution: "swr@npm:2.2.4" dependencies: client-only: ^0.0.1 use-sync-external-store: ^1.2.0 peerDependencies: react: ^16.11.0 || ^17.0.0 || ^18.0.0 - checksum: afb3d4824f7631bc3a045483f4e4beb5ca9bfa82b64690b3d1133cdf0666ad8e4a9a879657fac5b34dbf19ea9a1503cf92c9bde972f3d40cefe434c73bd9627a + checksum: d1398f89fd68af0e0cb6100a5769b1e17c0dbe8a778898643ad28456acda64add43344754c7d919e3f2ca82854adf86ff7d465aba25a2d555bcb669e457138f8 languageName: node linkType: hard @@ -40499,7 +40286,7 @@ __metadata: languageName: node linkType: hard -"tar-fs@npm:2.1.1, tar-fs@npm:^2.0.0, tar-fs@npm:^2.1.1": +"tar-fs@npm:^2.0.0, tar-fs@npm:^2.1.1": version: 2.1.1 resolution: "tar-fs@npm:2.1.1" dependencies: @@ -40598,14 +40385,11 @@ __metadata: "@types/react": "*" "@types/react-dom": "*" cross-env: ^7.0.0 - cypress: ^10.0.0 - eslint-plugin-cypress: ^2.10.3 history: ^5.0.0 react: ^17.0.2 react-dom: ^17.0.2 react-router-dom: ^6.3.0 react-use: ^17.2.4 - start-server-and-test: ^1.10.11 languageName: unknown linkType: soft @@ -40726,10 +40510,10 @@ __metadata: languageName: node linkType: hard -"textextensions@npm:^5.12.0, textextensions@npm:^5.13.0": - version: 5.14.0 - resolution: "textextensions@npm:5.14.0" - checksum: 1f610ccf2a2c1445fb7156c23b5c8defd608c74e8047df18abd4b9ee44c74d29b453ba104d14c53c91f9026670f7c923114cd12200ee5ec458cc518fd0798c74 +"textextensions@npm:^5.12.0, textextensions@npm:^5.13.0, textextensions@npm:^5.16.0": + version: 5.16.0 + resolution: "textextensions@npm:5.16.0" + checksum: d2abd5c962760046aa85d9ca542bd8bdb451370fc0a5e5f807aa80dd2f50175ec10d5ce9d28ae96968aaf6a1b1bea254cf4715f24852d0dcf29c6a60af7f793c languageName: node linkType: hard @@ -40758,13 +40542,6 @@ __metadata: languageName: node linkType: hard -"throttleit@npm:^1.0.0": - version: 1.0.0 - resolution: "throttleit@npm:1.0.0" - checksum: 1b2db4d2454202d589e8236c07a69d2fab838876d370030ebea237c34c0a7d1d9cf11c29f994531ebb00efd31e9728291042b7754f2798a8352ec4463455b659 - languageName: node - linkType: hard - "through2@npm:^4.0.0": version: 4.0.2 resolution: "through2@npm:4.0.2" @@ -40774,7 +40551,7 @@ __metadata: languageName: node linkType: hard -"through@npm:2, through@npm:^2.3.6, through@npm:^2.3.8, through@npm:~2.3, through@npm:~2.3.1": +"through@npm:2, through@npm:^2.3.6, through@npm:^2.3.8": version: 2.3.8 resolution: "through@npm:2.3.8" checksum: a38c3e059853c494af95d50c072b83f8b676a9ba2818dcc5b108ef252230735c54e0185437618596c790bbba8fcdaef5b290405981ffa09dce67b1f1bf190cbd @@ -40866,7 +40643,7 @@ __metadata: languageName: node linkType: hard -"tmp@npm:^0.2.0, tmp@npm:^0.2.1, tmp@npm:~0.2.1": +"tmp@npm:^0.2.0, tmp@npm:^0.2.1": version: 0.2.1 resolution: "tmp@npm:0.2.1" dependencies: @@ -40955,13 +40732,14 @@ __metadata: linkType: hard "tough-cookie@npm:^4.0.0": - version: 4.0.0 - resolution: "tough-cookie@npm:4.0.0" + version: 4.1.3 + resolution: "tough-cookie@npm:4.1.3" dependencies: psl: ^1.1.33 punycode: ^2.1.1 - universalify: ^0.1.2 - checksum: 0891b37eb7d17faa3479d47f0dce2e3007f2583094ad272f2670d120fbcc3df3b0b0a631ba96ecad49f9e2297d93ff8995ce0d3292d08dd7eabe162f5b224d69 + universalify: ^0.2.0 + url-parse: ^1.5.3 + checksum: c9226afff36492a52118432611af083d1d8493a53ff41ec4ea48e5b583aec744b989e4280bcf476c910ec1525a89a4a0f1cae81c08b18fb2ec3a9b3a72b91dcc languageName: node linkType: hard @@ -41555,16 +41333,6 @@ __metadata: languageName: node linkType: hard -"unbzip2-stream@npm:1.4.3": - version: 1.4.3 - resolution: "unbzip2-stream@npm:1.4.3" - dependencies: - buffer: ^5.2.1 - through: ^2.3.8 - checksum: 0e67c4a91f4fa0fc7b4045f8b914d3498c2fc2e8c39c359977708ec85ac6d6029840e97f508675fdbdf21fcb8d276ca502043406f3682b70f075e69aae626d1d - languageName: node - linkType: hard - "unc-path-regex@npm:^0.1.2": version: 0.1.2 resolution: "unc-path-regex@npm:0.1.2" @@ -41775,13 +41543,20 @@ __metadata: languageName: node linkType: hard -"universalify@npm:^0.1.0, universalify@npm:^0.1.2": +"universalify@npm:^0.1.0": version: 0.1.2 resolution: "universalify@npm:0.1.2" checksum: 40cdc60f6e61070fe658ca36016a8f4ec216b29bf04a55dce14e3710cc84c7448538ef4dad3728d0bfe29975ccd7bfb5f414c45e7b78883567fb31b246f02dff languageName: node linkType: hard +"universalify@npm:^0.2.0": + version: 0.2.0 + resolution: "universalify@npm:0.2.0" + checksum: e86134cb12919d177c2353196a4cc09981524ee87abf621f7bc8d249dbbbebaec5e7d1314b96061497981350df786e4c5128dbf442eba104d6e765bc260678b5 + languageName: node + linkType: hard + "universalify@npm:^2.0.0": version: 2.0.0 resolution: "universalify@npm:2.0.0" @@ -41867,7 +41642,7 @@ __metadata: languageName: node linkType: hard -"url-parse@npm:^1.5.10": +"url-parse@npm:^1.5.10, url-parse@npm:^1.5.3": version: 1.5.10 resolution: "url-parse@npm:1.5.10" dependencies: @@ -42355,21 +42130,6 @@ __metadata: languageName: node linkType: hard -"wait-on@npm:7.0.1": - version: 7.0.1 - resolution: "wait-on@npm:7.0.1" - dependencies: - axios: ^0.27.2 - joi: ^17.7.0 - lodash: ^4.17.21 - minimist: ^1.2.7 - rxjs: ^7.8.0 - bin: - wait-on: bin/wait-on - checksum: 1e8a17d8ee6436f71d3ab82781ce31267481fcd7bbccde49b0f8124871e6e40a1acac3401f04f775ba6203853a5813352fa131620fc139914351f3b2894d573f - languageName: node - linkType: hard - "walk-up-path@npm:^1.0.0": version: 1.0.0 resolution: "walk-up-path@npm:1.0.0" @@ -42951,21 +42711,6 @@ __metadata: languageName: node linkType: hard -"ws@npm:8.8.1": - version: 8.8.1 - resolution: "ws@npm:8.8.1" - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: ^5.0.2 - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - checksum: 2152cf862cae0693f3775bc688a6afb2e989d19d626d215e70f5fcd8eb55b1c3b0d3a6a4052905ec320e2d7734e20aeedbf9744496d62f15a26ad79cf4cf7dae - languageName: node - linkType: hard - "ws@npm:^5.2.0 || ^6.0.0 || ^7.0.0, ws@npm:^7.4.6": version: 7.5.9 resolution: "ws@npm:7.5.9" @@ -42982,8 +42727,8 @@ __metadata: linkType: hard "ws@npm:^8.11.0, ws@npm:^8.13.0, ws@npm:^8.8.0": - version: 8.14.1 - resolution: "ws@npm:8.14.1" + version: 8.14.2 + resolution: "ws@npm:8.14.2" peerDependencies: bufferutil: ^4.0.1 utf-8-validate: ">=5.0.2" @@ -42992,7 +42737,7 @@ __metadata: optional: true utf-8-validate: optional: true - checksum: 9e310be2b0ff69e1f87d8c6d093ecd17a1ed4c37f281d17c35e8c30e2bd116401775b3d503249651374e6e0e1e9905db62fff096b694371c77561aee06bc3466 + checksum: 3ca0dad26e8cc6515ff392b622a1467430814c463b3368b0258e33696b1d4bed7510bc7030f7b72838b9fdeb8dbd8839cbf808367d6aae2e1d668ce741d4308b languageName: node linkType: hard @@ -43135,6 +42880,15 @@ __metadata: languageName: node linkType: hard +"xterm-addon-attach@npm:^0.9.0": + version: 0.9.0 + resolution: "xterm-addon-attach@npm:0.9.0" + peerDependencies: + xterm: ^5.0.0 + checksum: 70e5d3ecf139c04fae13c644b79c33858ef1a6e28dfe78f91dad3e34f5a155579029b87e91d1d016575acaf17f74e6c59402bde4bcff03461595bea0870f1ec1 + languageName: node + linkType: hard + "xterm-addon-fit@npm:^0.7.0": version: 0.7.0 resolution: "xterm-addon-fit@npm:0.7.0" @@ -43144,10 +42898,19 @@ __metadata: languageName: node linkType: hard -"xterm@npm:^5.2.1": - version: 5.2.1 - resolution: "xterm@npm:5.2.1" - checksum: 3a9de30e772c7ae30895ec97fcfb3b0906429c5ea0cddf8948e8e30301385f82e467c6e6aca28ae50a48300ce795381d83fe35b4e17886ab4a1357054a15f68f +"xterm-addon-fit@npm:^0.8.0": + version: 0.8.0 + resolution: "xterm-addon-fit@npm:0.8.0" + peerDependencies: + xterm: ^5.0.0 + checksum: 5af2041b442f7c804eda2e6f62e3b68b5159b0ae6bd96e2aa8d85b26441df57291cbfed653d1196d4af5d9b94bfc39993df8b409a25c35e0d36bdaf6f5cdfe5f + languageName: node + linkType: hard + +"xterm@npm:^5.2.1, xterm@npm:^5.3.0": + version: 5.3.0 + resolution: "xterm@npm:5.3.0" + checksum: 1bdfdfe4cae4412128376180d85e476b43fb021cdd1114b18acad821c9ea44b5b600e0d88febf2b3572f38fad7741e5161ce0178a44369617cf937222cc6e011 languageName: node linkType: hard @@ -43487,9 +43250,9 @@ __metadata: linkType: hard "zod@npm:^3.21.4": - version: 3.22.2 - resolution: "zod@npm:3.22.2" - checksum: 231e2180c8eabb56e88680d80baff5cf6cbe6d64df3c44c50ebe52f73081ecd0229b1c7215b9552537f537a36d9e36afac2737ddd86dc14e3519bdbc777e82b9 + version: 3.22.3 + resolution: "zod@npm:3.22.3" + checksum: 65b05139be337078a70700b05942ab7f2ef5f11abe194df14ef257fac4e5c383476a4dc290731842996bd57fc8d5bf38e5a4c907fe8cdf8b15477f8da5bfcc00 languageName: node linkType: hard