diff --git a/.changeset/angry-starfishes-confess.md b/.changeset/angry-starfishes-confess.md new file mode 100644 index 0000000000..5cb4395d9a --- /dev/null +++ b/.changeset/angry-starfishes-confess.md @@ -0,0 +1,41 @@ +--- +'@backstage/plugin-catalog-backend-module-bitbucket-cloud': patch +--- + +Handle Bitbucket Cloud `repo:push` events at the `BitbucketCloudEntityProvider` +by subscribing to the topic `bitbucketCloud.repo:push.` + +Implements `EventSubscriber` to receive events for the topic `bitbucketCloud.repo:push`. + +On `repo:push`, the affected repository will be refreshed. +This includes adding new Location entities, refreshing existing ones, +and removing obsolete ones. + +To support this, a new annotation `bitbucket.org/repo-url` was added +to Location entities. + +A full refresh will require 1 API call to Bitbucket Cloud to discover all catalog files. +When we handle one `repo:push` event, we also need 1 API call in order to know +which catalog files exist. +This may lead to more discovery-related API calls (code search). +The main cause for hitting the rate limits are Locations refresh-related operations. + +A reduction of total API calls to reduce the rate limit issues can only be achieved in +combination with + +1. reducing the full refresh frequency (e.g., to monthly) +2. reducing the frequency of general Location refresh operations by the processing loop + +For (2.), it is not possible to reduce the frequency only for Bitbucket Cloud-related +Locations though. + +Further optimizations might be required to resolve the rate limit issue. + +**Installation and Migration** + +Please find more information at +https://backstage.io/docs/integrations/bitbucketCloud/discovery, +in particular the section about "_Installation with Events Support_". + +In case of the new backend-plugin-api _(alpha)_ the module will take care of +registering itself at both. diff --git a/.changeset/blue-papayas-relax.md b/.changeset/blue-papayas-relax.md new file mode 100644 index 0000000000..002fd66a62 --- /dev/null +++ b/.changeset/blue-papayas-relax.md @@ -0,0 +1,14 @@ +--- +'@backstage/plugin-events-backend-module-bitbucket-cloud': minor +--- + +Adds a new module `bitbucket-cloud` to plugin-events-backend. + +The module adds a new event router `BitbucketCloudEventRouter`. + +The event router will re-publish events received at topic `bitbucketCloud` +under a more specific topic depending on their `x-event-key` value +(e.g., `bitbucketCloud.repo:push`). + +Please find more information at +https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-bitbucket-cloud/README.md. diff --git a/.changeset/brave-bugs-teach.md b/.changeset/brave-bugs-teach.md new file mode 100644 index 0000000000..2869796c2a --- /dev/null +++ b/.changeset/brave-bugs-teach.md @@ -0,0 +1,8 @@ +--- +'@backstage/plugin-apache-airflow': patch +--- + +1. Added a new column in the table to quickly view the latest DAG runs, plus a link to it if you want to have a deeper look. +2. Table columns are togglable +3. Set hidden columns +4. Fixed bug with turning on/off the DAGs diff --git a/.changeset/chilled-moles-itch.md b/.changeset/chilled-moles-itch.md new file mode 100644 index 0000000000..2421993779 --- /dev/null +++ b/.changeset/chilled-moles-itch.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Updated the `backstage-cli` so that the `list-deprecations` command is visible and also removed the "[EXPERIMENTAL]" tag. diff --git a/.changeset/clever-colts-roll.md b/.changeset/clever-colts-roll.md new file mode 100644 index 0000000000..b0aed88dae --- /dev/null +++ b/.changeset/clever-colts-roll.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': patch +--- + +Updated to use `@rjsf` packages of version `^5.0.0-beta.12` diff --git a/.changeset/cuddly-coats-try.md b/.changeset/cuddly-coats-try.md new file mode 100644 index 0000000000..3b8bb654b2 --- /dev/null +++ b/.changeset/cuddly-coats-try.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +Improve processing error logging. + +Adds `location` and `owner` to the logging meta if they are available. diff --git a/.changeset/dry-phones-type.md b/.changeset/dry-phones-type.md new file mode 100644 index 0000000000..ad2cf40113 --- /dev/null +++ b/.changeset/dry-phones-type.md @@ -0,0 +1,5 @@ +--- +'@backstage/release-manifests': patch +--- + +Added a fallback that fetches manifests from `https://raw.githubusercontent.com` if `https://versions.backstage.io` is unavailable. diff --git a/.changeset/early-jars-laugh.md b/.changeset/early-jars-laugh.md new file mode 100644 index 0000000000..9b9de4ab80 --- /dev/null +++ b/.changeset/early-jars-laugh.md @@ -0,0 +1,5 @@ +--- +'@backstage/version-bridge': patch +--- + +Debuggable/inspectable versioned values diff --git a/.changeset/four-snails-raise.md b/.changeset/four-snails-raise.md new file mode 100644 index 0000000000..1484a454e1 --- /dev/null +++ b/.changeset/four-snails-raise.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Removed googleAnalyticsTrackingId configSchema. diff --git a/.changeset/funny-countries-watch.md b/.changeset/funny-countries-watch.md new file mode 100644 index 0000000000..452146d762 --- /dev/null +++ b/.changeset/funny-countries-watch.md @@ -0,0 +1,14 @@ +--- +'@backstage/plugin-events-backend-module-github': minor +--- + +Adds a new module `github` to plugin-events-backend. + +The module adds a new event router `GithubEventRouter`. + +The event router will re-publish events received at topic `github` +under a more specific topic depending on their `x-github-event` value +(e.g., `github.push`). + +Please find more information at +https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-github/README.md. diff --git a/.changeset/good-doors-attend.md b/.changeset/good-doors-attend.md new file mode 100644 index 0000000000..0f8a5344ee --- /dev/null +++ b/.changeset/good-doors-attend.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': patch +--- + +Fixed tiny grammar error in EntityNamePicker. The first letter of the description is now capitalized. diff --git a/.changeset/great-icons-greet.md b/.changeset/great-icons-greet.md new file mode 100644 index 0000000000..f32f6f1808 --- /dev/null +++ b/.changeset/great-icons-greet.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-auth-backend': patch +--- + +Add support for custom JWT header name in GCP IAP auth. diff --git a/.changeset/large-spies-doubt.md b/.changeset/large-spies-doubt.md new file mode 100644 index 0000000000..d81b31df28 --- /dev/null +++ b/.changeset/large-spies-doubt.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend': minor +--- + +Adds the ability to pass (an optional) array of strings that will be applied to the newly scaffolded repository as topic labels. diff --git a/.changeset/lazy-nails-study.md b/.changeset/lazy-nails-study.md new file mode 100644 index 0000000000..8d365c4662 --- /dev/null +++ b/.changeset/lazy-nails-study.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-graph': patch +--- + +feat: Enable theme overrides for components in catalog-graph plugin diff --git a/.changeset/light-eagles-poke.md b/.changeset/light-eagles-poke.md new file mode 100644 index 0000000000..8b1f5bb522 --- /dev/null +++ b/.changeset/light-eagles-poke.md @@ -0,0 +1,14 @@ +--- +'@backstage/plugin-events-backend-module-gerrit': minor +--- + +Adds a new module `gerrit` to plugin-events-backend. + +The module adds a new event router `GerritEventRouter`. + +The event router will re-publish events received at topic `gerrit` +under a more specific topic depending on their `$.type` value +(e.g., `gerrit.change-merged`). + +Please find more information at +https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-gerrit/README.md. diff --git a/.changeset/long-suits-pull.md b/.changeset/long-suits-pull.md new file mode 100644 index 0000000000..2f96ab18da --- /dev/null +++ b/.changeset/long-suits-pull.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-common': patch +--- + +Change to using `@keyv/memcache` now that `keyv-memcache` is deprecated diff --git a/.changeset/lovely-news-relax.md b/.changeset/lovely-news-relax.md new file mode 100644 index 0000000000..01e3f500d1 --- /dev/null +++ b/.changeset/lovely-news-relax.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +The built-in Jest configuration now always uses the Jest environments that are bundled with the CLI by default. This avoids a situation where Jest potentially picks up an incompatible version of the environment package from a different dependency in the project. diff --git a/.changeset/lucky-falcons-dress.md b/.changeset/lucky-falcons-dress.md new file mode 100644 index 0000000000..16e5c8a015 --- /dev/null +++ b/.changeset/lucky-falcons-dress.md @@ -0,0 +1,38 @@ +--- +'@backstage/create-app': patch +--- + +The [Analytics API](https://backstage.io/docs/plugins/analytics) is the recommended way to track usage in Backstage; an optionally installable [Google Analytics module](https://github.com/backstage/backstage/tree/master/plugins/analytics-module-ga#installation) has superseded the old app.googleAnalyticsTrackingId config and its corresponding script tags in packages/app/public/index.html. + +For an existing installation where you want to remove the redundant app.googleAnalyticsTrackingId, you should make the following adjustment to `packages/app/public/index.html`: + +```diff + <%= config.getString('app.title') %> +- <% if (config.has('app.googleAnalyticsTrackingId')) { %> +- +- +- <% } %> + +``` + +Additionally, you should make the following adjustment to `app-config.yaml`: + +```diff +app: + title: Backstage Example App + baseUrl: http://localhost:3000 +- googleAnalyticsTrackingId: # UA-000000-0 +``` diff --git a/.changeset/many-starfishes-exist.md b/.changeset/many-starfishes-exist.md new file mode 100644 index 0000000000..d6f891aa78 --- /dev/null +++ b/.changeset/many-starfishes-exist.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-stack-overflow': patch +--- + +`StackOverflowSearchResultListItem` now accept optional rank property to be able to capture rank analytics data. diff --git a/.changeset/modern-toys-yell.md b/.changeset/modern-toys-yell.md new file mode 100644 index 0000000000..d867d2b3af --- /dev/null +++ b/.changeset/modern-toys-yell.md @@ -0,0 +1,12 @@ +--- +'@backstage/plugin-events-backend-module-aws-sqs': minor +--- + +Adds a new module `aws-sqs` for plugin-events-backend. + +The module provides an event publisher `AwsSqsConsumingEventPublisher` +which will allow you to receive events from +an AWS SQS queue and will publish these to the used event broker. + +Please find more information at +https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-aws-sqs/README.md. diff --git a/.changeset/moody-countries-live.md b/.changeset/moody-countries-live.md new file mode 100644 index 0000000000..d6cc53871b --- /dev/null +++ b/.changeset/moody-countries-live.md @@ -0,0 +1,14 @@ +--- +'@backstage/plugin-events-backend-module-azure': minor +--- + +Adds a new module `azure` to plugin-events-backend. + +The module adds a new event router `AzureDevOpsEventRouter`. + +The event router will re-publish events received at topic `azureDevOps` +under a more specific topic depending on their `$.eventType` value +(e.g., `azureDevOps.git.push`). + +Please find more information at +https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-azure/README.md. diff --git a/.changeset/moody-pots-end.md b/.changeset/moody-pots-end.md new file mode 100644 index 0000000000..80ee32c2c3 --- /dev/null +++ b/.changeset/moody-pots-end.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': patch +--- + +Fix `formData` not being present in the `next` version diff --git a/.changeset/pink-snails-hammer.md b/.changeset/pink-snails-hammer.md new file mode 100644 index 0000000000..fbcadfb1d9 --- /dev/null +++ b/.changeset/pink-snails-hammer.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-code-coverage': patch +'@backstage/plugin-code-coverage-backend': patch +--- + +Adds installation instructions diff --git a/.changeset/poor-cheetahs-work.md b/.changeset/poor-cheetahs-work.md new file mode 100644 index 0000000000..0fa29949d2 --- /dev/null +++ b/.changeset/poor-cheetahs-work.md @@ -0,0 +1,17 @@ +--- +'@backstage/plugin-events-backend': minor +'@backstage/plugin-events-node': minor +--- + +Support events received via HTTP endpoints at plugin-events-backend. + +The plugin provides an event publisher `HttpPostIngressEventPublisher` +which will allow you to receive events via +HTTP endpoints `POST /api/events/http/{topic}` +and will publish these to the used event broker. + +Using a provided custom validator, you can participate in the decision +which events are accepted, e.g. by verifying the source of the request. + +Please find more information at +https://github.com/backstage/backstage/tree/master/plugins/events-backend/README.md. diff --git a/.changeset/pre.json b/.changeset/pre.json index 9aa5bbdfdf..008636c972 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -1,5 +1,5 @@ { - "mode": "pre", + "mode": "exit", "tag": "next", "initialVersions": { "example-app": "0.2.76", @@ -176,23 +176,31 @@ "@backstage/plugin-xcmetrics": "0.2.30", "@backstage/plugin-azure-sites": "0.0.0", "@backstage/plugin-azure-sites-backend": "0.0.0", - "@backstage/plugin-azure-sites-common": "0.0.0" + "@backstage/plugin-azure-sites-common": "0.0.0", + "@backstage/plugin-org-react": "0.0.0" }, "changesets": [ + "analyze-next-software-creation", "analyze-software-creation", "analyze-software-exploration", "beige-gorillas-sip", "big-islands-add", + "blue-items-shop", "brave-eels-allow", + "bright-pillows-build", "brown-days-pretend", "calm-bottles-happen", + "calm-clouds-smoke", "chatty-planets-flash", "clean-feet-remain", "clean-planets-rhyme", + "cool-suns-add", "create-app-1667233110", "dirty-birds-burn", + "dry-phones-type", "dull-oranges-tap", "eight-pears-attack", + "eighty-planets-train", "eleven-pets-sneeze", "few-books-remember", "flat-items-perform", @@ -201,29 +209,39 @@ "forty-jokes-lie", "fresh-cooks-sing", "fresh-weeks-share", + "funny-singers-serve", "gorgeous-balloons-sit", "gorgeous-onions-thank", "gorgeous-queens-pull", "great-colts-invite", + "great-planes-arrive", "grumpy-clouds-drum", "grumpy-pigs-reflect", "happy-avocados-tan", "heavy-elephants-nail", + "hungry-kiwis-scream", "itchy-paws-protect", "kind-emus-juggle", + "large-spies-doubt", "lazy-planes-repair", "little-bikes-eat", + "little-plums-look", "lucky-cats-peel", "lucky-cobras-sell", "lucky-spoons-hide", "mean-files-fly", "metal-dogs-swim", "metal-hairs-mix", + "moody-pots-end", "nasty-crabs-share", "orange-trees-peel", + "pink-snails-hammer", + "popular-ants-mix", "popular-bulldogs-lie", "popular-mails-wave", "real-swans-repair", + "renovate-25512c2", + "renovate-3d08223", "renovate-6fb5f1b", "selfish-kiwis-matter", "shaggy-birds-happen", @@ -231,22 +249,29 @@ "sharp-goats-itch", "shiny-beers-relax", "short-balloons-work", + "silent-moles-chew", + "silly-meals-teach", "sixty-islands-develop", "sixty-pigs-shave", "sixty-singers-push", "spicy-parents-lick", "spotty-dryers-explain", + "stale-dots-love", "stupid-pens-occur", "sweet-readers-compare", "tame-ads-appear", "tasty-colts-hug", "tasty-scissors-tickle", + "ten-hats-tickle", "ten-pens-draw", + "thirty-deers-float", "three-houses-agree", "three-poems-think", "two-oranges-joke", + "two-timers-pump", "two-yaks-wave", "unlucky-buttons-poke", - "wet-cameras-call" + "wet-cameras-call", + "witty-carrots-live" ] } diff --git a/.changeset/proud-queens-warn.md b/.changeset/proud-queens-warn.md new file mode 100644 index 0000000000..0eb133f290 --- /dev/null +++ b/.changeset/proud-queens-warn.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend-module-github': patch +--- + +- Make it possible to inject custom user and team transformers when configuring the `GithubOrgEntityProvider` diff --git a/.changeset/renovate-9097e77-extras.md b/.changeset/renovate-9097e77-extras.md new file mode 100644 index 0000000000..082a6921a0 --- /dev/null +++ b/.changeset/renovate-9097e77-extras.md @@ -0,0 +1,9 @@ +--- +'@backstage/plugin-catalog-backend-module-azure': patch +'@backstage/plugin-catalog-backend-module-bitbucket': patch +'@backstage/plugin-catalog-backend-module-gerrit': patch +'@backstage/plugin-catalog-backend-module-github': patch +'@backstage/plugin-catalog-backend-module-gitlab': patch +--- + +Updated dependency `msw` to `^0.48.0` while moving it to be a dev dependency. diff --git a/.changeset/renovate-9097e77.md b/.changeset/renovate-9097e77.md new file mode 100644 index 0000000000..4e7f767a45 --- /dev/null +++ b/.changeset/renovate-9097e77.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-test-utils': patch +--- + +Updated dependency `msw` to `^0.48.0`. diff --git a/.changeset/renovate-e920c22.md b/.changeset/renovate-e920c22.md new file mode 100644 index 0000000000..29a66fba59 --- /dev/null +++ b/.changeset/renovate-e920c22.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-api-docs': patch +--- + +Updated dependency `@asyncapi/react-component` to `1.0.0-next.44`. diff --git a/.changeset/rotten-readers-yell.md b/.changeset/rotten-readers-yell.md new file mode 100644 index 0000000000..29be4102dc --- /dev/null +++ b/.changeset/rotten-readers-yell.md @@ -0,0 +1,14 @@ +--- +'@backstage/plugin-events-backend': minor +'@backstage/plugin-events-node': minor +'@backstage/plugin-events-backend-test-utils': minor +--- + +Adds a new backend plugin plugin-events-backend for managing events. + +plugin-events-node exposes interfaces which can be used by modules. + +plugin-events-backend-test-utils provides utilities which can be used while writing tests e.g. for modules. + +Please find more information at +https://github.com/backstage/backstage/tree/master/plugins/events-backend/README.md. diff --git a/.changeset/shaggy-moles-jump.md b/.changeset/shaggy-moles-jump.md new file mode 100644 index 0000000000..b2417beb9e --- /dev/null +++ b/.changeset/shaggy-moles-jump.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-cost-insights': patch +--- + +Added support for displaying entity cost insights by implementing the new `getCatalogEntityDailyCost` that's part of the `CostInsightsApi`. diff --git a/.changeset/silly-snails-fail.md b/.changeset/silly-snails-fail.md new file mode 100644 index 0000000000..10376e5ece --- /dev/null +++ b/.changeset/silly-snails-fail.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs': minor +--- + +Hide document description if not provided diff --git a/.changeset/small-chefs-tell.md b/.changeset/small-chefs-tell.md new file mode 100644 index 0000000000..46d8a33f3c --- /dev/null +++ b/.changeset/small-chefs-tell.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-bitbucket-cloud-common': patch +--- + +Add interfaces for Bitbucket Cloud (webhook) events. diff --git a/.changeset/small-months-call.md b/.changeset/small-months-call.md new file mode 100644 index 0000000000..de926ee219 --- /dev/null +++ b/.changeset/small-months-call.md @@ -0,0 +1,14 @@ +--- +'@backstage/plugin-events-backend-module-gitlab': minor +--- + +Adds a new module `gitlab` to plugin-events-backend. + +The module adds a new event router `GitlabEventRouter`. + +The event router will re-publish events received at topic `gitlab` +under a more specific topic depending on their `$.event_name` value +(e.g., `gitlab.push`). + +Please find more information at +https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-gitlab/README.md. diff --git a/.changeset/stale-dots-love.md b/.changeset/stale-dots-love.md new file mode 100644 index 0000000000..46327937f0 --- /dev/null +++ b/.changeset/stale-dots-love.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-tech-insights-backend': patch +--- + +Add Documentation on 404 Errors diff --git a/.changeset/stale-tools-yawn.md b/.changeset/stale-tools-yawn.md new file mode 100644 index 0000000000..f0173c7dd7 --- /dev/null +++ b/.changeset/stale-tools-yawn.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-org': patch +--- + +Add entity kind to the Ownership Cards. Fix the query parameters for the links of the Ownership Cards so that the catalog page actually selects the right entity kind. diff --git a/.changeset/techdocs-analyze-clicks.md b/.changeset/techdocs-analyze-clicks.md new file mode 100644 index 0000000000..664fea10bd --- /dev/null +++ b/.changeset/techdocs-analyze-clicks.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs': patch +--- + +An analytics event matching the semantics of the `click` action is now captured when users click links within a TechDocs document. diff --git a/.changeset/techdocs-analyze-entities.md b/.changeset/techdocs-analyze-entities.md new file mode 100644 index 0000000000..b9c701c1a8 --- /dev/null +++ b/.changeset/techdocs-analyze-entities.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs-react': patch +--- + +Analytics events captured within the `` now include the conventional `entityRef` context value, associating those events with their corresponding entity. diff --git a/.changeset/ten-hats-tickle.md b/.changeset/ten-hats-tickle.md new file mode 100644 index 0000000000..5545dfa7ba --- /dev/null +++ b/.changeset/ten-hats-tickle.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend': patch +--- + +Implement "Branch protection rules" support for "publish:github" action diff --git a/.changeset/tidy-avocados-ring.md b/.changeset/tidy-avocados-ring.md new file mode 100644 index 0000000000..bc1a0f330d --- /dev/null +++ b/.changeset/tidy-avocados-ring.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': patch +--- + +Fix the return type for the `createNextScaffodlerFieldExtension` type as before it wasn't a component type for the extension diff --git a/.changeset/unlucky-pigs-end.md b/.changeset/unlucky-pigs-end.md new file mode 100644 index 0000000000..7088a92c48 --- /dev/null +++ b/.changeset/unlucky-pigs-end.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-sonarqube': minor +--- + +Fix sonarqube annotation parsing. Add content page for Sonarqube. +Removed the deprecated `plugin` export; please use `sonarQubePlugin` instead. diff --git a/.changeset/wicked-pumas-nail.md b/.changeset/wicked-pumas-nail.md new file mode 100644 index 0000000000..c9e05aff74 --- /dev/null +++ b/.changeset/wicked-pumas-nail.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-auth-backend': patch +--- + +Inject optional `CatalogApi` into auth-backend `createRouter` function. This will enable developers to use customized `CatalogApi` when creating the router. diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 2dd8f4b55b..3f17c9591f 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -36,6 +36,15 @@ yarn.lock @backstage/reviewers @backst /plugins/code-coverage-backend @backstage/reviewers @alde @nissayeva /plugins/cost-insights @backstage/reviewers @backstage/silver-lining /plugins/cost-insights-* @backstage/reviewers @backstage/silver-lining +/plugins/events-backend @backstage/reviewers @pjungermann +/plugins/events-backend-module-aws-sqs @backstage/reviewers @pjungermann +/plugins/events-backend-module-azure @backstage/reviewers @pjungermann +/plugins/events-backend-module-bitbucket-cloud @backstage/reviewers @pjungermann +/plugins/events-backend-module-gerrit @backstage/reviewers @pjungermann +/plugins/events-backend-module-github @backstage/reviewers @pjungermann +/plugins/events-backend-module-gitlab @backstage/reviewers @pjungermann +/plugins/events-backend-test-utils @backstage/reviewers @pjungermann +/plugins/events-node @backstage/reviewers @pjungermann /plugins/explore @backstage/reviewers @backstage/sda-se-reviewers /plugins/explore-react @backstage/reviewers @backstage/sda-se-reviewers /plugins/fossa @backstage/reviewers @backstage/sda-se-reviewers diff --git a/.github/vale/Vocab/Backstage/accept.txt b/.github/vale/Vocab/Backstage/accept.txt index 839afaa256..58f5b57004 100644 --- a/.github/vale/Vocab/Backstage/accept.txt +++ b/.github/vale/Vocab/Backstage/accept.txt @@ -234,6 +234,8 @@ onboarding Onboarding OpenShift orgs +padding +paddings pagerduty pageview parallelization @@ -352,6 +354,7 @@ theia thumbsup todo todos +togglable tolerations Tolerations toolchain diff --git a/.github/workflows/automate_stale.yml b/.github/workflows/automate_stale.yml index 51bf41d61a..12fccdc7ed 100644 --- a/.github/workflows/automate_stale.yml +++ b/.github/workflows/automate_stale.yml @@ -17,7 +17,7 @@ jobs: for your contributions. days-before-issue-stale: 60 days-before-issue-close: 7 - exempt-issue-labels: pinned,security,plugin,after-vacations,rfc,will-fix + exempt-issue-labels: plugin,after-vacations,will-fix stale-issue-label: stale stale-pr-message: > This PR has been automatically marked as stale because it has not had diff --git a/ADOPTERS.md b/ADOPTERS.md index da56d592b3..76ec9ea348 100644 --- a/ADOPTERS.md +++ b/ADOPTERS.md @@ -141,7 +141,7 @@ _You can do this by using the [Adopter form](https://info.backstage.spotify.com/ | [Kambi AB](https://www.kambi.com) | [Martin Norum](mailto:martin.norum@kambi.com) | We want to kick ass at speed, so we're currently building up a catalog of our existing software, and looking into how Backstage can support us in our journey towards autonomous product teams. Both to improve speed to market and operational awareness. | | [ANZ](https://www.anz.com.au/personal/) | [Elliot Jackson](mailto:elliot.jackson@anz.com) | Catalog, tech docs and automation | | [Genie Solutions](https://www.geniesolutionssoftware.com.au) | [Zainab Bagasrawala](mailto:zainabbagasrawala@geniesolutions.com.au) | Developer Portal to track our projects, documentation, observability tools and more | -| [MadeiraMadeira](https://www.madeiramadeira.com.br) | [Paulo Eduardo Peixoto](mailto:paulo.peixoto@madeiramadeira.com.br) | As a support tool for developers, following the principles of "Developer Experience". In order to make the developer's day to day more practical, efficient and, why not, happy. | +| [MadeiraMadeira](https://www.madeiramadeira.com.br) | [DX Team](mailto:dxteam@madeiramadeira.com.br) | As a support tool for developers, following the principles of "Developer Experience". In order to make the developer's day to day more practical, efficient and, why not, happy. | | [Sonatype](https://www.sonatype.com) | [Srikar Ananthula](mailto:sananthula@sonatype.com) | Centralize services used internally with many plugins | | [CVS Health](https://www.cvshealth.com) | [Ari Ben-Elazar](mailto:abenelazar@gmail.com) | Cataloging and documenting our service offerings to offer our internal developers a better operational journey | | [Yatra.com](https://www.yatra.com) | [Matiur Rahman Maitur](mailto:arifrahman4u@gmail.com) | Easy to find out Project details, ownership, dependent services, Documentation, it is very useful for developer. | @@ -217,3 +217,7 @@ _You can do this by using the [Adopter form](https://info.backstage.spotify.com/ | [StatusNeo](https://statusneo.com/) | [Karan Nangru](mailto:nangru@statusneo.com), [@NishkarshRaj](https://github.com/NishkarshRaj), and [Gaurav Sarien](mailto:gaurav.sarien@statusneo.com) | Harnessing the power of central catalog inventory and self-serving software templates | | [Alaska Airlines](https://alaskaair.com) | [@swerdick](https://github.com/swerdick) | Backstage is the developer portal for our 'software delivery platform'. Consolidating developer tools to one place, and providing automation to make it easy for developers to create and deploy applications to Kubernetes | [Loft](https://loft.com.br) | [Squad DevTools](mailto:squad_devtools@loft.com.br) | We're using Backstage to give visibility and promote ownership of all our applications, resources and tools. Now moving to use it as a Developer Portal to create applications, AWS resources etc. | +| [Raízen](https://www.raizen.com) | [Melquisedque Bernardes Pereira](https://github.com/rayleshh) and [Paulo Eduardo Peixoto](https://github.com/padupe) | Backstage helps us to organize and make available, in a simple and direct way, all the infrastructure for new projects. In addition, it has become a great support tool for our developers. | +| [Trifork](https://trifork.com) | [Casper Thygesen](https://github.com/cthtrifork) | We're using Backstage as part of our dataplatform product. It integrates with the infrastructure components and is the developer portal for all the platform users. | +| [MSCI](http://msci.com) | [Stephen Burrows](mailto:stephen.burrows@msci.com) | Developer portal, service catalog, documentation and tooling +| [ESW](https://esw.com) | [Alisson Fabiano](https://github.com/afabianoo), [Bruno Quintella](https://github.com/quintelab) and [Guilherme Oenning](https://github.com/goenning) | Backstage is our one stop shop to find everything related to all our services, such as ownership, dependencies, production status, tech health and much more. diff --git a/app-config.yaml b/app-config.yaml index 69a1207365..ef133491af 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -1,7 +1,6 @@ app: title: Backstage Example App baseUrl: http://localhost:3000 - googleAnalyticsTrackingId: # UA-000000-0 #datadogRum: # clientToken: '123456789' # applicationId: qwerty diff --git a/contrib/chart/backstage/templates/backstage-app-config.yaml b/contrib/chart/backstage/templates/backstage-app-config.yaml index f06e47feab..061fc3285b 100644 --- a/contrib/chart/backstage/templates/backstage-app-config.yaml +++ b/contrib/chart/backstage/templates/backstage-app-config.yaml @@ -13,7 +13,6 @@ metadata: data: APP_CONFIG_app_baseUrl: {{ .Values.appConfig.app.baseUrl | quote | quote }} APP_CONFIG_app_title: {{ .Values.appConfig.app.title | quote | quote }} - APP_CONFIG_app_googleAnalyticsTrackingId: {{ .Values.appConfig.app.googleAnalyticsTrackingId | quote | quote }} APP_CONFIG_backend_baseUrl: {{ .Values.appConfig.backend.baseUrl | quote | quote }} APP_CONFIG_backend_cors_origin: {{ .Values.appConfig.backend.cors.origin | quote | quote }} APP_CONFIG_techdocs_storageUrl: {{ .Values.appConfig.techdocs.storageUrl | quote | quote }} diff --git a/contrib/chart/backstage/values.yaml b/contrib/chart/backstage/values.yaml index 6ffe076e57..cd80fd954b 100644 --- a/contrib/chart/backstage/values.yaml +++ b/contrib/chart/backstage/values.yaml @@ -92,7 +92,6 @@ appConfig: app: baseUrl: https://demo.example.com title: Backstage - googleAnalyticsTrackingId: backend: baseUrl: https://demo.example.com listen: diff --git a/docs/auth/add-auth-provider.md b/docs/auth/add-auth-provider.md index 01c18f04cd..a43e2307e6 100644 --- a/docs/auth/add-auth-provider.md +++ b/docs/auth/add-auth-provider.md @@ -49,7 +49,7 @@ the user to initiate a login. This login request is done to the `/start` endpoint which is handled by the `start` method. The `start` method re-directs to the external auth provider who authenticates -the request and re-directs the request to the `/frame/handler` endpoint, which +the request and re-directs the request to the `/handler/frame` endpoint, which is handled by the `frameHandler` method. The `frameHandler` returns an HTML response, containing a script that does a diff --git a/docs/auth/google/gcp-iap-auth.md b/docs/auth/google/gcp-iap-auth.md index 1ebfcaf15b..90d267b327 100644 --- a/docs/auth/google/gcp-iap-auth.md +++ b/docs/auth/google/gcp-iap-auth.md @@ -26,6 +26,7 @@ auth: providers: gcp-iap: audience: '/projects//global/backendServices/' + jwtHeader: x-custom-header # Optional: Only if you are using a custom header for the IAP JWT ``` You can find the project number and service ID in the Google Cloud Console. diff --git a/docs/auth/microsoft/provider.md b/docs/auth/microsoft/provider.md index cbd24867b7..583139cff1 100644 --- a/docs/auth/microsoft/provider.md +++ b/docs/auth/microsoft/provider.md @@ -46,11 +46,18 @@ The Microsoft provider is a structure with three configuration keys: - `clientSecret`: Secret, found on App Registration > Certificates & secrets - `tenantId`: Directory (tenant) ID, found on App Registration > Overview -In order to finish signing a user in from Azure, the Backstage backend must -fetch their information from graph.microsoft.com (as seen in [this source -code](https://github.com/seanfisher/passport-microsoft/blob/0456aa9bce05579c18e77f51330176eb26373658/lib/strategy.js#L93-L95)), -so ensure that your Backstage backend has connectivity to this host. -Otherwise users may see an `Authentication failed, failed to fetch user profile` error when they attempt to log in. +## Outbound Network Access + +If your environment has restrictions on outgoing access (e.g. through +firewall rules), make sure your Backstage backend has access to the following +hosts: + +- `login.microsoftonline.com`, to get and exchange authorization codes and access + tokens +- `graph.microsoft.com`, to fetch user profile information (as seen + in [this source + code](https://github.com/seanfisher/passport-microsoft/blob/0456aa9bce05579c18e77f51330176eb26373658/lib/strategy.js#L93-L95)). + If this host is unreachable, users may see an `Authentication failed, failed to fetch user profile` error when they attempt to log in. ## Adding the provider to the Backstage frontend diff --git a/docs/deployment/docker.md b/docs/deployment/docker.md index 04a509d316..0b28e4d506 100644 --- a/docs/deployment/docker.md +++ b/docs/deployment/docker.md @@ -108,10 +108,13 @@ root of the repo to speed up the build by reducing build context size: ```text .git +.yarn/cache +.yarn/install-state.gz node_modules packages/*/src packages/*/node_modules plugins +*.local.yaml ``` With the project built and the `.dockerignore` and `Dockerfile` in place, we are diff --git a/docs/dls/component-design-guidelines.md b/docs/dls/component-design-guidelines.md new file mode 100644 index 0000000000..65eef4c057 --- /dev/null +++ b/docs/dls/component-design-guidelines.md @@ -0,0 +1,108 @@ +--- +id: component-design-guidelines +title: Component Design Guidelines +description: Documentation on Design +--- + +Be it a new component contribution, or plugin specific components, you'll want +to follow these guidelines. We'll cover the three main subjects that define the +general look and feel of your components, all of which build on top of the +Material-UI theme features: + +- Layout +- Color palette +- Typography + +## 🏗️ Layout + +Layout refers to how you organize or stack content. Whenever possible, we want +to use Backstage's components (check the [Storybook][1] for a list and demo) +first, and otherwise fall back to Material-UI components (check the [MUI docs][2]). + +If none of these fit your layout needs, then you can build your own components. +However, using HTML+CSS directly is not recommended; it's better to use MUI +layout components to make your layout theme aware, meaning if someone changes +the theme, your layout would react to those changes without requiring updates +to your code. + +Specifically you want to look at these components that make use of the +`theme.spacing()` function for margins, paddings and positions, as well as +color palette and typography: + +- [Container][3] mostly at page level +- [Box][4] like a div that can be customized a lot +- [Grid][5] for flexible grid layouts +- [Paper][6] The base of a card, like it's background & padding on the borders +- [Card][7] Card with support for title, description, buttons, images... + +## Color palette + +If you're using an existing component and want to tweak the colors it uses in +general in the whole application, you can use a [Custom Theme][10] to override +specific styles for that component, that includes paddings, margins and colors. + +However when making a component from scratch you'll need to reference the theme +as much as possible, make sure to use the theme's color palette. Most Backstage +components and all MUI components should use the theme's color palette by default, +so unless you need explicit control on the color of a component (say when the +component was designed to use the primary color but you want to use the +secondary color instead), then the easiest way to access the color palette is +to [Override the Component Styles][11] as suggested by Backstage. + +It's not a very common use case to override a theme color in a MUI component +but let's say you have a custom Sidebar component with a Paper component that +highlights its content with a different color for a side menu or something +(usually you use the elevation, but maybe the designer wanted a colorful app). +You can use the theme like this: + +```tsx +import { makeStyles, Paper } from '@material-ui/core'; + +const useStyles = makeStyles((theme: Theme) => ({ + sidebarPaper: { + backgroundColor: theme.palette.primary.main, + color: theme.palette.primary.contrastText, + }, +})); + +export function Sidebar({ children }) { + const { sidebarPaper } = useStyles(); + return {children}; +} +``` + +Here is a link to the [Default Palette values][8] you can use, the tokens will +be the same, what changes are the colors associated with those depending on your +app theme color palette, there's also a [Default Theme Explorer][12] to look +which tokens you can use as reference from the compiled theme. + +## Typography + +Most of the time the components from MUI will use the `` component +which will use the theme's typography properties like font family, size, weight +and appropriate color from the palette for the context of that component. This applies for example to +buttons that use white font color for contained buttons, or the respective color +passed on via props when not outlined for proper contrast (buttons in dark +theme adapt properly by using a dark font instead of white). + +However for those cases where the parent component of the content doesn't handle +the text, like when the parent component is a layout one, you use typography +component instead of the HTML counterparts, usually used for titles and +paragraphs but it is valid for any type of text. + +Check the [Typography docs][9] for information on how to install, use, +customize semantic elements and specially the recommendations about +accessibility. + +[1]: http://backstage.io/storybook +[2]: https://v4.mui.com/getting-started/supported-components/ +[3]: https://v4.mui.com/components/container/ +[4]: https://v4.mui.com/components/box/ +[5]: https://v4.mui.com/components/grid/ +[6]: https://v4.mui.com/components/paper/ +[7]: https://v4.mui.com/components/cards/ +[8]: https://v4.mui.com/customization/palette/#default-values +[9]: https://v4.mui.com/customization/typography/ +[10]: https://backstage.io/docs/getting-started/app-custom-theme +[11]: https://backstage.io/docs/getting-started/app-custom-theme#overriding-backstage-and-material-ui-components-styles +[12]: https://v4.mui.com/customization/default-theme/#explore diff --git a/docs/features/kubernetes/installation.md b/docs/features/kubernetes/installation.md index 5b4e2fa716..616991123d 100644 --- a/docs/features/kubernetes/installation.md +++ b/docs/features/kubernetes/installation.md @@ -102,7 +102,7 @@ If either existing don't work for your use-case, it is possible to implement a custom [KubernetesClustersSupplier](https://backstage.io/docs/reference/plugin-kubernetes-backend.kubernetesclusterssupplier). -Change the following in `packages/backend/src/plugin/kubernetes.ts`: +Change the following in `packages/backend/src/plugins/kubernetes.ts`: ```diff -import { KubernetesBuilder } from '@backstage/plugin-kubernetes-backend'; diff --git a/docs/integrations/azure/org.md b/docs/integrations/azure/org.md index 99c517b568..acb43db182 100644 --- a/docs/integrations/azure/org.md +++ b/docs/integrations/azure/org.md @@ -101,7 +101,7 @@ To grant the managed identity the same permissions as mentioned in _App Registra ## Filtering imported Users and Groups By default, the plugin will import all users and groups from your directory. -This can be customized through filters and search queries. +This can be customized through [filters](https://learn.microsoft.com/en-us/graph/filter-query-parameter) and [search](https://learn.microsoft.com/en-us/graph/search-query-parameter) queries. ### Groups @@ -228,6 +228,17 @@ export async function myOrganizationTransformer( ## Troubleshooting +### No data + +First check your logs for the message `Reading msgraph users and groups`. +If you don't see this, check you've registered the provider, and that the schedule is valid + +If you see a log entry `Read 0 msgraph users and 0 msgraph groups`, check your search and filter arguments. + +If you see the start message (`Reading msgraph users and groups`) but no end message (`Read X msgraph users and Y msgraph groups`), then it is likely the job is taking a long time due to a large volume of data. +The default behavior is to import all users and groups, which is often more data than needed. +Try importing a smaller set of data (e.g. `filter: displayName eq 'John Smith'`). + ### Authentication / Token Errors See [Troubleshooting Azure Identity Authentication Issues](https://aka.ms/azsdk/js/identity/troubleshoot) diff --git a/docs/integrations/bitbucketCloud/discovery.md b/docs/integrations/bitbucketCloud/discovery.md index 9b9bc4ecde..f6ceab9ff7 100644 --- a/docs/integrations/bitbucketCloud/discovery.md +++ b/docs/integrations/bitbucketCloud/discovery.md @@ -24,10 +24,12 @@ package. yarn add --cwd packages/backend @backstage/plugin-catalog-backend-module-bitbucket-cloud ``` +### Installation without Events Support + And then add the entity provider to your catalog builder: ```diff - // In packages/backend/src/plugins/catalog.ts +// packages/backend/src/plugins/catalog.ts + import { BitbucketCloudEntityProvider } from '@backstage/plugin-catalog-backend-module-bitbucket-cloud'; export default async function createPlugin( @@ -37,11 +39,7 @@ And then add the entity provider to your catalog builder: + builder.addEntityProvider( + BitbucketCloudEntityProvider.fromConfig(env.config, { + logger: env.logger, -+ // optional: alternatively, configure via app-config.yaml -+ schedule: env.scheduler.createScheduledTaskRunner({ -+ frequency: { minutes: 30 }, -+ timeout: { minutes: 3 }, -+ }), ++ scheduler: env.scheduler, + }), + ); @@ -49,6 +47,62 @@ And then add the entity provider to your catalog builder: } ``` +Alternatively to the config-based schedule, you can use + +```diff +- scheduler: env.scheduler, ++ schedule: env.scheduler.createScheduledTaskRunner({ ++ frequency: { minutes: 30 }, ++ timeout: { minutes: 3 }, ++ }), +``` + +### Installation with Events Support + +Please follow the installation instructions at + +- https://github.com/backstage/backstage/tree/master/plugins/events-backend/README.md +- https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-bitbucket-cloud/README.md + +Additionally, you need to decide how you want to receive events from external sources like + +- [via HTTP endpoint](https://github.com/backstage/backstage/tree/master/plugins/events-backend/README.md) +- [via an AWS SQS queue](https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-aws-sqs/README.md) + +Set up your provider + +```diff +// packages/backend/src/plugins/catalogEventBasedProviders.ts ++import { CatalogClient } from '@backstage/catalog-client'; ++import { BitbucketCloudEntityProvider } from '@backstage/plugin-catalog-backend-module-bitbucket-cloud'; + import { EntityProvider } from '@backstage/plugin-catalog-node'; + import { EventSubscriber } from '@backstage/plugin-events-node'; + import { PluginEnvironment } from '../types'; + + export default async function createCatalogEventBasedProviders( +- _: PluginEnvironment, ++ env: PluginEnvironment, + ): Promise> { + const providers: Array< + (EntityProvider & EventSubscriber) | Array + > = []; +- // add your event-based entity providers here ++ providers.push( ++ BitbucketCloudEntityProvider.fromConfig(env.config, { ++ catalogApi: new CatalogClient({ discoveryApi: env.discovery }), ++ logger: env.logger, ++ scheduler: env.scheduler, ++ tokenManager: env.tokenManager, ++ }), ++ ); + return providers.flat(); + } +``` + +**Attention:** +`catalogApi` and `tokenManager` are required at this variant +compared to the one without events support. + ## Configuration To use the entity provider, you'll need a [Bitbucket Cloud integration set up](locations.md). diff --git a/docs/integrations/github/org.md b/docs/integrations/github/org.md index 8212c254d7..9e3c450adc 100644 --- a/docs/integrations/github/org.md +++ b/docs/integrations/github/org.md @@ -97,6 +97,66 @@ that must be approved first before the changes are applied.** ![email](../../assets/integrations/github/email.png) +### Custom Transformers + +You can inject your own transformation logic to help map from GH API responses +into backstage entities. You can do this on the user and team requests to +enable you to do further processing or updates to the entities. + +To enable this you pass a function into the `GitHubOrgEntityProvider`. You can +pass a `UserTransformer`, `TeamTransformer` or both. The function is invoked +for each item (user or team) that is returned from the API. You can either +return an Entity (User or Group) or `undefined` if you do not want to import +that item. + +There is also a `defaultUserTransformer` and `defaultOrganizationTeamTransformer`. +You could use these and simply decorate the response from the default +transformation if you only need to change a few properties. + +### Resolving GitHub users via organization email + +When you authenticate users you should resolve them to an entity within the +catalog. Often the authentication you use could be a corporate SSO system that +provides you with email as a key. To enable you to find and resolve GitHub users +it's useful to also import the private domain verified emails into the User +entity in backstage. + +The integration attempts to return `organizationVerifiedDomainEmails` from the +GitHub API and makes this available as part of the object passed to +`UserTransformer`. The GitHub API will only return emails that use a domain +that's a verified domain for your GitHub Org. It also relies on the user having +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 +returned identity. + +```typescript +async (user, ctx): Promise => { + const entity = await defaultUserTransformer(user, ctx); + + if (entity && user.organizationVerifiedDomainEmails) { + entity.spec.profile!.email = user.organizationVerifiedDomainEmails[0] || ''; + } + + return entity; +}, +``` + +Once you have imported the emails you can resolve users in your sign-in in +resolver using the catalog entity search via email + +```typescript +// packages/backend/src/plugins/auth.ts +ctx.signInWithCatalogUser({ + filter: { + kind: ['User'], + 'spec.profile.email': email as string, + }, +}); +``` + ## Using a Processor instead of a Provider An alternative to using the Provider for ingesting organizational entities is to diff --git a/docs/releases/v1.8.0-next.2-changelog.md b/docs/releases/v1.8.0-next.2-changelog.md new file mode 100644 index 0000000000..d6c55998f6 --- /dev/null +++ b/docs/releases/v1.8.0-next.2-changelog.md @@ -0,0 +1,1903 @@ +# Release v1.8.0-next.2 + +## @backstage/cli@0.21.0-next.1 + +### Minor Changes + +- 384eaa2307: Switched `tsconfig.json` to target and support `ES2021`, in line with the bump to Node.js 16 & 18. + +### Patch Changes + +- 88f99b8b13: Bumped `tar` dependency to `^6.1.12` in order to ensure Node.js v18 compatibility. +- 969a8444ea: Updated dependency `esbuild` to `^0.15.0`. +- Updated dependencies + - @backstage/release-manifests@0.0.7-next.0 + - @backstage/cli-common@0.1.10 + - @backstage/config@1.0.4-next.0 + - @backstage/config-loader@1.1.6-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/types@1.0.1-next.0 + +## @backstage/plugin-org@0.6.0-next.1 + +### Minor Changes + +- 0b11500151: Updates the User and Group Profile cards to add the links from the UserEntity or the GroupEntity + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-org-react@0.1.0-next.0 + +### Minor Changes + +- e96274f1fe: Implemented the org-react plugin, with it's first component being: a `GroupListPicker` component that will give the user the ability to choose a group + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-scaffolder-backend@1.8.0-next.2 + +### Minor Changes + +- 5025d2e8b6: Adds the ability to pass (an optional) array of strings that will be applied to the newly scaffolded repository as topic labels. + +### Patch Changes + +- 969a8444ea: Updated dependency `esbuild` to `^0.15.0`. +- 9ff4ff3745: Implement "Branch protection rules" support for "publish:github" action +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/types@1.0.1-next.0 + - @backstage/plugin-scaffolder-common@1.2.2-next.0 + +## @backstage/plugin-splunk-on-call@0.4.0-next.1 + +### Minor Changes + +- 34b772ef31: Use the routing key if it's available instead of team name when triggering incidents. + + BREAKING CHANGE: + Before, the team name was used even if the routing key (with or without team) was used. + Now, the routing key defined for the component will be used instead of the team name. + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/app-defaults@1.0.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-app-api@1.2.0-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-permission-react@0.4.7-next.0 + +## @backstage/backend-app-api@0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-permission-node@0.7.1-next.1 + - @backstage/errors@1.1.3-next.0 + +## @backstage/backend-common@0.16.0-next.1 + +### Patch Changes + +- 88f99b8b13: Bumped `tar` dependency to `^6.1.12` in order to ensure Node.js v18 compatibility. +- cfb30b700c: Pin `@kubernetes/client-node` version to `0.17.0`. +- Updated dependencies + - @backstage/cli-common@0.1.10 + - @backstage/config@1.0.4-next.0 + - @backstage/config-loader@1.1.6-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/types@1.0.1-next.0 + +## @backstage/backend-defaults@0.1.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-app-api@0.2.3-next.1 + - @backstage/backend-plugin-api@0.1.4-next.1 + +## @backstage/backend-plugin-api@0.1.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/plugin-permission-common@0.7.1-next.0 + +## @backstage/backend-tasks@0.3.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/types@1.0.1-next.0 + +## @backstage/backend-test-utils@0.1.30-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/cli@0.21.0-next.1 + - @backstage/backend-app-api@0.2.3-next.1 + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/config@1.0.4-next.0 + +## @backstage/codemods@0.1.41-next.0 + +### Patch Changes + +- 58502ec285: Updated dependency `jscodeshift` to `^0.14.0`. +- Updated dependencies + - @backstage/cli-common@0.1.10 + +## @backstage/core-components@0.12.0-next.1 + +### Patch Changes + +- b4fb5c8ecc: MissingAnnotationEmptyState now accepts either a string or an array of strings to support multiple missing annotations. +- Updated dependencies + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/version-bridge@1.0.1 + +## @backstage/create-app@0.4.34-next.2 + +### Patch Changes + +- 384eaa2307: Switched Node.js version to support version 16 & 18, rather than 14 & 16. To switch the Node.js version in your own project, apply the following change to the root `package.json`: + + ```diff + "engines": { + - "node": "14 || 16" + + "node": "16 || 18" + }, + ``` + + As well as the following change to `packages/app/package.json`: + + ```diff + - "@types/node": "^14.14.32", + + "@types/node": "^16.11.26", + ``` + +- 864c876e57: Fixed incorrect comments in the templated `app-config.yaml` and `app-config.production.yaml`. The `backend.listen` directive is not in fact needed to override the `backend.baseUrl`, the backend listens to all interfaces by default. The configuration has also been updated to listen to all interfaces, rather than just IPv4 ones, as this is required for Node.js v18. The production configuration now also shows the option to specify `backend.listen` as a single string. + + To apply this changes to an existing app, make the following change to `app-config.yaml`: + + ```diff + - # Uncomment the following host directive to bind to all IPv4 interfaces and + - # not just the baseUrl hostname. + - # host: 0.0.0.0 + + # Uncomment the following host directive to bind to specific interfaces + + # host: 127.0.0.1 + ``` + + And the following change to `app-config.production.yaml`: + + ```diff + - listen: + - port: 7007 + - # The following host directive binds to all IPv4 interfaces when its value + - # is "0.0.0.0". This is the most permissive setting. The right value depends + - # on your specific deployment. If you remove the host line entirely, the + - # backend will bind on the interface that corresponds to the backend.baseUrl + - # hostname. + - host: 0.0.0.0 + + # The listener can also be expressed as a single : string. In this case we bind to + + # all interfaces, the most permissive setting. The right value depends on your specific deployment. + + listen: ':7007' + ``` + +- Updated dependencies + - @backstage/cli-common@0.1.10 + +## @backstage/dev-utils@1.0.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/app-defaults@1.0.8-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-app-api@1.2.0-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/integration-react@1.1.6-next.1 + - @backstage/test-utils@1.2.2-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/integration-react@1.1.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/theme@0.2.16 + +## @backstage/release-manifests@0.0.7-next.0 + +### Patch Changes + +- a4496131fa: Added a fallback that fetches manifests from `https://raw.githubusercontent.com` if `https://versions.backstage.io` is unavailable. + +## @techdocs/cli@1.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-techdocs-node@1.4.2-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/cli-common@0.1.10 + - @backstage/config@1.0.4-next.0 + +## @backstage/plugin-adr@0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/integration-react@1.1.6-next.1 + - @backstage/theme@0.2.16 + - @backstage/plugin-adr-common@0.2.3-next.0 + - @backstage/plugin-catalog-react@1.2.1-next.1 + - @backstage/plugin-search-common@1.1.1-next.0 + - @backstage/plugin-search-react@1.2.1-next.1 + +## @backstage/plugin-adr-backend@0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/plugin-adr-common@0.2.3-next.0 + - @backstage/plugin-search-common@1.1.1-next.0 + +## @backstage/plugin-airbrake@0.3.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/dev-utils@1.0.8-next.1 + - @backstage/test-utils@1.2.2-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-airbrake-backend@0.2.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/config@1.0.4-next.0 + +## @backstage/plugin-allure@0.1.27-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-analytics-module-ga@0.1.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + +## @backstage/plugin-apache-airflow@0.2.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + +## @backstage/plugin-api-docs@0.8.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog@1.6.1-next.1 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-apollo-explorer@0.1.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + +## @backstage/plugin-app-backend@0.3.38-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/config-loader@1.1.6-next.0 + - @backstage/types@1.0.1-next.0 + +## @backstage/plugin-auth-backend@0.17.1-next.1 + +### Patch Changes + +- 0d6837ca4e: Fix wrong GitHub callback URL documentation +- abaed9770e: Improve logging +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/types@1.0.1-next.0 + +## @backstage/plugin-auth-node@0.2.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + +## @backstage/plugin-azure-devops@0.2.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-azure-devops-common@0.3.0 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-azure-devops-backend@0.3.17-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/plugin-azure-devops-common@0.3.0 + +## @backstage/plugin-azure-sites@0.1.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-azure-sites-common@0.1.0-next.0 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-azure-sites-backend@0.1.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/plugin-azure-sites-common@0.1.0-next.0 + +## @backstage/plugin-badges@0.2.35-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-badges-backend@0.1.32-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + +## @backstage/plugin-bazaar@0.2.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.21.0-next.1 + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/plugin-catalog@1.6.1-next.1 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-bazaar-backend@0.2.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-test-utils@0.1.30-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + +## @backstage/plugin-bitrise@0.1.38-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-catalog@1.6.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration-react@1.1.6-next.1 + - @backstage/theme@0.2.16 + - @backstage/types@1.0.1-next.0 + - @backstage/plugin-catalog-common@1.0.8-next.0 + - @backstage/plugin-catalog-react@1.2.1-next.1 + - @backstage/plugin-search-common@1.1.1-next.0 + - @backstage/plugin-search-react@1.2.1-next.1 + +## @backstage/plugin-catalog-backend@1.5.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/plugin-permission-node@0.7.1-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/types@1.0.1-next.0 + - @backstage/plugin-catalog-common@1.0.8-next.0 + - @backstage/plugin-permission-common@0.7.1-next.0 + - @backstage/plugin-scaffolder-common@1.2.2-next.0 + - @backstage/plugin-search-common@1.1.1-next.0 + +## @backstage/plugin-catalog-backend-module-aws@0.1.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/types@1.0.1-next.0 + +## @backstage/plugin-catalog-backend-module-azure@0.1.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/types@1.0.1-next.0 + +## @backstage/plugin-catalog-backend-module-bitbucket@0.2.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/types@1.0.1-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.1-next.0 + +## @backstage/plugin-catalog-backend-module-bitbucket-cloud@0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.1-next.0 + +## @backstage/plugin-catalog-backend-module-bitbucket-server@0.1.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + +## @backstage/plugin-catalog-backend-module-gerrit@0.1.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + +## @backstage/plugin-catalog-backend-module-github@0.2.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/types@1.0.1-next.0 + +## @backstage/plugin-catalog-backend-module-gitlab@0.1.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/types@1.0.1-next.0 + +## @backstage/plugin-catalog-backend-module-ldap@0.5.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/types@1.0.1-next.0 + +## @backstage/plugin-catalog-backend-module-msgraph@0.4.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + +## @backstage/plugin-catalog-backend-module-openapi@0.1.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/types@1.0.1-next.0 + +## @backstage/plugin-catalog-graph@0.2.23-next.1 + +### Patch Changes + +- da0bf25d1a: Preserve graph options and increment `maxDepth` by 1. + + The change will preserve options used at the `CatalogGraphCard` + (displayed at the entity page) and additionally, increments the + `maxDepth` option by 1 to increase the scope slightly compared to + the graph already seen by the users. + + The default for `maxDepth` at `CatalogGraphCard` is 1. + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-catalog-import@0.9.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/integration-react@1.1.6-next.1 + - @backstage/plugin-catalog-common@1.0.8-next.0 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-catalog-node@1.2.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/types@1.0.1-next.0 + - @backstage/plugin-catalog-common@1.0.8-next.0 + +## @backstage/plugin-catalog-react@1.2.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/types@1.0.1-next.0 + - @backstage/version-bridge@1.0.1 + - @backstage/plugin-catalog-common@1.0.8-next.0 + - @backstage/plugin-permission-common@0.7.1-next.0 + - @backstage/plugin-permission-react@0.4.7-next.0 + +## @backstage/plugin-cicd-statistics@0.1.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-cicd-statistics-module-gitlab@0.1.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/plugin-cicd-statistics@0.1.13-next.1 + +## @backstage/plugin-circleci@0.3.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-cloudbuild@0.3.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-code-climate@0.1.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-code-coverage@0.2.4-next.1 + +### Patch Changes + +- fcab2579a0: Adds installation instructions +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-code-coverage-backend@0.2.4-next.1 + +### Patch Changes + +- fcab2579a0: Adds installation instructions +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + +## @backstage/plugin-codescene@0.1.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + +## @backstage/plugin-config-schema@0.1.34-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/types@1.0.1-next.0 + +## @backstage/plugin-cost-insights@0.12.0-next.1 + +### Patch Changes + +- e92aa15f01: Bumped `canvas` dependency to the latest version, which has better Node.js v18 support. +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-cost-insights-common@0.1.1 + +## @backstage/plugin-dynatrace@1.0.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-explore@0.3.42-next.1 + +### Patch Changes + +- 5c25ce6d9e: Added a section to explore plugin README that describes the customization of explore tools content. +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + - @backstage/plugin-explore-react@0.0.23-next.0 + +## @backstage/plugin-firehydrant@0.1.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-fossa@0.2.43-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-gcalendar@0.3.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + +## @backstage/plugin-gcp-projects@0.3.30-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + +## @backstage/plugin-git-release-manager@0.3.24-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/theme@0.2.16 + +## @backstage/plugin-github-actions@0.5.11-next.1 + +### Patch Changes + +- ed438a3ba5: Add error panel when the plugin fails. +- 0d6837ca4e: Fix wrong GitHub callback URL documentation +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-github-deployments@0.1.42-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/integration-react@1.1.6-next.1 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-github-issues@0.2.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-github-pull-requests-board@0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-gitops-profiles@0.3.29-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + +## @backstage/plugin-gocd@0.1.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-graphiql@0.2.43-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + +## @backstage/plugin-graphql-backend@0.1.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/plugin-catalog-graphql@0.3.15-next.0 + +## @backstage/plugin-home@0.4.27-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + - @backstage/plugin-stack-overflow@0.1.7-next.1 + +## @backstage/plugin-ilert@0.2.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-jenkins@0.7.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + - @backstage/plugin-jenkins-common@0.1.10-next.0 + +## @backstage/plugin-jenkins-backend@0.1.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/plugin-jenkins-common@0.1.10-next.0 + - @backstage/plugin-permission-common@0.7.1-next.0 + +## @backstage/plugin-kafka@0.3.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-kafka-backend@0.2.31-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + +## @backstage/plugin-kubernetes@0.7.4-next.1 + +### Patch Changes + +- cfb30b700c: Pin `@kubernetes/client-node` version to `0.17.0`. +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/plugin-kubernetes-common@0.4.4-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-kubernetes-backend@0.8.0-next.1 + +### Patch Changes + +- cfb30b700c: Pin `@kubernetes/client-node` version to `0.17.0`. +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-kubernetes-common@0.4.4-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + +## @backstage/plugin-kubernetes-common@0.4.4-next.1 + +### Patch Changes + +- cfb30b700c: Pin `@kubernetes/client-node` version to `0.17.0`. +- Updated dependencies + - @backstage/catalog-model@1.1.3-next.0 + +## @backstage/plugin-lighthouse@0.3.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-newrelic@0.3.29-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + +## @backstage/plugin-newrelic-dashboard@0.2.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-pagerduty@0.5.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-periskop@0.1.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-periskop-backend@0.1.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/config@1.0.4-next.0 + +## @backstage/plugin-permission-backend@0.5.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/plugin-permission-node@0.7.1-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/plugin-permission-common@0.7.1-next.0 + +## @backstage/plugin-permission-node@0.7.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/plugin-permission-common@0.7.1-next.0 + +## @backstage/plugin-playlist@0.1.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-common@1.0.8-next.0 + - @backstage/plugin-catalog-react@1.2.1-next.1 + - @backstage/plugin-permission-common@0.7.1-next.0 + - @backstage/plugin-permission-react@0.4.7-next.0 + - @backstage/plugin-playlist-common@0.1.2-next.0 + - @backstage/plugin-search-react@1.2.1-next.1 + +## @backstage/plugin-playlist-backend@0.2.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-test-utils@0.1.30-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/plugin-permission-node@0.7.1-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/plugin-permission-common@0.7.1-next.0 + - @backstage/plugin-playlist-common@0.1.2-next.0 + +## @backstage/plugin-proxy-backend@0.2.32-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/config@1.0.4-next.0 + +## @backstage/plugin-rollbar@0.4.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-rollbar-backend@0.1.35-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/config@1.0.4-next.0 + +## @backstage/plugin-scaffolder@1.8.0-next.1 + +### Patch Changes + +- 580285787d: The `create` and `click` analytics events are now also captured on the "next" version of the component creation page. +- 3b3fc3cc3c: Fix `formData` not being present in the `next` version +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/integration-react@1.1.6-next.1 + - @backstage/theme@0.2.16 + - @backstage/types@1.0.1-next.0 + - @backstage/plugin-catalog-common@1.0.8-next.0 + - @backstage/plugin-catalog-react@1.2.1-next.1 + - @backstage/plugin-permission-react@0.4.7-next.0 + - @backstage/plugin-scaffolder-common@1.2.2-next.0 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.2.13-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-scaffolder-backend@1.8.0-next.2 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/types@1.0.1-next.0 + +## @backstage/plugin-scaffolder-backend-module-rails@0.4.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-scaffolder-backend@1.8.0-next.2 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/types@1.0.1-next.0 + +## @backstage/plugin-scaffolder-backend-module-yeoman@0.2.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.8.0-next.2 + - @backstage/config@1.0.4-next.0 + - @backstage/types@1.0.1-next.0 + +## @backstage/plugin-search@1.0.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/types@1.0.1-next.0 + - @backstage/version-bridge@1.0.1 + - @backstage/plugin-catalog-react@1.2.1-next.1 + - @backstage/plugin-search-common@1.1.1-next.0 + - @backstage/plugin-search-react@1.2.1-next.1 + +## @backstage/plugin-search-backend@1.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/plugin-permission-node@0.7.1-next.1 + - @backstage/plugin-search-backend-node@1.0.4-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/types@1.0.1-next.0 + - @backstage/plugin-permission-common@0.7.1-next.0 + - @backstage/plugin-search-common@1.1.1-next.0 + +## @backstage/plugin-search-backend-module-elasticsearch@1.0.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-backend-node@1.0.4-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/plugin-search-common@1.1.1-next.0 + +## @backstage/plugin-search-backend-module-pg@0.4.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-search-backend-node@1.0.4-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/plugin-search-common@1.1.1-next.0 + +## @backstage/plugin-search-backend-node@1.0.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/plugin-permission-common@0.7.1-next.0 + - @backstage/plugin-search-common@1.1.1-next.0 + +## @backstage/plugin-search-react@1.2.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/types@1.0.1-next.0 + - @backstage/version-bridge@1.0.1 + - @backstage/plugin-search-common@1.1.1-next.0 + +## @backstage/plugin-sentry@0.4.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-shortcuts@0.3.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/types@1.0.1-next.0 + +## @backstage/plugin-sonarqube@0.4.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-sonarqube-backend@0.1.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + +## @backstage/plugin-stack-overflow@0.1.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-home@0.4.27-next.1 + - @backstage/plugin-search-common@1.1.1-next.0 + +## @backstage/plugin-stack-overflow-backend@0.1.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.21.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/plugin-search-common@1.1.1-next.0 + +## @backstage/plugin-tech-insights@0.3.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/types@1.0.1-next.0 + - @backstage/plugin-catalog-react@1.2.1-next.1 + - @backstage/plugin-tech-insights-common@0.2.8-next.0 + +## @backstage/plugin-tech-insights-backend@0.5.4-next.1 + +### Patch Changes + +- f12e9e5b8c: Add Documentation on 404 Errors +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-tech-insights-node@0.3.6-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/types@1.0.1-next.0 + - @backstage/plugin-tech-insights-common@0.2.8-next.0 + +## @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-tech-insights-node@0.3.6-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/plugin-tech-insights-common@0.2.8-next.0 + +## @backstage/plugin-tech-insights-node@0.3.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/types@1.0.1-next.0 + - @backstage/plugin-tech-insights-common@0.2.8-next.0 + +## @backstage/plugin-tech-radar@0.5.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + +## @backstage/plugin-techdocs@1.4.0-next.2 + +### Patch Changes + +- e92aa15f01: Bumped `canvas` dependency to the latest version, which has better Node.js v18 support. +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/integration-react@1.1.6-next.1 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + - @backstage/plugin-search-common@1.1.1-next.0 + - @backstage/plugin-search-react@1.2.1-next.1 + - @backstage/plugin-techdocs-react@1.0.6-next.1 + +## @backstage/plugin-techdocs-addons-test-utils@1.0.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.4.0-next.2 + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-app-api@1.2.0-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/integration-react@1.1.6-next.1 + - @backstage/test-utils@1.2.2-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog@1.6.1-next.1 + - @backstage/plugin-search-react@1.2.1-next.1 + - @backstage/plugin-techdocs-react@1.0.6-next.1 + +## @backstage/plugin-techdocs-backend@1.4.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-techdocs-node@1.4.2-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/plugin-catalog-common@1.0.8-next.0 + - @backstage/plugin-permission-common@0.7.1-next.0 + - @backstage/plugin-search-common@1.1.1-next.0 + +## @backstage/plugin-techdocs-module-addons-contrib@1.0.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/integration-react@1.1.6-next.1 + - @backstage/theme@0.2.16 + - @backstage/plugin-techdocs-react@1.0.6-next.1 + +## @backstage/plugin-techdocs-node@1.4.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/plugin-search-common@1.1.1-next.0 + +## @backstage/plugin-techdocs-react@1.0.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/version-bridge@1.0.1 + +## @backstage/plugin-todo@0.2.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-todo-backend@0.1.35-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + +## @backstage/plugin-user-settings@0.5.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-app-api@1.2.0-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/types@1.0.1-next.0 + +## @backstage/plugin-user-settings-backend@0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/types@1.0.1-next.0 + +## @backstage/plugin-vault@0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + +## @backstage/plugin-vault-backend@0.2.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/backend-test-utils@0.1.30-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + +## @backstage/plugin-xcmetrics@0.2.31-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + +## example-app@0.2.77-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder@1.8.0-next.1 + - @backstage/plugin-cost-insights@0.12.0-next.1 + - @backstage/plugin-techdocs@1.4.0-next.2 + - @backstage/plugin-explore@0.3.42-next.1 + - @backstage/plugin-github-actions@0.5.11-next.1 + - @backstage/cli@0.21.0-next.1 + - @backstage/plugin-catalog-graph@0.2.23-next.1 + - @backstage/core-components@0.12.0-next.1 + - @backstage/plugin-code-coverage@0.2.4-next.1 + - @backstage/plugin-org@0.6.0-next.1 + - @backstage/plugin-kubernetes@0.7.4-next.1 + - @backstage/app-defaults@1.0.8-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-app-api@1.2.0-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/integration-react@1.1.6-next.1 + - @backstage/theme@0.2.16 + - @backstage/plugin-airbrake@0.3.11-next.1 + - @backstage/plugin-apache-airflow@0.2.4-next.1 + - @backstage/plugin-api-docs@0.8.11-next.1 + - @backstage/plugin-azure-devops@0.2.2-next.1 + - @backstage/plugin-azure-sites@0.1.0-next.1 + - @backstage/plugin-badges@0.2.35-next.1 + - @backstage/plugin-catalog-common@1.0.8-next.0 + - @backstage/plugin-catalog-import@0.9.1-next.1 + - @backstage/plugin-catalog-react@1.2.1-next.1 + - @backstage/plugin-circleci@0.3.11-next.1 + - @backstage/plugin-cloudbuild@0.3.11-next.1 + - @backstage/plugin-dynatrace@1.0.1-next.1 + - @backstage/plugin-gcalendar@0.3.7-next.1 + - @backstage/plugin-gcp-projects@0.3.30-next.1 + - @backstage/plugin-gocd@0.1.17-next.1 + - @backstage/plugin-graphiql@0.2.43-next.1 + - @backstage/plugin-home@0.4.27-next.1 + - @backstage/plugin-jenkins@0.7.10-next.1 + - @backstage/plugin-kafka@0.3.11-next.1 + - @backstage/plugin-lighthouse@0.3.11-next.1 + - @backstage/plugin-newrelic@0.3.29-next.1 + - @backstage/plugin-newrelic-dashboard@0.2.4-next.1 + - @backstage/plugin-pagerduty@0.5.4-next.1 + - @backstage/plugin-permission-react@0.4.7-next.0 + - @backstage/plugin-playlist@0.1.2-next.2 + - @backstage/plugin-rollbar@0.4.11-next.1 + - @backstage/plugin-search@1.0.4-next.1 + - @backstage/plugin-search-common@1.1.1-next.0 + - @backstage/plugin-search-react@1.2.1-next.1 + - @backstage/plugin-sentry@0.4.4-next.1 + - @backstage/plugin-shortcuts@0.3.3-next.1 + - @backstage/plugin-stack-overflow@0.1.7-next.1 + - @backstage/plugin-tech-insights@0.3.3-next.1 + - @backstage/plugin-tech-radar@0.5.18-next.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.0.6-next.1 + - @backstage/plugin-techdocs-react@1.0.6-next.1 + - @backstage/plugin-todo@0.2.13-next.1 + - @backstage/plugin-user-settings@0.5.1-next.1 + - @internal/plugin-catalog-customized@0.0.4-next.1 + +## example-backend@0.2.77-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-backend@0.17.1-next.1 + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-scaffolder-backend@1.8.0-next.2 + - @backstage/plugin-code-coverage-backend@0.2.4-next.1 + - @backstage/plugin-kubernetes-backend@0.8.0-next.1 + - @backstage/plugin-tech-insights-backend@0.5.4-next.1 + - example-app@0.2.77-next.2 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-app-backend@0.3.38-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/plugin-azure-devops-backend@0.3.17-next.2 + - @backstage/plugin-azure-sites-backend@0.1.0-next.1 + - @backstage/plugin-badges-backend@0.1.32-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/plugin-graphql-backend@0.1.28-next.1 + - @backstage/plugin-jenkins-backend@0.1.28-next.1 + - @backstage/plugin-kafka-backend@0.2.31-next.1 + - @backstage/plugin-permission-backend@0.5.13-next.1 + - @backstage/plugin-permission-node@0.7.1-next.1 + - @backstage/plugin-playlist-backend@0.2.1-next.2 + - @backstage/plugin-proxy-backend@0.2.32-next.1 + - @backstage/plugin-rollbar-backend@0.1.35-next.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.6-next.2 + - @backstage/plugin-search-backend@1.1.1-next.1 + - @backstage/plugin-search-backend-module-elasticsearch@1.0.4-next.1 + - @backstage/plugin-search-backend-module-pg@0.4.2-next.1 + - @backstage/plugin-search-backend-node@1.0.4-next.1 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.22-next.1 + - @backstage/plugin-tech-insights-node@0.3.6-next.1 + - @backstage/plugin-techdocs-backend@1.4.1-next.1 + - @backstage/plugin-todo-backend@0.1.35-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/plugin-permission-common@0.7.1-next.0 + - @backstage/plugin-search-common@1.1.1-next.0 + +## example-backend-next@0.0.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.8.0-next.2 + - @backstage/plugin-app-backend@0.3.38-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/backend-defaults@0.1.3-next.1 + +## techdocs-cli-embedded-app@0.2.76-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.4.0-next.2 + - @backstage/cli@0.21.0-next.1 + - @backstage/core-components@0.12.0-next.1 + - @backstage/app-defaults@1.0.8-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-app-api@1.2.0-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/integration-react@1.1.6-next.1 + - @backstage/test-utils@1.2.2-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog@1.6.1-next.1 + - @backstage/plugin-techdocs-react@1.0.6-next.1 + +## @internal/plugin-catalog-customized@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 + +## @internal/plugin-todo-list@1.0.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + +## @internal/plugin-todo-list-backend@1.0.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 diff --git a/microsite/data/plugins/announcements.yaml b/microsite/data/plugins/announcements.yaml new file mode 100644 index 0000000000..de80dcf6fe --- /dev/null +++ b/microsite/data/plugins/announcements.yaml @@ -0,0 +1,10 @@ +--- +title: Announcements +author: K-Phoen +authorUrl: https://github.com/K-Phoen +category: Discovery +description: Write and share announcements within Backstage. +documentation: https://github.com/K-Phoen/backstage-plugin-announcements/ +iconUrl: img/plugin-announcements-logo.png +npmPackageName: '@k-phoen/backstage-plugin-announcements' +addedDate: '2022-11-09' diff --git a/microsite/pages/en/community.js b/microsite/pages/en/community.js index 0580ec045a..a5fd5353e0 100644 --- a/microsite/pages/en/community.js +++ b/microsite/pages/en/community.js @@ -149,7 +149,7 @@ const Background = props => { - + Community initiatives @@ -183,6 +183,29 @@ const Background = props => { + + + + Trainings and Certifications + + + + + Introduction to Backstage: Developer Portals Made Easy (LFS142x) + + + This is a course produced and curated by the Linux Foundation. + This course introduces you to Backstage and how to get started + with the project. + + + + Learn more + + + + + diff --git a/microsite/pages/en/index.js b/microsite/pages/en/index.js index 8e963c2453..ab3dabe14e 100644 --- a/microsite/pages/en/index.js +++ b/microsite/pages/en/index.js @@ -31,15 +31,6 @@ class Index extends React.Component { ! - -
- 🤩 Join us for the first{' '} - - BackstageCon - {' '} - on October 24, 2022! -
-
diff --git a/microsite/sidebars.json b/microsite/sidebars.json index f9fdb9ee9a..725290cb69 100644 --- a/microsite/sidebars.json +++ b/microsite/sidebars.json @@ -316,6 +316,7 @@ ], "Designing for Backstage": [ "dls/design", + "dls/component-design-guidelines", "dls/contributing-to-storybook", "dls/figma" ], diff --git a/microsite/static/img/plugin-announcements-logo.png b/microsite/static/img/plugin-announcements-logo.png new file mode 100644 index 0000000000..edb0caf8d9 Binary files /dev/null and b/microsite/static/img/plugin-announcements-logo.png differ diff --git a/mkdocs.yml b/mkdocs.yml index ea2031dac6..f3194f0d61 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -178,6 +178,7 @@ nav: - Heroku: 'deployment/heroku.md' - Designing for Backstage: - Design: 'dls/design.md' + - Component Design Guidelines: 'dls/component-design-guidelines.md' - Contributing to Storybook: 'dls/contributing-to-storybook.md' - Figma: 'dls/figma.md' - API Reference: diff --git a/package.json b/package.json index 11e92b530b..3977bcc18f 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "@types/react": "^17", "@types/react-dom": "^17" }, - "version": "1.8.0-next.1", + "version": "1.8.0-next.2", "dependencies": { "@backstage/errors": "workspace:^", "@manypkg/get-packages": "^1.1.3", diff --git a/packages/app-defaults/CHANGELOG.md b/packages/app-defaults/CHANGELOG.md index 12b6a0894f..aa79c74c87 100644 --- a/packages/app-defaults/CHANGELOG.md +++ b/packages/app-defaults/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/app-defaults +## 1.0.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-app-api@1.2.0-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-permission-react@0.4.7-next.0 + ## 1.0.8-next.0 ### Patch Changes diff --git a/packages/app-defaults/package.json b/packages/app-defaults/package.json index 6658f0a8bd..71d3eb5824 100644 --- a/packages/app-defaults/package.json +++ b/packages/app-defaults/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/app-defaults", "description": "Provides the default wiring of a Backstage App", - "version": "1.0.8-next.0", + "version": "1.0.8-next.1", "publishConfig": { "access": "public", "main": "dist/index.esm.js", diff --git a/packages/app/CHANGELOG.md b/packages/app/CHANGELOG.md index b713987116..5780e61681 100644 --- a/packages/app/CHANGELOG.md +++ b/packages/app/CHANGELOG.md @@ -1,5 +1,68 @@ # example-app +## 0.2.77-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder@1.8.0-next.1 + - @backstage/plugin-cost-insights@0.12.0-next.1 + - @backstage/plugin-techdocs@1.4.0-next.2 + - @backstage/plugin-explore@0.3.42-next.1 + - @backstage/plugin-github-actions@0.5.11-next.1 + - @backstage/cli@0.21.0-next.1 + - @backstage/plugin-catalog-graph@0.2.23-next.1 + - @backstage/core-components@0.12.0-next.1 + - @backstage/plugin-code-coverage@0.2.4-next.1 + - @backstage/plugin-org@0.6.0-next.1 + - @backstage/plugin-kubernetes@0.7.4-next.1 + - @backstage/app-defaults@1.0.8-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-app-api@1.2.0-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/integration-react@1.1.6-next.1 + - @backstage/theme@0.2.16 + - @backstage/plugin-airbrake@0.3.11-next.1 + - @backstage/plugin-apache-airflow@0.2.4-next.1 + - @backstage/plugin-api-docs@0.8.11-next.1 + - @backstage/plugin-azure-devops@0.2.2-next.1 + - @backstage/plugin-azure-sites@0.1.0-next.1 + - @backstage/plugin-badges@0.2.35-next.1 + - @backstage/plugin-catalog-common@1.0.8-next.0 + - @backstage/plugin-catalog-import@0.9.1-next.1 + - @backstage/plugin-catalog-react@1.2.1-next.1 + - @backstage/plugin-circleci@0.3.11-next.1 + - @backstage/plugin-cloudbuild@0.3.11-next.1 + - @backstage/plugin-dynatrace@1.0.1-next.1 + - @backstage/plugin-gcalendar@0.3.7-next.1 + - @backstage/plugin-gcp-projects@0.3.30-next.1 + - @backstage/plugin-gocd@0.1.17-next.1 + - @backstage/plugin-graphiql@0.2.43-next.1 + - @backstage/plugin-home@0.4.27-next.1 + - @backstage/plugin-jenkins@0.7.10-next.1 + - @backstage/plugin-kafka@0.3.11-next.1 + - @backstage/plugin-lighthouse@0.3.11-next.1 + - @backstage/plugin-newrelic@0.3.29-next.1 + - @backstage/plugin-newrelic-dashboard@0.2.4-next.1 + - @backstage/plugin-pagerduty@0.5.4-next.1 + - @backstage/plugin-permission-react@0.4.7-next.0 + - @backstage/plugin-playlist@0.1.2-next.2 + - @backstage/plugin-rollbar@0.4.11-next.1 + - @backstage/plugin-search@1.0.4-next.1 + - @backstage/plugin-search-common@1.1.1-next.0 + - @backstage/plugin-search-react@1.2.1-next.1 + - @backstage/plugin-sentry@0.4.4-next.1 + - @backstage/plugin-shortcuts@0.3.3-next.1 + - @backstage/plugin-stack-overflow@0.1.7-next.1 + - @backstage/plugin-tech-insights@0.3.3-next.1 + - @backstage/plugin-tech-radar@0.5.18-next.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.0.6-next.1 + - @backstage/plugin-techdocs-react@1.0.6-next.1 + - @backstage/plugin-todo@0.2.13-next.1 + - @backstage/plugin-user-settings@0.5.1-next.1 + - @internal/plugin-catalog-customized@0.0.4-next.1 + ## 0.2.77-next.1 ### Patch Changes diff --git a/packages/app/package.json b/packages/app/package.json index 3f93c523a3..b7f7f40b89 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "example-app", - "version": "0.2.77-next.1", + "version": "0.2.77-next.2", "private": true, "backstage": { "role": "frontend" diff --git a/packages/app/public/index.html b/packages/app/public/index.html index 885fb6c228..863566e776 100644 --- a/packages/app/public/index.html +++ b/packages/app/public/index.html @@ -44,24 +44,7 @@ /> <%= config.getString('app.title') %> - <% if (config.has('app.googleAnalyticsTrackingId')) { %> - - - <% } %> <% if (config.has('app.datadogRum')) { %> + <% if (config.has('app.datadogRum')) { %> - - <% } %> diff --git a/packages/dev-utils/CHANGELOG.md b/packages/dev-utils/CHANGELOG.md index 7177a25fb2..bbf36f42bd 100644 --- a/packages/dev-utils/CHANGELOG.md +++ b/packages/dev-utils/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/dev-utils +## 1.0.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/app-defaults@1.0.8-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-app-api@1.2.0-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/integration-react@1.1.6-next.1 + - @backstage/test-utils@1.2.2-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 1.0.8-next.0 ### Patch Changes diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json index 0decdbe985..4e2666e34f 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.8-next.0", + "version": "1.0.8-next.1", "publishConfig": { "access": "public", "main": "dist/index.esm.js", diff --git a/packages/integration-react/CHANGELOG.md b/packages/integration-react/CHANGELOG.md index b396593d12..606b6f0f80 100644 --- a/packages/integration-react/CHANGELOG.md +++ b/packages/integration-react/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/integration-react +## 1.1.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/theme@0.2.16 + ## 1.1.6-next.0 ### Patch Changes diff --git a/packages/integration-react/package.json b/packages/integration-react/package.json index 7efea2e74a..d1a4250efb 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.6-next.0", + "version": "1.1.6-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -45,7 +45,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/packages/integration/package.json b/packages/integration/package.json index bbed7de2d1..07c42eb206 100644 --- a/packages/integration/package.json +++ b/packages/integration/package.json @@ -46,7 +46,7 @@ "@backstage/config-loader": "workspace:^", "@backstage/test-utils": "workspace:^", "@types/luxon": "^3.0.0", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist", diff --git a/packages/release-manifests/CHANGELOG.md b/packages/release-manifests/CHANGELOG.md index 177ea55a5a..6e2de9598f 100644 --- a/packages/release-manifests/CHANGELOG.md +++ b/packages/release-manifests/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/release-manifests +## 0.0.7-next.0 + +### Patch Changes + +- a4496131fa: Added a fallback that fetches manifests from `https://raw.githubusercontent.com` if `https://versions.backstage.io` is unavailable. + ## 0.0.6 ### Patch Changes diff --git a/packages/release-manifests/package.json b/packages/release-manifests/package.json index 949cd2bcd5..6bd8f8ca4d 100644 --- a/packages/release-manifests/package.json +++ b/packages/release-manifests/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/release-manifests", "description": "Helper library for receiving release manifests", - "version": "0.0.6", + "version": "0.0.7-next.0", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { @@ -38,7 +38,7 @@ "@backstage/cli": "workspace:^", "@backstage/test-utils": "workspace:^", "@types/node": "^16.0.0", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/packages/release-manifests/src/manifest.test.ts b/packages/release-manifests/src/manifest.test.ts index 272555df70..6a53f993c8 100644 --- a/packages/release-manifests/src/manifest.test.ts +++ b/packages/release-manifests/src/manifest.test.ts @@ -17,7 +17,11 @@ import { setupServer } from 'msw/node'; import { rest } from 'msw'; import { setupRequestMockHandlers } from '@backstage/test-utils'; -import { getManifestByReleaseLine, getManifestByVersion } from './manifest'; +import { + getManifestByReleaseLine, + getManifestByVersion, + withFallback, +} from './manifest'; describe('Release Manifests', () => { const worker = setupServer(); @@ -86,3 +90,50 @@ describe('Release Manifests', () => { }); }); }); + +describe('withFallback', () => { + it('should use the first value to resolve', async () => { + const fn1 = jest.fn((_s: AbortSignal) => Promise.resolve(1)); + const fn2 = jest.fn((_s: AbortSignal) => Promise.resolve(2)); + await expect(withFallback(fn1, fn2, 100)).resolves.toBe(1); + expect(fn1.mock.lastCall?.[0].aborted).toBe(false); + expect(fn2).not.toHaveBeenCalled(); + }); + + it('should fall back on rejection', async () => { + const fn1 = jest.fn((_s: AbortSignal) => Promise.reject(new Error('1'))); + const fn2 = jest.fn((_s: AbortSignal) => Promise.resolve(2)); + await expect(withFallback(fn1, fn2, 0)).resolves.toBe(2); + expect(fn1.mock.lastCall?.[0].aborted).toBe(true); + expect(fn2.mock.lastCall?.[0].aborted).toBe(false); + }); + + it('should fall back on timeout', async () => { + const fn1 = jest.fn((_s: AbortSignal) => new Promise(() => {})); + const fn2 = jest.fn((_s: AbortSignal) => Promise.resolve(2)); + await expect(withFallback(fn1, fn2, 0)).resolves.toBe(2); + expect(fn1.mock.lastCall?.[0].aborted).toBe(true); + expect(fn2.mock.lastCall?.[0].aborted).toBe(false); + }); + + it('should always reject with the first error', async () => { + const fn1 = jest.fn((_s: AbortSignal) => Promise.reject(new Error('1'))); + const fn2 = jest.fn((_s: AbortSignal) => Promise.reject(new Error('2'))); + await expect(withFallback(fn1, fn2, 0)).rejects.toThrow('1'); + expect(fn1.mock.lastCall?.[0].aborted).toBe(false); + expect(fn2.mock.lastCall?.[0].aborted).toBe(false); + }); + + it('should always reject with the first error even if rejected after', async () => { + const fn1 = jest.fn( + (_s: AbortSignal) => + new Promise((_resolve, reject) => { + setTimeout(() => reject(new Error('1')), 100); + }), + ); + const fn2 = jest.fn((_s: AbortSignal) => Promise.reject(new Error('2'))); + await expect(withFallback(fn1, fn2, 0)).rejects.toThrow('1'); + expect(fn1.mock.lastCall?.[0].aborted).toBe(false); + expect(fn2.mock.lastCall?.[0].aborted).toBe(false); + }); +}); diff --git a/packages/release-manifests/src/manifest.ts b/packages/release-manifests/src/manifest.ts index 955cf7308c..004ccfc77c 100644 --- a/packages/release-manifests/src/manifest.ts +++ b/packages/release-manifests/src/manifest.ts @@ -16,7 +16,9 @@ import fetch from 'cross-fetch'; -const VERSIONS_DOMAIN = 'https://versions.backstage.io'; +const VERSIONS_BASE_URL = 'https://versions.backstage.io'; +const GITHUB_RAW_BASE_URL = + 'https://raw.githubusercontent.com/backstage/versions/main'; /** * Contains mapping between Backstage release and package versions. @@ -35,6 +37,45 @@ export type GetManifestByVersionOptions = { version: string; }; +// Wait for waitMs, or until signal is aborted. +function wait(waitMs: number, signal: AbortSignal) { + return new Promise((resolve, reject) => { + const timeout = setTimeout(() => { + if (!signal.aborted) { + resolve(); + } + }, waitMs); + signal.addEventListener('abort', () => { + clearTimeout(timeout); + reject(new Error('Aborted')); + }); + }); +} + +// Run fn1 and then fn2 after fallbackDelayMs. Whichever one finishes +// first wins, and the other one is aborted through the provided signal. +export async function withFallback( + fn1: (signal: AbortSignal) => Promise, + fn2: (signal: AbortSignal) => Promise, + fallbackDelayMs: number, +): Promise { + const c1 = new AbortController(); + const c2 = new AbortController(); + + const promise1 = fn1(c1.signal).then(res => { + c2.abort(); + return res; + }); + const promise2 = wait(fallbackDelayMs, c2.signal) + .then(() => fn2(c2.signal)) + .then(res => { + c1.abort(); + return res; + }); + + return Promise.any([promise1, promise2]).catch(() => promise1); +} + /** * Returns a release manifest based on supplied version. * @public @@ -42,19 +83,27 @@ export type GetManifestByVersionOptions = { export async function getManifestByVersion( options: GetManifestByVersionOptions, ): Promise { - const url = `${VERSIONS_DOMAIN}/v1/releases/${encodeURIComponent( - options.version, - )}/manifest.json`; - const response = await fetch(url); - if (response.status === 404) { + const versionEnc = encodeURIComponent(options.version); + const res = await withFallback( + signal => + fetch(`${VERSIONS_BASE_URL}/v1/releases/${versionEnc}/manifest.json`, { + signal, + }), + signal => + fetch(`${GITHUB_RAW_BASE_URL}/v1/releases/${versionEnc}/manifest.json`, { + signal, + }), + 500, + ); + if (res.status === 404) { throw new Error(`No release found for ${options.version} version`); } - if (response.status !== 200) { + if (res.status !== 200) { throw new Error( - `Unexpected response status ${response.status} when fetching release from ${url}.`, + `Unexpected response status ${res.status} when fetching release from ${res.url}.`, ); } - return await response.json(); + return res.json(); } /** @@ -72,17 +121,31 @@ export type GetManifestByReleaseLineOptions = { export async function getManifestByReleaseLine( options: GetManifestByReleaseLineOptions, ): Promise { - const url = `${VERSIONS_DOMAIN}/v1/tags/${encodeURIComponent( - options.releaseLine, - )}/manifest.json`; - const response = await fetch(url); - if (response.status === 404) { + const releaseEnc = encodeURIComponent(options.releaseLine); + const res = await withFallback( + signal => + fetch(`${VERSIONS_BASE_URL}/v1/tags/${releaseEnc}/manifest.json`, { + signal, + }), + async signal => { + // The release tags are symlinks, which we need to follow manually when fetching from GitHub. + const baseUrl = `${GITHUB_RAW_BASE_URL}/v1/tags/${releaseEnc}`; + const linkRes = await fetch(baseUrl, { signal }); + if (!linkRes.ok) { + return linkRes; + } + const link = (await linkRes.text()).trim(); + return fetch(new URL(`${link}/manifest.json`, baseUrl), { signal }); + }, + 1000, + ); + if (res.status === 404) { throw new Error(`No '${options.releaseLine}' release line found`); } - if (response.status !== 200) { + if (res.status !== 200) { throw new Error( - `Unexpected response status ${response.status} when fetching release from ${url}.`, + `Unexpected response status ${res.status} when fetching release from ${res.url}.`, ); } - return await response.json(); + return res.json(); } diff --git a/packages/techdocs-cli-embedded-app/CHANGELOG.md b/packages/techdocs-cli-embedded-app/CHANGELOG.md index 35515eb5d2..e6d842d121 100644 --- a/packages/techdocs-cli-embedded-app/CHANGELOG.md +++ b/packages/techdocs-cli-embedded-app/CHANGELOG.md @@ -1,5 +1,24 @@ # techdocs-cli-embedded-app +## 0.2.76-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.4.0-next.2 + - @backstage/cli@0.21.0-next.1 + - @backstage/core-components@0.12.0-next.1 + - @backstage/app-defaults@1.0.8-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-app-api@1.2.0-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/integration-react@1.1.6-next.1 + - @backstage/test-utils@1.2.2-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog@1.6.1-next.1 + - @backstage/plugin-techdocs-react@1.0.6-next.1 + ## 0.2.76-next.1 ### Patch Changes diff --git a/packages/techdocs-cli-embedded-app/package.json b/packages/techdocs-cli-embedded-app/package.json index 740889a661..4006fbe4c9 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.76-next.1", + "version": "0.2.76-next.2", "private": true, "backstage": { "role": "frontend" diff --git a/packages/techdocs-cli/CHANGELOG.md b/packages/techdocs-cli/CHANGELOG.md index 26f085b6ce..3e39ba06d3 100644 --- a/packages/techdocs-cli/CHANGELOG.md +++ b/packages/techdocs-cli/CHANGELOG.md @@ -1,5 +1,16 @@ # @techdocs/cli +## 1.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-techdocs-node@1.4.2-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/cli-common@0.1.10 + - @backstage/config@1.0.4-next.0 + ## 1.2.3-next.0 ### Patch Changes diff --git a/packages/techdocs-cli/package.json b/packages/techdocs-cli/package.json index 10b738c025..615651d6f9 100644 --- a/packages/techdocs-cli/package.json +++ b/packages/techdocs-cli/package.json @@ -1,7 +1,7 @@ { "name": "@techdocs/cli", "description": "Utility CLI for managing TechDocs sites in Backstage.", - "version": "1.2.3-next.0", + "version": "1.2.3-next.1", "publishConfig": { "access": "public" }, diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index 70e6dca4cc..b9c164b97d 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -57,7 +57,7 @@ "devDependencies": { "@backstage/cli": "workspace:^", "@types/node": "^16.11.26", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/packages/version-bridge/src/lib/VersionedValue.ts b/packages/version-bridge/src/lib/VersionedValue.ts index b7c2153e38..51a9fd7879 100644 --- a/packages/version-bridge/src/lib/VersionedValue.ts +++ b/packages/version-bridge/src/lib/VersionedValue.ts @@ -36,9 +36,17 @@ export function createVersionedValueMap< Versions extends { [version: number]: unknown }, >(versions: Versions): VersionedValue { Object.freeze(versions); - return { + const versionedValue: VersionedValue = { atVersion(version) { return versions[version]; }, }; + Object.defineProperty(versionedValue, '$map', { + configurable: true, + enumerable: true, + get() { + return versions; + }, + }); + return versionedValue; } diff --git a/plugins/adr-backend/CHANGELOG.md b/plugins/adr-backend/CHANGELOG.md index 84143ccf78..4b3c7bf9d6 100644 --- a/plugins/adr-backend/CHANGELOG.md +++ b/plugins/adr-backend/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-adr-backend +## 0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/plugin-adr-common@0.2.3-next.0 + - @backstage/plugin-search-common@1.1.1-next.0 + ## 0.2.3-next.0 ### Patch Changes diff --git a/plugins/adr-backend/package.json b/plugins/adr-backend/package.json index ccbd3f119e..7ab4aab172 100644 --- a/plugins/adr-backend/package.json +++ b/plugins/adr-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-adr-backend", - "version": "0.2.3-next.0", + "version": "0.2.3-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -46,7 +46,7 @@ "@backstage/cli": "workspace:^", "@types/marked": "^4.0.0", "@types/supertest": "^2.0.8", - "msw": "^0.47.0", + "msw": "^0.48.0", "supertest": "^6.1.3" }, "files": [ diff --git a/plugins/adr/CHANGELOG.md b/plugins/adr/CHANGELOG.md index e1f34381e4..018b90a5dd 100644 --- a/plugins/adr/CHANGELOG.md +++ b/plugins/adr/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-adr +## 0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/integration-react@1.1.6-next.1 + - @backstage/theme@0.2.16 + - @backstage/plugin-adr-common@0.2.3-next.0 + - @backstage/plugin-catalog-react@1.2.1-next.1 + - @backstage/plugin-search-common@1.1.1-next.0 + - @backstage/plugin-search-react@1.2.1-next.1 + ## 0.2.3-next.0 ### Patch Changes diff --git a/plugins/adr/package.json b/plugins/adr/package.json index e6113c7a83..0495be1614 100644 --- a/plugins/adr/package.json +++ b/plugins/adr/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-adr", - "version": "0.2.3-next.0", + "version": "0.2.3-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -55,7 +55,7 @@ "@types/git-url-parse": "^9.0.0", "@types/node": "*", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/airbrake-backend/CHANGELOG.md b/plugins/airbrake-backend/CHANGELOG.md index 38ed0acbc7..24caeabf88 100644 --- a/plugins/airbrake-backend/CHANGELOG.md +++ b/plugins/airbrake-backend/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-airbrake-backend +## 0.2.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/config@1.0.4-next.0 + ## 0.2.11-next.0 ### Patch Changes diff --git a/plugins/airbrake-backend/package.json b/plugins/airbrake-backend/package.json index f8904563a4..d2bc8206eb 100644 --- a/plugins/airbrake-backend/package.json +++ b/plugins/airbrake-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-airbrake-backend", - "version": "0.2.11-next.0", + "version": "0.2.11-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -35,7 +35,7 @@ "@backstage/cli": "workspace:^", "@types/http-proxy-middleware": "^0.19.3", "@types/supertest": "^2.0.8", - "msw": "^0.47.0", + "msw": "^0.48.0", "supertest": "^6.1.6" }, "files": [ diff --git a/plugins/airbrake/CHANGELOG.md b/plugins/airbrake/CHANGELOG.md index a714e4d69f..b81d9ccfcd 100644 --- a/plugins/airbrake/CHANGELOG.md +++ b/plugins/airbrake/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-airbrake +## 0.3.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/dev-utils@1.0.8-next.1 + - @backstage/test-utils@1.2.2-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.3.11-next.0 ### Patch Changes diff --git a/plugins/airbrake/package.json b/plugins/airbrake/package.json index 3f04501019..d34c31e89b 100644 --- a/plugins/airbrake/package.json +++ b/plugins/airbrake/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-airbrake", - "version": "0.3.11-next.0", + "version": "0.3.11-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -50,7 +50,7 @@ "@types/node": "^16.11.26", "@types/object-hash": "^2.2.1", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/allure/CHANGELOG.md b/plugins/allure/CHANGELOG.md index 0f57d596c5..0184290777 100644 --- a/plugins/allure/CHANGELOG.md +++ b/plugins/allure/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-allure +## 0.1.27-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.1.27-next.0 ### Patch Changes diff --git a/plugins/allure/package.json b/plugins/allure/package.json index 68808cf511..18b3a21612 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.27-next.0", + "version": "0.1.27-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -47,7 +47,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/analytics-module-ga/CHANGELOG.md b/plugins/analytics-module-ga/CHANGELOG.md index 149215b223..5f28f9b0e8 100644 --- a/plugins/analytics-module-ga/CHANGELOG.md +++ b/plugins/analytics-module-ga/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-analytics-module-ga +## 0.1.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + ## 0.1.22-next.0 ### Patch Changes diff --git a/plugins/analytics-module-ga/package.json b/plugins/analytics-module-ga/package.json index ac94ad8979..a442a8f686 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.22-next.0", + "version": "0.1.22-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -45,7 +45,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist", diff --git a/plugins/apache-airflow/CHANGELOG.md b/plugins/apache-airflow/CHANGELOG.md index b4dee086eb..8d60af0baf 100644 --- a/plugins/apache-airflow/CHANGELOG.md +++ b/plugins/apache-airflow/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-apache-airflow +## 0.2.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + ## 0.2.4-next.0 ### Patch Changes diff --git a/plugins/apache-airflow/package.json b/plugins/apache-airflow/package.json index bba1177b06..55db3b6b75 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.4-next.0", + "version": "0.2.4-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -43,7 +43,7 @@ "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist", diff --git a/plugins/apache-airflow/src/api/ApacheAirflowApi.ts b/plugins/apache-airflow/src/api/ApacheAirflowApi.ts index 838292524a..128f6e551d 100644 --- a/plugins/apache-airflow/src/api/ApacheAirflowApi.ts +++ b/plugins/apache-airflow/src/api/ApacheAirflowApi.ts @@ -16,6 +16,7 @@ import { createApiRef, DiscoveryApi } from '@backstage/core-plugin-api'; import { Dag, InstanceStatus, InstanceVersion } from './types'; +import { DagRun } from './types/Dags'; export const apacheAirflowApiRef = createApiRef({ id: 'plugin.apacheairflow.service', @@ -27,6 +28,10 @@ export type ApacheAirflowApi = { listDags(options?: { objectsPerRequest: number }): Promise; getDags(dagIds: string[]): Promise<{ dags: Dag[]; dagsNotFound: string[] }>; updateDag(dagId: string, isPaused: boolean): Promise; + getDagRuns( + dagId: string, + options?: { objectsPerRequest?: number; limit?: number }, + ): Promise; getInstanceStatus(): Promise; getInstanceVersion(): Promise; }; diff --git a/plugins/apache-airflow/src/api/ApacheAirflowClient.test.ts b/plugins/apache-airflow/src/api/ApacheAirflowClient.test.ts index b9bdb02283..ab0565f4e4 100644 --- a/plugins/apache-airflow/src/api/ApacheAirflowClient.test.ts +++ b/plugins/apache-airflow/src/api/ApacheAirflowClient.test.ts @@ -20,6 +20,7 @@ import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { ApacheAirflowClient } from './index'; import { Dag } from './types'; +import { DagRun } from './types/Dags'; const server = setupServer(); @@ -66,12 +67,45 @@ const dags: Dag[] = [ }, ]; +const dagRuns: DagRun[] = [ + { + dag_run_id: 'mock dag run 1', + dag_id: 'mock_dag_1', + logical_date: '2022-05-27T11:25:23.251274+00:00', + start_date: '2022-05-27T11:25:23.251274+00:00', + end_date: '2022-05-27T11:25:23.251274+00:00', + state: 'success', + external_trigger: true, + conf: {}, + }, + { + dag_run_id: 'mock dag run 2', + dag_id: 'mock_dag_2', + logical_date: '2022-05-27T11:25:23.251274+00:00', + start_date: '2022-05-27T11:25:23.251274+00:00', + end_date: '2022-05-27T11:25:23.251274+00:00', + state: 'running', + external_trigger: true, + conf: {}, + }, + { + dag_run_id: 'mock dag run 3', + dag_id: 'mock_dag_1', + logical_date: '2022-05-27T11:25:23.251274+00:00', + start_date: '2022-05-27T11:25:23.251274+00:00', + end_date: '2022-05-27T11:25:23.251274+00:00', + state: 'failed', + external_trigger: true, + conf: {}, + }, +]; + describe('ApacheAirflowClient', () => { setupRequestMockHandlers(server); const mockBaseUrl = 'http://backstage:9191/api/proxy'; const discoveryApi = UrlPatternDiscovery.compile(mockBaseUrl); - + let client: ApacheAirflowClient; const setupHandlers = () => { server.use( rest.get(`${mockBaseUrl}/airflow/dags`, (req, res, ctx) => { @@ -116,41 +150,61 @@ describe('ApacheAirflowClient', () => { return res(ctx.status(404)); }), - rest.patch(`${mockBaseUrl}/airflow/dags/:dag_id`, (req, res, ctx) => { - const { dag_id } = req.params; - const body = JSON.parse(req.body as string); - expect(body.is_paused).toBeDefined(); - return res( - ctx.json({ - dag_id: dag_id, - root_dag_id: 'string', - is_paused: body.is_paused, - is_active: true, - is_subdag: true, - fileloc: 'string', - file_token: 'string', - owners: ['string'], - description: 'string', - schedule_interval: { - __type: 'string', - days: 0, - seconds: 0, - microseconds: 0, - }, - tags: [{}], - }), - ); - }), + rest.get( + `${mockBaseUrl}/airflow/dags/:dag_id/dagRuns`, + (req, res, ctx) => { + const { dag_id } = req.params; + const runs = dagRuns.filter(run => run.dag_id === dag_id); + // event if the dag_id is invalid, airflow returns a valid response (with 0 dag runs) + return res( + ctx.json({ + dag_runs: runs, + total_entries: runs.length, + }), + ); + }, + ), + + rest.patch( + `${mockBaseUrl}/airflow/dags/:dag_id`, + async (req, res, ctx) => { + const { dag_id } = req.params; + const body = JSON.parse(await req.text()); + expect(body.is_paused).toBeDefined(); + return res( + ctx.json({ + dag_id: dag_id, + root_dag_id: 'string', + is_paused: body.is_paused, + is_active: true, + is_subdag: true, + fileloc: 'string', + file_token: 'string', + owners: ['string'], + description: 'string', + schedule_interval: { + __type: 'string', + days: 0, + seconds: 0, + microseconds: 0, + }, + tags: [{}], + }), + ); + }, + ), ); }; - it('list dags should return all dags with emulated pagination', async () => { + beforeEach(() => { setupHandlers(); - const client = new ApacheAirflowClient({ + client = new ApacheAirflowClient({ discoveryApi: discoveryApi, baseUrl: 'localhost:8080/', }); + }); + it('list dags should return all dags with emulated pagination', async () => { // call with limit of 2, to force two paginations in requesting all dags // as our mocked response has 4 total entries const responseDags = await client.listDags({ objectsPerRequest: 2 }); @@ -159,11 +213,6 @@ describe('ApacheAirflowClient', () => { }); it('update dag should return dag information with updated paused attribute', async () => { - setupHandlers(); - const client = new ApacheAirflowClient({ - discoveryApi: discoveryApi, - baseUrl: 'localhost:8080/', - }); const dagId = 'mock_dag_1'; const response: Dag = await client.updateDag(dagId, true); expect(response.dag_id).toEqual(dagId); @@ -171,11 +220,6 @@ describe('ApacheAirflowClient', () => { }); it('get only some dags', async () => { - setupHandlers(); - const client = new ApacheAirflowClient({ - discoveryApi: discoveryApi, - baseUrl: 'localhost:8080/', - }); const dagIds = ['mock_dag_1', 'mock_dag_3']; const response = await client.getDags(dagIds); expect(response.dags.length).toEqual(dagIds.length); @@ -186,11 +230,6 @@ describe('ApacheAirflowClient', () => { }); it('get dags but ignore NOT FOUND errors', async () => { - setupHandlers(); - const client = new ApacheAirflowClient({ - discoveryApi: discoveryApi, - baseUrl: 'localhost:8080/', - }); const dagIds = ['mock_dag_1', 'a-random-DAG-id']; const response = await client.getDags(dagIds); expect(response.dags.length).toEqual(1); @@ -198,4 +237,11 @@ describe('ApacheAirflowClient', () => { expect(response.dagsNotFound.length).toEqual(1); expect(response.dagsNotFound[0]).toEqual('a-random-DAG-id'); }); + + it('should get dag runs', async () => { + const dagId = 'mock_dag_1'; + const response = await client.getDagRuns(dagId); + expect(response.length).toEqual(2); + response.forEach(run => expect(run.dag_id).toEqual(dagId)); + }); }); diff --git a/plugins/apache-airflow/src/api/ApacheAirflowClient.ts b/plugins/apache-airflow/src/api/ApacheAirflowClient.ts index c722f5977d..ebd60b668a 100644 --- a/plugins/apache-airflow/src/api/ApacheAirflowClient.ts +++ b/plugins/apache-airflow/src/api/ApacheAirflowClient.ts @@ -25,6 +25,7 @@ import { InstanceVersion, ListDagsParams, } from './types'; +import { DagRun } from './types/Dags'; export class ApacheAirflowClient implements ApacheAirflowApi { discoveryApi: DiscoveryApi; @@ -97,11 +98,56 @@ export class ApacheAirflowClient implements ApacheAirflowApi { async updateDag(dagId: string, isPaused: boolean): Promise { const init = { method: 'PATCH', + headers: { + 'Content-Type': 'application/json', + }, body: JSON.stringify({ is_paused: isPaused }), }; return await this.fetch(`/dags/${dagId}`, init); } + /** + * Get the latest DAG Runs of a specific DAG. + * The DAG runs are ordered by start date + * + * @remarks + * + * The "limit" option means the maximum number of DAG runs to return + * "objectsPerRequest" means the maximum number of DAG runs to be taken per fetch request. + * This is just to make sure the response payloads are not too big + */ + async getDagRuns( + dagId: string, + options = { objectsPerRequest: 100, limit: 5 }, + ): Promise { + const dagRuns: DagRun[] = []; + const searchParams: ListDagsParams = { + limit: Math.min(options.objectsPerRequest || 100, options.limit || 5), + offset: 0, + order_by: '-start_date', + }; + + for (;;) { + const response = await this.fetch<{ + dag_runs: DagRun[]; + total_entries: number; + }>(`/dags/${dagId}/dagRuns?${qs.stringify(searchParams)}`); + dagRuns.push(...response.dag_runs); + + if (response.dag_runs.length < searchParams.limit!) { + break; + } + if ( + dagRuns.length >= response.total_entries || + dagRuns.length >= options.limit + ) { + break; + } + searchParams.offset! += response.dag_runs.length; + } + return dagRuns; + } + async getInstanceStatus(): Promise { return await this.fetch('/health'); } diff --git a/plugins/apache-airflow/src/api/types/Dags.ts b/plugins/apache-airflow/src/api/types/Dags.ts index 8f1d68fb2d..702a6470e7 100644 --- a/plugins/apache-airflow/src/api/types/Dags.ts +++ b/plugins/apache-airflow/src/api/types/Dags.ts @@ -44,6 +44,17 @@ export interface Dag { tags: Tag[]; } +export interface DagRun { + dag_run_id: string; + dag_id: string; + logical_date: string; + start_date: string; + end_date: string; + state: 'queued' | 'running' | 'success' | 'failed'; + external_trigger: boolean; + conf: {}; +} + export interface TimeDelta { __type: 'TimeDelta'; days: number; diff --git a/plugins/apache-airflow/src/components/DagTableComponent/DagTableComponent.tsx b/plugins/apache-airflow/src/components/DagTableComponent/DagTableComponent.tsx index fcd87b2020..2660e9380e 100644 --- a/plugins/apache-airflow/src/components/DagTableComponent/DagTableComponent.tsx +++ b/plugins/apache-airflow/src/components/DagTableComponent/DagTableComponent.tsx @@ -22,7 +22,7 @@ import { TableColumn, WarningPanel, } from '@backstage/core-components'; -import { useApi } from '@backstage/core-plugin-api'; +import { storageApiRef, useApi } from '@backstage/core-plugin-api'; import Box from '@material-ui/core/Box'; import Chip from '@material-ui/core/Chip'; import IconButton from '@material-ui/core/IconButton'; @@ -31,101 +31,151 @@ import Tooltip from '@material-ui/core/Tooltip'; import Typography from '@material-ui/core/Typography'; import OpenInBrowserIcon from '@material-ui/icons/OpenInBrowser'; import Alert from '@material-ui/lab/Alert'; -import React from 'react'; +import React, { useEffect, useState } from 'react'; import useAsync from 'react-use/lib/useAsync'; import { apacheAirflowApiRef } from '../../api'; import { Dag } from '../../api/types'; import { ScheduleIntervalLabel } from '../ScheduleIntervalLabel'; +import { LatestDagRunsStatus } from '../LatestDagRunsStatus'; type DagTableRow = Dag & { id: string; dagUrl: string; }; -const columns: TableColumn[] = [ - { - title: 'Paused', - field: 'is_paused', - render: (row: Partial) => ( - - - - ), - width: '5%', - }, - { - title: 'DAG', - field: 'id', - render: (row: Partial) => ( -
- - {row.id} - - - {row.tags?.map((tag, ix) => ( - - ))} - -
- ), - width: '60%', - }, - { - title: 'Owner', - field: 'owners', - render: (row: Partial) => ( - - {row.owners?.map((owner, ix) => ( - - ))} - - ), - width: '10%', - }, - { - title: 'Active', - render: (row: Partial) => ( - - {row.is_active ? : } - - {row.is_active ? 'Active' : 'Inactive'} - - - ), - width: '10%', - }, - { - title: 'Schedule', - render: (row: Partial) => ( - - ), - width: '10%', - }, - { - title: 'Link', - field: 'dagUrl', - render: (row: Partial) => ( - - - - - - ), - width: '5%', - }, -]; - type DenseTableProps = { dags: Dag[]; + rowClick: Function; }; -export const DenseTable = ({ dags }: DenseTableProps) => { +export const DenseTable = ({ dags, rowClick }: DenseTableProps) => { + const storage = useApi(storageApiRef); + const hiddenColumnsKey = 'dag-table-hidden-columns'; + const [hiddenColumns, setHiddenColumns] = useState([]); + + useEffect(() => { + const hiddenState = storage.snapshot(hiddenColumnsKey); + if (hiddenState.presence === 'present') { + setHiddenColumns(hiddenState.value as string[]); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + const columns: TableColumn[] = [ + { + title: 'Paused', + field: 'is_paused', + render: (row: Partial) => ( + + + + ), + width: '5%', + hidden: hiddenColumns.some(field => field === 'is_paused'), + }, + { + title: 'DAG', + field: 'id', + render: (row: Partial) => ( +
+ + {row.id} + + + {row.tags?.map((tag, ix) => ( + + ))} + +
+ ), + width: '50%', + disableClick: true, + hidden: hiddenColumns.some(field => field === 'id'), + }, + { + title: 'Runs', + field: 'runs', + render: (row: Partial) => ( + + ), + width: '10%', + disableClick: true, + hidden: hiddenColumns.some(field => field === 'runs'), + }, + { + title: 'Owner', + field: 'owners', + render: (row: Partial) => ( + + {row.owners?.map((owner, ix) => ( + + ))} + + ), + width: '10%', + disableClick: true, + hidden: hiddenColumns.some(field => field === 'owners'), + }, + { + title: 'Active', + field: 'active', + render: (row: Partial) => ( + + {row.is_active ? : } + + {row.is_active ? 'Active' : 'Inactive'} + + + ), + width: '10%', + disableClick: true, + hidden: hiddenColumns.some(field => field === 'active'), + }, + { + title: 'Schedule', + field: 'schedule', + render: (row: Partial) => ( + + ), + width: '10%', + disableClick: true, + hidden: hiddenColumns.some(field => field === 'schedule'), + }, + { + title: 'Link', + field: 'dagUrl', + render: (row: Partial) => ( + + + + + + ), + width: '5%', + disableClick: true, + hidden: hiddenColumns.some(field => field === 'dagUrl'), + }, + ]; + return ( rowClick(rowData)} + onChangeColumnHidden={(column, hidden) => { + if (column.field) { + let newHiddenColumns: string[]; + if (hidden) { + newHiddenColumns = hiddenColumns.concat(column.field); + } else { + newHiddenColumns = hiddenColumns.filter(v => v !== column.field); + } + setHiddenColumns(newHiddenColumns); + storage.set(hiddenColumnsKey, newHiddenColumns); + } + }} /> ); }; @@ -136,27 +186,54 @@ type DagTableComponentProps = { export const DagTableComponent = (props: DagTableComponentProps) => { const { dagIds } = props; + const [dagsData, setDagsData] = useState([]); const apiClient = useApi(apacheAirflowApiRef); - const { value, loading, error } = useAsync(async (): Promise => { + const updatePaused = async (rowData: Dag): Promise => { + const newDag = await apiClient.updateDag( + rowData.dag_id, + !rowData.is_paused, + ); + + const newDags = dagsData.map(el => { + if (el.dag_id === newDag.dag_id) { + return { ...el, is_paused: newDag.is_paused }; + } + return el; + }); + + setDagsData(newDags); + return newDag; + }; + + const { value, loading, error } = useAsync(async (): Promise< + DagTableRow[] + > => { + let dags: Dag[] = []; if (dagIds) { - const { dags } = await apiClient.getDags(dagIds); - return dags; + dags = (await apiClient.getDags(dagIds)).dags; + } else { + dags = await apiClient.listDags(); } - return await apiClient.listDags(); + return dags.map(el => ({ + ...el, + id: el.dag_id, // table records require `id` attribute + dagUrl: `${apiClient.baseUrl}dag_details?dag_id=${el.dag_id}`, // construct path to DAG using `baseUrl` + })); }, []); + useEffect(() => { + if (value) { + setDagsData(value); + } + }, [value]); + if (loading) { return ; } else if (error) { return {error.message}; } - const data = value?.map(el => ({ - ...el, - id: el.dag_id, // table records require `id` attribute - dagUrl: `${apiClient.baseUrl}dag_details?dag_id=${el.dag_id}`, // construct path to DAG using `baseUrl` - })); const dagsNotFound = dagIds && value ? dagIds.filter(id => !value.find(d => d.dag_id === id)) @@ -172,7 +249,7 @@ export const DagTableComponent = (props: DagTableComponentProps) => { ) : ( '' )} - + ); }; diff --git a/plugins/apache-airflow/src/components/LatestDagRunsStatus/LatestDagRunsStatus.test.tsx b/plugins/apache-airflow/src/components/LatestDagRunsStatus/LatestDagRunsStatus.test.tsx new file mode 100644 index 0000000000..fb020ee9e9 --- /dev/null +++ b/plugins/apache-airflow/src/components/LatestDagRunsStatus/LatestDagRunsStatus.test.tsx @@ -0,0 +1,67 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { ApacheAirflowApi, apacheAirflowApiRef } from '../../api'; +import { DagRun } from '../../api/types/Dags'; +import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; +import React from 'react'; +import { LatestDagRunsStatus } from './LatestDagRunsStatus'; + +describe('LatestDagRunsStatus', () => { + const baseDagRun: Partial = { + dag_run_id: 'mock dag run 1', + dag_id: 'mock_dag_1', + logical_date: '2022-05-27T11:25:23.251274+00:00', + start_date: '2022-05-27T11:25:23.251274+00:00', + end_date: '2022-05-27T11:25:23.251274+00:00', + state: 'success', + external_trigger: true, + conf: {}, + }; + const mockApi: jest.Mocked = { + getDagRuns: jest.fn().mockResolvedValue([ + baseDagRun, + { + ...baseDagRun, + dag_run_id: 'mock dag run 2', + state: 'running', + }, + { + ...baseDagRun, + dag_run_id: 'mock dag run 3', + state: 'failed', + }, + { + ...baseDagRun, + dag_run_id: 'mock dag run 3', + state: 'queued', + }, + ] as DagRun[]), + } as any; + + it('should render the status of mock dag 1', async () => { + const dagId = 'mock_dag_1'; + + const { getByLabelText } = await renderInTestApp( + + + , + ); + expect(getByLabelText('Status ok')).toBeInTheDocument(); + expect(getByLabelText('Status running')).toBeInTheDocument(); + expect(getByLabelText('Status error')).toBeInTheDocument(); + expect(getByLabelText('Status pending')).toBeInTheDocument(); + }); +}); diff --git a/plugins/apache-airflow/src/components/LatestDagRunsStatus/LatestDagRunsStatus.tsx b/plugins/apache-airflow/src/components/LatestDagRunsStatus/LatestDagRunsStatus.tsx new file mode 100644 index 0000000000..90cb0694f8 --- /dev/null +++ b/plugins/apache-airflow/src/components/LatestDagRunsStatus/LatestDagRunsStatus.tsx @@ -0,0 +1,161 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; +import { apacheAirflowApiRef } from '../../api'; +import useAsync from 'react-use/lib/useAsync'; +import { DagRun } from '../../api/types/Dags'; +import { useApi } from '@backstage/core-plugin-api'; +import { + Box, + Button, + CircularProgress, + List, + ListItem, + ListItemIcon, + makeStyles, + Tooltip, + Typography, +} from '@material-ui/core'; +import { + Link, + StatusError, + StatusOK, + StatusPending, + StatusRunning, +} from '@backstage/core-components'; +import DirectionsRun from '@material-ui/icons/DirectionsRun'; +import Check from '@material-ui/icons/Check'; +import CalendarToday from '@material-ui/icons/CalendarToday'; +import qs from 'qs'; +import AccountTree from '@material-ui/icons/AccountTree'; + +interface LatestDagRunsStatusProps { + dagId: string; + limit?: number; +} + +const useStyles = makeStyles(() => ({ + noMaxWidth: { + maxWidth: 'none', + }, +})); + +const DagRunTooltip = ({ + dagRun, + graphUrl, +}: { + dagRun: DagRun; + graphUrl: string; +}) => { + return ( + + + + + + {dagRun.dag_run_id} + + + + + + {new Date(dagRun.start_date).toLocaleString()} + + + + + + + {dagRun.end_date ? new Date(dagRun.end_date).toLocaleString() : '-'} + + + + + + + ); +}; + +export const LatestDagRunsStatus = ({ + dagId, + limit = 5, +}: LatestDagRunsStatusProps) => { + const classes = useStyles(); + const apiClient = useApi(apacheAirflowApiRef); + const { value, loading, error } = useAsync( + async (): Promise => await apiClient.getDagRuns(dagId, { limit }), + [dagId, limit], + ); + + if (loading) { + return ( + + + + ); + } + + if (error) { + return Can't get dag runs; + } + + const statusDots: JSX.Element[] | undefined = value?.map(dagRun => { + function status() { + switch (dagRun.state) { + case 'success': + return ; + case 'failed': + return ; + case 'running': + return ; + case 'queued': + return ; + default: + return Unrecognized state; + } + } + + const key = dagRun.dag_id + dagRun.dag_run_id; + const dagRunParams = { + dag_id: dagRun.dag_id, + execution_date: dagRun.logical_date, + }; + const graphUrl = `${apiClient.baseUrl}graph?${qs.stringify(dagRunParams)}`; + return ( + } + key={key} + classes={{ tooltip: classes.noMaxWidth }} + interactive + > + + {status()} + + + ); + }); + + return {statusDots}; +}; diff --git a/plugins/apache-airflow/src/components/LatestDagRunsStatus/index.ts b/plugins/apache-airflow/src/components/LatestDagRunsStatus/index.ts new file mode 100644 index 0000000000..acd84a3584 --- /dev/null +++ b/plugins/apache-airflow/src/components/LatestDagRunsStatus/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { LatestDagRunsStatus } from './LatestDagRunsStatus'; diff --git a/plugins/api-docs/CHANGELOG.md b/plugins/api-docs/CHANGELOG.md index de93784591..716cd44e05 100644 --- a/plugins/api-docs/CHANGELOG.md +++ b/plugins/api-docs/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-api-docs +## 0.8.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog@1.6.1-next.1 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.8.11-next.0 ### Patch Changes diff --git a/plugins/api-docs/package.json b/plugins/api-docs/package.json index ecb6fe3ff4..8b6f4a638d 100644 --- a/plugins/api-docs/package.json +++ b/plugins/api-docs/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-api-docs", "description": "A Backstage plugin that helps represent API entities in the frontend", - "version": "0.8.11-next.0", + "version": "0.8.11-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,7 +32,7 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@asyncapi/react-component": "1.0.0-next.43", + "@asyncapi/react-component": "1.0.0-next.44", "@backstage/catalog-model": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", @@ -66,7 +66,7 @@ "@types/node": "^16.11.26", "@types/swagger-ui-react": "^4.1.1", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/apollo-explorer/CHANGELOG.md b/plugins/apollo-explorer/CHANGELOG.md index 5ef5cb16f9..c388e42e6e 100644 --- a/plugins/apollo-explorer/CHANGELOG.md +++ b/plugins/apollo-explorer/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-apollo-explorer +## 0.1.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + ## 0.1.4-next.0 ### Patch Changes diff --git a/plugins/apollo-explorer/package.json b/plugins/apollo-explorer/package.json index 91fe56950e..02b5883d07 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.4-next.0", + "version": "0.1.4-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -45,7 +45,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "*", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/app-backend/CHANGELOG.md b/plugins/app-backend/CHANGELOG.md index 81c2020152..3d0508a9a0 100644 --- a/plugins/app-backend/CHANGELOG.md +++ b/plugins/app-backend/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-app-backend +## 0.3.38-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/config-loader@1.1.6-next.0 + - @backstage/types@1.0.1-next.0 + ## 0.3.38-next.0 ### Patch Changes diff --git a/plugins/app-backend/package.json b/plugins/app-backend/package.json index 5e72d7b666..a2eea49792 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.38-next.0", + "version": "0.3.38-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -58,7 +58,7 @@ "@types/supertest": "^2.0.8", "get-port": "^6.1.2", "mock-fs": "^5.1.0", - "msw": "^0.47.0", + "msw": "^0.48.0", "node-fetch": "^2.6.7", "supertest": "^6.1.3" }, diff --git a/plugins/auth-backend/CHANGELOG.md b/plugins/auth-backend/CHANGELOG.md index a65fa417d8..31ea050088 100644 --- a/plugins/auth-backend/CHANGELOG.md +++ b/plugins/auth-backend/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-auth-backend +## 0.17.1-next.1 + +### Patch Changes + +- 0d6837ca4e: Fix wrong GitHub callback URL documentation +- abaed9770e: Improve logging +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/types@1.0.1-next.0 + ## 0.17.1-next.0 ### Patch Changes diff --git a/plugins/auth-backend/api-report.md b/plugins/auth-backend/api-report.md index cc6962cdbe..cec3422d9c 100644 --- a/plugins/auth-backend/api-report.md +++ b/plugins/auth-backend/api-report.md @@ -669,6 +669,8 @@ export const readState: (stateString: string) => OAuthState; // @public (undocumented) export interface RouterOptions { + // (undocumented) + catalogApi?: CatalogApi; // (undocumented) config: Config; // (undocumented) diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json index 67deb66b33..ff6534814a 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.17.1-next.0", + "version": "0.17.1-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -89,7 +89,7 @@ "@types/passport-saml": "^1.1.3", "@types/passport-strategy": "^0.2.35", "@types/xml2js": "^0.4.7", - "msw": "^0.47.0", + "msw": "^0.48.0", "supertest": "^6.1.3" }, "files": [ diff --git a/plugins/auth-backend/src/providers/gcp-iap/helpers.test.ts b/plugins/auth-backend/src/providers/gcp-iap/helpers.test.ts index c0e351c90b..0162366f61 100644 --- a/plugins/auth-backend/src/providers/gcp-iap/helpers.test.ts +++ b/plugins/auth-backend/src/providers/gcp-iap/helpers.test.ts @@ -95,19 +95,19 @@ describe('helpers', () => { parseRequestToken(7, undefined as any), ).rejects.toMatchObject({ name: 'AuthenticationError', - message: 'Missing Google IAP header: x-goog-iap-jwt-assertion', + message: 'Missing Google IAP header', }); await expect( parseRequestToken(undefined, undefined as any), ).rejects.toMatchObject({ name: 'AuthenticationError', - message: 'Missing Google IAP header: x-goog-iap-jwt-assertion', + message: 'Missing Google IAP header', }); await expect( parseRequestToken('', undefined as any), ).rejects.toMatchObject({ name: 'AuthenticationError', - message: 'Missing Google IAP header: x-goog-iap-jwt-assertion', + message: 'Missing Google IAP header', }); }); diff --git a/plugins/auth-backend/src/providers/gcp-iap/helpers.ts b/plugins/auth-backend/src/providers/gcp-iap/helpers.ts index c7e81adc73..26d9a8c904 100644 --- a/plugins/auth-backend/src/providers/gcp-iap/helpers.ts +++ b/plugins/auth-backend/src/providers/gcp-iap/helpers.ts @@ -17,7 +17,7 @@ import { AuthenticationError } from '@backstage/errors'; import { OAuth2Client, TokenPayload } from 'google-auth-library'; import { AuthHandler } from '../types'; -import { GcpIapResult, IAP_JWT_HEADER } from './types'; +import { GcpIapResult } from './types'; export function createTokenValidator( audience: string, @@ -52,9 +52,7 @@ export async function parseRequestToken( tokenValidator: (token: string) => Promise, ): Promise { if (typeof jwtToken !== 'string' || !jwtToken) { - throw new AuthenticationError( - `Missing Google IAP header: ${IAP_JWT_HEADER}`, - ); + throw new AuthenticationError('Missing Google IAP header'); } let payload: TokenPayload; diff --git a/plugins/auth-backend/src/providers/gcp-iap/provider.test.ts b/plugins/auth-backend/src/providers/gcp-iap/provider.test.ts index b1b2a3f66e..c01db3a853 100644 --- a/plugins/auth-backend/src/providers/gcp-iap/provider.test.ts +++ b/plugins/auth-backend/src/providers/gcp-iap/provider.test.ts @@ -18,6 +18,7 @@ import express from 'express'; import request from 'supertest'; import { AuthResolverContext } from '../types'; import { GcpIapProvider } from './provider'; +import { DEFAULT_IAP_JWT_HEADER } from './types'; beforeEach(() => { jest.clearAllMocks(); @@ -28,44 +29,47 @@ describe('GcpIapProvider', () => { const signInResolver = jest.fn(); const tokenValidator = jest.fn(); - it('runs the happy path', async () => { - const provider = new GcpIapProvider({ - authHandler, - signInResolver, - tokenValidator, - resolverContext: {} as AuthResolverContext, - }); + it.each([undefined, 'x-custom-header'])( + 'runs the happy path', + async jwtHeader => { + const provider = new GcpIapProvider({ + authHandler, + signInResolver, + tokenValidator, + resolverContext: {} as AuthResolverContext, + jwtHeader: jwtHeader, + }); - // { "sub": "user:default/me", "ent": ["group:default/home"] } - const backstageToken = - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyOmRlZmF1bHQvbWUiLCJlbnQiOlsiZ3JvdXA6ZGVmYXVsdC9ob21lIl19.CbmAKzFErGmtsnpRxyPc7dHv7WEjb5lY6206YCzR_Rc'; - const iapToken = { sub: 's', email: 'e@mail.com' }; + // { "sub": "user:default/me", "ent": ["group:default/home"] } + const backstageToken = + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyOmRlZmF1bHQvbWUiLCJlbnQiOlsiZ3JvdXA6ZGVmYXVsdC9ob21lIl19.CbmAKzFErGmtsnpRxyPc7dHv7WEjb5lY6206YCzR_Rc'; + const iapToken = { sub: 's', email: 'e@mail.com' }; - authHandler.mockResolvedValueOnce({ email: 'e@mail.com' }); - signInResolver.mockResolvedValueOnce({ token: backstageToken }); - tokenValidator.mockResolvedValueOnce(iapToken); + authHandler.mockResolvedValueOnce({ email: 'e@mail.com' }); + signInResolver.mockResolvedValueOnce({ token: backstageToken }); + tokenValidator.mockResolvedValueOnce(iapToken); - const app = express(); - app.use('/refresh', provider.refresh.bind(provider)); + const app = express(); + app.use('/refresh', provider.refresh.bind(provider)); - const response = await request(app) - .get('/refresh') - .set('x-goog-iap-jwt-assertion', 'token'); + const header = jwtHeader || DEFAULT_IAP_JWT_HEADER; + const response = await request(app).get('/refresh').set(header, 'token'); - expect(response.status).toBe(200); - expect(response.get('content-type')).toBe( - 'application/json; charset=utf-8', - ); - expect(response.body).toEqual({ - backstageIdentity: { - token: backstageToken, - identity: { - type: 'user', - userEntityRef: 'user:default/me', - ownershipEntityRefs: ['group:default/home'], + expect(response.status).toBe(200); + expect(response.get('content-type')).toBe( + 'application/json; charset=utf-8', + ); + expect(response.body).toEqual({ + backstageIdentity: { + token: backstageToken, + identity: { + type: 'user', + userEntityRef: 'user:default/me', + ownershipEntityRefs: ['group:default/home'], + }, }, - }, - providerInfo: { iapToken }, - }); - }); + providerInfo: { iapToken }, + }); + }, + ); }); diff --git a/plugins/auth-backend/src/providers/gcp-iap/provider.ts b/plugins/auth-backend/src/providers/gcp-iap/provider.ts index 500b062d5b..7e77853737 100644 --- a/plugins/auth-backend/src/providers/gcp-iap/provider.ts +++ b/plugins/auth-backend/src/providers/gcp-iap/provider.ts @@ -29,24 +29,27 @@ import { defaultAuthHandler, parseRequestToken, } from './helpers'; -import { GcpIapResponse, GcpIapResult, IAP_JWT_HEADER } from './types'; +import { GcpIapResponse, GcpIapResult, DEFAULT_IAP_JWT_HEADER } from './types'; export class GcpIapProvider implements AuthProviderRouteHandlers { private readonly authHandler: AuthHandler; private readonly signInResolver: SignInResolver; private readonly tokenValidator: (token: string) => Promise; private readonly resolverContext: AuthResolverContext; + private readonly jwtHeader: string; constructor(options: { authHandler: AuthHandler; signInResolver: SignInResolver; tokenValidator: (token: string) => Promise; resolverContext: AuthResolverContext; + jwtHeader?: string; }) { this.authHandler = options.authHandler; this.signInResolver = options.signInResolver; this.tokenValidator = options.tokenValidator; this.resolverContext = options.resolverContext; + this.jwtHeader = options?.jwtHeader || DEFAULT_IAP_JWT_HEADER; } async start() {} @@ -55,7 +58,7 @@ export class GcpIapProvider implements AuthProviderRouteHandlers { async refresh(req: express.Request, res: express.Response): Promise { const result = await parseRequestToken( - req.header(IAP_JWT_HEADER), + req.header(this.jwtHeader), this.tokenValidator, ); @@ -103,6 +106,7 @@ export const gcpIap = createAuthProviderIntegration({ }) { return ({ config, resolverContext }) => { const audience = config.getString('audience'); + const jwtHeader = config.getOptionalString('jwtHeader'); const authHandler = options.authHandler ?? defaultAuthHandler; const signInResolver = options.signIn.resolver; @@ -113,6 +117,7 @@ export const gcpIap = createAuthProviderIntegration({ signInResolver, tokenValidator, resolverContext, + jwtHeader, }); }; }, diff --git a/plugins/auth-backend/src/providers/gcp-iap/types.ts b/plugins/auth-backend/src/providers/gcp-iap/types.ts index 25828b7d51..6519de64ac 100644 --- a/plugins/auth-backend/src/providers/gcp-iap/types.ts +++ b/plugins/auth-backend/src/providers/gcp-iap/types.ts @@ -20,7 +20,7 @@ import { AuthResponse } from '../types'; /** * The header name used by the IAP. */ -export const IAP_JWT_HEADER = 'x-goog-iap-jwt-assertion'; +export const DEFAULT_IAP_JWT_HEADER = 'x-goog-iap-jwt-assertion'; /** * The data extracted from an IAP token. diff --git a/plugins/auth-backend/src/service/router.ts b/plugins/auth-backend/src/service/router.ts index 7240ba1bcb..8013777415 100644 --- a/plugins/auth-backend/src/service/router.ts +++ b/plugins/auth-backend/src/service/router.ts @@ -28,7 +28,7 @@ import { TokenManager, } from '@backstage/backend-common'; import { assertError, NotFoundError } from '@backstage/errors'; -import { CatalogClient } from '@backstage/catalog-client'; +import { CatalogApi, CatalogClient } from '@backstage/catalog-client'; import { Config } from '@backstage/config'; import { createOidcRouter, TokenFactory, KeyStores } from '../identity'; import session from 'express-session'; @@ -48,6 +48,7 @@ export interface RouterOptions { tokenManager: TokenManager; tokenFactoryAlgorithm?: string; providerFactories?: ProviderFactories; + catalogApi?: CatalogApi; } /** @public */ @@ -62,6 +63,7 @@ export async function createRouter( tokenManager, tokenFactoryAlgorithm, providerFactories, + catalogApi, } = options; const router = Router(); @@ -78,7 +80,6 @@ export async function createRouter( logger: logger.child({ component: 'token-factory' }), algorithm: tokenFactoryAlgorithm, }); - const catalogApi = new CatalogClient({ discoveryApi: discovery }); const secret = config.getOptionalString('auth.session.secret'); if (secret) { @@ -127,7 +128,8 @@ export async function createRouter( logger, resolverContext: CatalogAuthResolverContext.create({ logger, - catalogApi, + catalogApi: + catalogApi ?? new CatalogClient({ discoveryApi: discovery }), tokenIssuer, tokenManager, }), diff --git a/plugins/auth-node/CHANGELOG.md b/plugins/auth-node/CHANGELOG.md index aac75b87e9..8f31f276dc 100644 --- a/plugins/auth-node/CHANGELOG.md +++ b/plugins/auth-node/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-node +## 0.2.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + ## 0.2.7-next.0 ### Patch Changes diff --git a/plugins/auth-node/package.json b/plugins/auth-node/package.json index 79dcc6d6b8..156af7f1bf 100644 --- a/plugins/auth-node/package.json +++ b/plugins/auth-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-node", - "version": "0.2.7-next.0", + "version": "0.2.7-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -35,7 +35,7 @@ "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "lodash": "^4.17.21", - "msw": "^0.47.0", + "msw": "^0.48.0", "uuid": "^8.0.0" }, "files": [ diff --git a/plugins/azure-devops-backend/CHANGELOG.md b/plugins/azure-devops-backend/CHANGELOG.md index ae57ae23a9..e6a148f278 100644 --- a/plugins/azure-devops-backend/CHANGELOG.md +++ b/plugins/azure-devops-backend/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-azure-devops-backend +## 0.3.17-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/plugin-azure-devops-common@0.3.0 + ## 0.3.17-next.1 ### Patch Changes diff --git a/plugins/azure-devops-backend/package.json b/plugins/azure-devops-backend/package.json index 50a99dbc2a..eaf689d676 100644 --- a/plugins/azure-devops-backend/package.json +++ b/plugins/azure-devops-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-azure-devops-backend", - "version": "0.3.17-next.1", + "version": "0.3.17-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -37,7 +37,7 @@ "devDependencies": { "@backstage/cli": "workspace:^", "@types/supertest": "^2.0.8", - "msw": "^0.47.0", + "msw": "^0.48.0", "supertest": "^6.1.6" }, "files": [ diff --git a/plugins/azure-devops/CHANGELOG.md b/plugins/azure-devops/CHANGELOG.md index 1317547b7f..2dc9629a4b 100644 --- a/plugins/azure-devops/CHANGELOG.md +++ b/plugins/azure-devops/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-azure-devops +## 0.2.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-azure-devops-common@0.3.0 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.2.2-next.0 ### Patch Changes diff --git a/plugins/azure-devops/package.json b/plugins/azure-devops/package.json index a2ffd77c84..33b3d05ff8 100644 --- a/plugins/azure-devops/package.json +++ b/plugins/azure-devops/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-azure-devops", - "version": "0.2.2-next.0", + "version": "0.2.2-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -56,7 +56,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/azure-sites-backend/CHANGELOG.md b/plugins/azure-sites-backend/CHANGELOG.md index b06742648f..230c8912a8 100644 --- a/plugins/azure-sites-backend/CHANGELOG.md +++ b/plugins/azure-sites-backend/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-azure-sites-backend +## 0.1.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/plugin-azure-sites-common@0.1.0-next.0 + ## 0.1.0-next.0 ### Minor Changes diff --git a/plugins/azure-sites-backend/package.json b/plugins/azure-sites-backend/package.json index f6529b7a3d..ae1f2a6f3d 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.0-next.0", + "version": "0.1.0-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -48,7 +48,7 @@ "devDependencies": { "@backstage/cli": "workspace:^", "@types/supertest": "^2.0.8", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/azure-sites/CHANGELOG.md b/plugins/azure-sites/CHANGELOG.md index 4e1b2bb12b..ad4e9a5f41 100644 --- a/plugins/azure-sites/CHANGELOG.md +++ b/plugins/azure-sites/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-azure-sites +## 0.1.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-azure-sites-common@0.1.0-next.0 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.1.0-next.0 ### Minor Changes diff --git a/plugins/azure-sites/package.json b/plugins/azure-sites/package.json index feff8e8645..ac152be385 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.0-next.0", + "version": "0.1.0-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -57,7 +57,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/badges-backend/CHANGELOG.md b/plugins/badges-backend/CHANGELOG.md index c88b7cf763..9566bfa567 100644 --- a/plugins/badges-backend/CHANGELOG.md +++ b/plugins/badges-backend/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-badges-backend +## 0.1.32-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + ## 0.1.32-next.0 ### Patch Changes diff --git a/plugins/badges-backend/package.json b/plugins/badges-backend/package.json index a8e465597c..09eee82efb 100644 --- a/plugins/badges-backend/package.json +++ b/plugins/badges-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-badges-backend", "description": "A Backstage backend plugin that generates README badges for your entities", - "version": "0.1.32-next.0", + "version": "0.1.32-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/badges/CHANGELOG.md b/plugins/badges/CHANGELOG.md index f736588933..7eea420307 100644 --- a/plugins/badges/CHANGELOG.md +++ b/plugins/badges/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-badges +## 0.2.35-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.2.35-next.0 ### Patch Changes diff --git a/plugins/badges/package.json b/plugins/badges/package.json index 68d47e08ac..bd3b2f64b1 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.35-next.0", + "version": "0.2.35-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -54,7 +54,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/bazaar-backend/CHANGELOG.md b/plugins/bazaar-backend/CHANGELOG.md index d0524bd9f5..743f89dc74 100644 --- a/plugins/bazaar-backend/CHANGELOG.md +++ b/plugins/bazaar-backend/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-bazaar-backend +## 0.2.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-test-utils@0.1.30-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + ## 0.2.1-next.0 ### Patch Changes diff --git a/plugins/bazaar-backend/package.json b/plugins/bazaar-backend/package.json index 2f0e766917..1721508fcb 100644 --- a/plugins/bazaar-backend/package.json +++ b/plugins/bazaar-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-bazaar-backend", - "version": "0.2.1-next.0", + "version": "0.2.1-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 7ff38b63f8..0db71d8fed 100644 --- a/plugins/bazaar/CHANGELOG.md +++ b/plugins/bazaar/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-bazaar +## 0.2.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.21.0-next.1 + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/plugin-catalog@1.6.1-next.1 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.2.0-next.0 ### Minor Changes diff --git a/plugins/bazaar/package.json b/plugins/bazaar/package.json index eb0542a504..a197baee72 100644 --- a/plugins/bazaar/package.json +++ b/plugins/bazaar/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-bazaar", - "version": "0.2.0-next.0", + "version": "0.2.0-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/bitbucket-cloud-common/api-report.md b/plugins/bitbucket-cloud-common/api-report.md index d66b8b9a70..5182579a4b 100644 --- a/plugins/bitbucket-cloud-common/api-report.md +++ b/plugins/bitbucket-cloud-common/api-report.md @@ -24,6 +24,57 @@ export class BitbucketCloudClient { ): WithPagination; } +// @public (undocumented) +export namespace Events { + // (undocumented) + export interface Change { + // (undocumented) + closed: boolean; + // (undocumented) + commits: Models.Commit[]; + // (undocumented) + created: boolean; + // (undocumented) + forced: boolean; + // (undocumented) + links: ChangeLinks; + // (undocumented) + new: Models.Branch; + // (undocumented) + old: Models.Branch; + // (undocumented) + truncated: boolean; + } + // (undocumented) + export interface ChangeLinks { + // (undocumented) + commits: Models.Link; + // (undocumented) + diff: Models.Link; + // (undocumented) + html: Models.Link; + } + // (undocumented) + export interface RepoEvent { + // (undocumented) + actor: Models.Account; + // (undocumented) + repository: Models.Repository & { + workspace: Models.Workspace; + }; + } + // (undocumented) + export interface RepoPush { + // (undocumented) + changes: Change[]; + } + // (undocumented) + export interface RepoPushEvent extends RepoEvent { + // (undocumented) + push: RepoPush; + } +} + // @public (undocumented) export type FilterAndSortOptions = { q?: string; @@ -340,6 +391,37 @@ export namespace Models { // (undocumented) self?: Link; } + export interface Workspace extends ModelObject { + // (undocumented) + created_on?: string; + is_private?: boolean; + // (undocumented) + links?: WorkspaceLinks; + name?: string; + slug?: string; + // (undocumented) + updated_on?: string; + uuid?: string; + } + // (undocumented) + export interface WorkspaceLinks { + // (undocumented) + avatar?: Link; + // (undocumented) + html?: Link; + // (undocumented) + members?: Link; + // (undocumented) + owners?: Link; + // (undocumented) + projects?: Link; + // (undocumented) + repositories?: Link; + // (undocumented) + self?: Link; + // (undocumented) + snippets?: Link; + } } // @public (undocumented) diff --git a/plugins/bitbucket-cloud-common/package.json b/plugins/bitbucket-cloud-common/package.json index fbc63e4497..3423a09b3e 100644 --- a/plugins/bitbucket-cloud-common/package.json +++ b/plugins/bitbucket-cloud-common/package.json @@ -33,7 +33,7 @@ "devDependencies": { "@backstage/cli": "workspace:^", "@openapitools/openapi-generator-cli": "^2.4.26", - "msw": "^0.47.0", + "msw": "^0.48.0", "ts-morph": "^15.0.0" }, "files": [ diff --git a/plugins/bitbucket-cloud-common/scripts/reduce-models.js b/plugins/bitbucket-cloud-common/scripts/reduce-models.js index 9d458f4e74..115020493c 100755 --- a/plugins/bitbucket-cloud-common/scripts/reduce-models.js +++ b/plugins/bitbucket-cloud-common/scripts/reduce-models.js @@ -30,6 +30,14 @@ const modelsModule = modelsFile.getModuleOrThrow('Models'); const clientFile = project.getSourceFile('src/BitbucketCloudClient.ts'); const clientClass = clientFile.getClassOrThrow('BitbucketCloudClient'); +const eventsFile = project.getSourceFile('src/events/index.ts'); +const eventsModule = eventsFile.getModuleOrThrow('Events'); +const eventsStmts = [ + ...eventsModule.getClasses(), + ...eventsModule.getInterfaces(), + ...eventsModule.getTypeAliases(), +]; + /** * Returns an array of the unique items of the provided array. * @@ -79,7 +87,11 @@ function referencedModelsIdentifiers(stmt, processed) { } // all directly or transitively referenced/used `Models.[...]` are allowed to stay -const allowed = referencedModelsIdentifiers(clientClass); +const processed = []; +const allowed = referencedModelsIdentifiers(clientClass, processed); +allowed.push( + ...eventsStmts.flatMap(stmt => referencedModelsIdentifiers(stmt, processed)), +); // remove everything not part of the "allow list" modelsModule diff --git a/plugins/bitbucket-cloud-common/src/events/index.ts b/plugins/bitbucket-cloud-common/src/events/index.ts new file mode 100644 index 0000000000..53658be032 --- /dev/null +++ b/plugins/bitbucket-cloud-common/src/events/index.ts @@ -0,0 +1,56 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { Models } from '../models'; + +// source: https://support.atlassian.com/bitbucket-cloud/docs/event-payloads + +/** @public */ +export namespace Events { + /** @public */ + export interface RepoEvent { + repository: Models.Repository & { workspace: Models.Workspace }; + actor: Models.Account; + } + + /** @public */ + export interface RepoPushEvent extends RepoEvent { + push: RepoPush; + } + + /** @public */ + export interface RepoPush { + changes: Change[]; + } + + /** @public */ + export interface Change { + old: Models.Branch; + new: Models.Branch; + truncated: boolean; + created: boolean; + forced: boolean; + closed: boolean; + links: ChangeLinks; + commits: Models.Commit[]; + } + + /** @public */ + export interface ChangeLinks { + commits: Models.Link; + diff: Models.Link; + html: Models.Link; + } +} diff --git a/plugins/bitbucket-cloud-common/src/index.ts b/plugins/bitbucket-cloud-common/src/index.ts index 4edf148240..4a9b00e89b 100644 --- a/plugins/bitbucket-cloud-common/src/index.ts +++ b/plugins/bitbucket-cloud-common/src/index.ts @@ -21,6 +21,7 @@ */ export * from './BitbucketCloudClient'; +export * from './events'; export * from './models'; export * from './pagination'; export * from './types'; diff --git a/plugins/bitbucket-cloud-common/src/models/index.ts b/plugins/bitbucket-cloud-common/src/models/index.ts index 580f23a13f..9d25bbb873 100644 --- a/plugins/bitbucket-cloud-common/src/models/index.ts +++ b/plugins/bitbucket-cloud-common/src/models/index.ts @@ -518,4 +518,46 @@ export namespace Models { repositories?: Link; self?: Link; } + + /** + * A Bitbucket workspace. + * Workspaces are used to organize repositories. + * @public + */ + export interface Workspace extends ModelObject { + created_on?: string; + /** + * Indicates whether the workspace is publicly accessible, or whether it is + * private to the members and consequently only visible to members. + */ + is_private?: boolean; + links?: WorkspaceLinks; + /** + * The name of the workspace. + */ + name?: string; + /** + * The short label that identifies this workspace. + */ + slug?: string; + updated_on?: string; + /** + * The workspace's immutable id. + */ + uuid?: string; + } + + /** + * @public + */ + export interface WorkspaceLinks { + avatar?: Link; + html?: Link; + members?: Link; + owners?: Link; + projects?: Link; + repositories?: Link; + self?: Link; + snippets?: Link; + } } diff --git a/plugins/bitrise/CHANGELOG.md b/plugins/bitrise/CHANGELOG.md index 2ec214ea00..e9f27547da 100644 --- a/plugins/bitrise/CHANGELOG.md +++ b/plugins/bitrise/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-bitrise +## 0.1.38-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.1.38-next.0 ### Patch Changes diff --git a/plugins/bitrise/package.json b/plugins/bitrise/package.json index cb23af3b90..d6527f9973 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.38-next.0", + "version": "0.1.38-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -51,7 +51,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "@types/recharts": "^1.8.15", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/catalog-backend-module-aws/CHANGELOG.md b/plugins/catalog-backend-module-aws/CHANGELOG.md index 59ab7970f2..487f0d9f77 100644 --- a/plugins/catalog-backend-module-aws/CHANGELOG.md +++ b/plugins/catalog-backend-module-aws/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-catalog-backend-module-aws +## 0.1.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/types@1.0.1-next.0 + ## 0.1.11-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-aws/package.json b/plugins/catalog-backend-module-aws/package.json index a000ee9d84..4d4dcfec3d 100644 --- a/plugins/catalog-backend-module-aws/package.json +++ b/plugins/catalog-backend-module-aws/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-aws", "description": "A Backstage catalog backend module that helps integrate towards AWS", - "version": "0.1.11-next.0", + "version": "0.1.11-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-azure/CHANGELOG.md b/plugins/catalog-backend-module-azure/CHANGELOG.md index 7fed636045..52ee6b7dd0 100644 --- a/plugins/catalog-backend-module-azure/CHANGELOG.md +++ b/plugins/catalog-backend-module-azure/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-catalog-backend-module-azure +## 0.1.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/types@1.0.1-next.0 + ## 0.1.9-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-azure/package.json b/plugins/catalog-backend-module-azure/package.json index 204321f876..5490425527 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.9-next.0", + "version": "0.1.9-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -44,7 +44,6 @@ "@backstage/plugin-catalog-node": "workspace:^", "@backstage/types": "workspace:^", "lodash": "^4.17.21", - "msw": "^0.47.0", "node-fetch": "^2.6.7", "uuid": "^8.0.0", "winston": "^3.2.1" @@ -53,7 +52,8 @@ "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "@types/lodash": "^4.14.151", - "luxon": "^3.0.0" + "luxon": "^3.0.0", + "msw": "^0.48.0" }, "files": [ "alpha", diff --git a/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md index 47cc94f257..933bf23b65 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md +++ b/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-catalog-backend-module-bitbucket-cloud +## 0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.1-next.0 + ## 0.1.5-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-bitbucket-cloud/api-report.md b/plugins/catalog-backend-module-bitbucket-cloud/api-report.md index 162ff8f67e..480395e477 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/api-report.md +++ b/plugins/catalog-backend-module-bitbucket-cloud/api-report.md @@ -4,24 +4,33 @@ ```ts import { BackendFeature } from '@backstage/backend-plugin-api'; +import { CatalogApi } from '@backstage/catalog-client'; import { Config } from '@backstage/config'; import { EntityProvider } from '@backstage/plugin-catalog-backend'; import { EntityProviderConnection } from '@backstage/plugin-catalog-backend'; +import { EventParams } from '@backstage/plugin-events-node'; +import { Events } from '@backstage/plugin-bitbucket-cloud-common'; +import { EventSubscriber } from '@backstage/plugin-events-node'; import { Logger } from 'winston'; import { PluginTaskScheduler } from '@backstage/backend-tasks'; import { TaskRunner } from '@backstage/backend-tasks'; +import { TokenManager } from '@backstage/backend-common'; // @public -export class BitbucketCloudEntityProvider implements EntityProvider { +export class BitbucketCloudEntityProvider + implements EntityProvider, EventSubscriber +{ // (undocumented) connect(connection: EntityProviderConnection): Promise; // (undocumented) static fromConfig( config: Config, options: { + catalogApi?: CatalogApi; logger: Logger; schedule?: TaskRunner; scheduler?: PluginTaskScheduler; + tokenManager?: TokenManager; }, ): BitbucketCloudEntityProvider[]; // (undocumented) @@ -29,7 +38,13 @@ export class BitbucketCloudEntityProvider implements EntityProvider { // (undocumented) getTaskId(): string; // (undocumented) + onEvent(params: EventParams): Promise; + // (undocumented) + onRepoPush(event: Events.RepoPushEvent): Promise; + // (undocumented) refresh(logger: Logger): Promise; + // (undocumented) + supportsEventTopics(): string[]; } // @alpha (undocumented) diff --git a/plugins/catalog-backend-module-bitbucket-cloud/package.json b/plugins/catalog-backend-module-bitbucket-cloud/package.json index 93a9407aa1..e7cd57b560 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.5-next.0", + "version": "0.1.5-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,13 +33,19 @@ "clean": "backstage-cli package clean" }, "dependencies": { + "@backstage/backend-common": "workspace:^", "@backstage/backend-plugin-api": "workspace:^", "@backstage/backend-tasks": "workspace:^", + "@backstage/catalog-client": "workspace:^", + "@backstage/catalog-model": "workspace:^", "@backstage/config": "workspace:^", "@backstage/integration": "workspace:^", "@backstage/plugin-bitbucket-cloud-common": "workspace:^", "@backstage/plugin-catalog-backend": "workspace:^", + "@backstage/plugin-catalog-common": "workspace:^", "@backstage/plugin-catalog-node": "workspace:^", + "@backstage/plugin-events-node": "workspace:^", + "p-limit": "^3.1.0", "uuid": "^8.0.0", "winston": "^3.2.1" }, @@ -48,7 +54,7 @@ "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "luxon": "^3.0.0", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "alpha", diff --git a/plugins/catalog-backend-module-bitbucket-cloud/src/BitbucketCloudEntityProvider.test.ts b/plugins/catalog-backend-module-bitbucket-cloud/src/BitbucketCloudEntityProvider.test.ts index 7d780cd064..72974a1c94 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/src/BitbucketCloudEntityProvider.test.ts +++ b/plugins/catalog-backend-module-bitbucket-cloud/src/BitbucketCloudEntityProvider.test.ts @@ -333,6 +333,8 @@ describe('BitbucketCloudEntityProvider', () => { annotations: { 'backstage.io/managed-by-location': `url:${url}`, 'backstage.io/managed-by-origin-location': `url:${url}`, + 'bitbucket.org/repo-url': + 'https://bitbucket.org/test-ws/test-repo2', }, name: 'generated-7c2e6263b6cc2d14e69fd4d029afba601ad6dc3b', }, diff --git a/plugins/catalog-backend-module-bitbucket-cloud/src/BitbucketCloudEntityProvider.ts b/plugins/catalog-backend-module-bitbucket-cloud/src/BitbucketCloudEntityProvider.ts index f3334a6574..37ad60426d 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/src/BitbucketCloudEntityProvider.ts +++ b/plugins/catalog-backend-module-bitbucket-cloud/src/BitbucketCloudEntityProvider.ts @@ -14,7 +14,14 @@ * limitations under the License. */ +import { TokenManager } from '@backstage/backend-common'; import { PluginTaskScheduler, TaskRunner } from '@backstage/backend-tasks'; +import { CatalogApi } from '@backstage/catalog-client'; +import { + Entity, + LocationEntity, + stringifyEntityRef, +} from '@backstage/catalog-model'; import { Config } from '@backstage/config'; import { BitbucketCloudIntegration, @@ -22,22 +29,35 @@ import { } from '@backstage/integration'; import { BitbucketCloudClient, + Events, Models, } from '@backstage/plugin-bitbucket-cloud-common'; import { + DeferredEntity, EntityProvider, EntityProviderConnection, - LocationSpec, locationSpecToLocationEntity, } from '@backstage/plugin-catalog-backend'; +import { LocationSpec } from '@backstage/plugin-catalog-common'; +import { EventParams, EventSubscriber } from '@backstage/plugin-events-node'; import { BitbucketCloudEntityProviderConfig, readProviderConfigs, } from './BitbucketCloudEntityProviderConfig'; +import limiterFactory from 'p-limit'; import * as uuid from 'uuid'; import { Logger } from 'winston'; const DEFAULT_BRANCH = 'master'; +const TOPIC_REPO_PUSH = 'bitbucketCloud/repo:push'; + +/** @public */ +export const ANNOTATION_BITBUCKET_CLOUD_REPO_URL = 'bitbucket.org/repo-url'; + +interface IngestionTarget { + fileUrl: string; + repoUrl: string; +} /** * Discovers catalog files located in [Bitbucket Cloud](https://bitbucket.org). @@ -47,19 +67,27 @@ const DEFAULT_BRANCH = 'master'; * * @public */ -export class BitbucketCloudEntityProvider implements EntityProvider { +export class BitbucketCloudEntityProvider + implements EntityProvider, EventSubscriber +{ private readonly client: BitbucketCloudClient; private readonly config: BitbucketCloudEntityProviderConfig; private readonly logger: Logger; private readonly scheduleFn: () => Promise; + private readonly catalogApi?: CatalogApi; + private readonly tokenManager?: TokenManager; private connection?: EntityProviderConnection; + private eventConfigErrorThrown = false; + static fromConfig( config: Config, options: { + catalogApi?: CatalogApi; logger: Logger; schedule?: TaskRunner; scheduler?: PluginTaskScheduler; + tokenManager?: TokenManager; }, ): BitbucketCloudEntityProvider[] { const integrations = ScmIntegrations.fromConfig(config); @@ -90,6 +118,8 @@ export class BitbucketCloudEntityProvider implements EntityProvider { integration, options.logger, taskRunner, + options.catalogApi, + options.tokenManager, ); }); } @@ -99,6 +129,8 @@ export class BitbucketCloudEntityProvider implements EntityProvider { integration: BitbucketCloudIntegration, logger: Logger, taskRunner: TaskRunner, + catalogApi?: CatalogApi, + tokenManager?: TokenManager, ) { this.client = BitbucketCloudClient.fromConfig(integration.config); this.config = config; @@ -106,6 +138,8 @@ export class BitbucketCloudEntityProvider implements EntityProvider { target: this.getProviderName(), }); this.scheduleFn = this.createScheduleFn(taskRunner); + this.catalogApi = catalogApi; + this.tokenManager = tokenManager; } private createScheduleFn(schedule: TaskRunner): () => Promise { @@ -154,15 +188,7 @@ export class BitbucketCloudEntityProvider implements EntityProvider { logger.info('Discovering catalog files in Bitbucket Cloud repositories'); const targets = await this.findCatalogFiles(); - const entities = targets - .map(BitbucketCloudEntityProvider.toLocationSpec) - .map(location => locationSpecToLocationEntity({ location })) - .map(entity => { - return { - locationKey: this.getProviderName(), - entity: entity, - }; - }); + const entities = this.toDeferredEntities(targets); await this.connection.applyMutation({ type: 'full', @@ -174,7 +200,135 @@ export class BitbucketCloudEntityProvider implements EntityProvider { ); } - private async findCatalogFiles(): Promise { + /** {@inheritdoc @backstage/plugin-events-node#EventSubscriber.supportsEventTopics} */ + supportsEventTopics(): string[] { + return [TOPIC_REPO_PUSH]; + } + + /** {@inheritdoc @backstage/plugin-events-node#EventSubscriber.onEvent} */ + async onEvent(params: EventParams): Promise { + if (params.topic !== TOPIC_REPO_PUSH) { + return; + } + + if (params.metadata?.['x-event-key'] === 'repo:push') { + await this.onRepoPush(params.eventPayload as Events.RepoPushEvent); + } + } + + private canHandleEvents(): boolean { + if (this.catalogApi && this.tokenManager) { + return true; + } + + // throw only once + if (!this.eventConfigErrorThrown) { + this.eventConfigErrorThrown = true; + throw new Error( + `${this.getProviderName()} not well configured to handle repo:push. Missing CatalogApi and/or TokenManager.`, + ); + } + + return false; + } + + async onRepoPush(event: Events.RepoPushEvent): Promise { + if (!this.canHandleEvents()) { + return; + } + + if (!this.connection) { + throw new Error('Not initialized'); + } + + if (event.repository.workspace.slug !== this.config.workspace) { + return; + } + + if (!this.matchesFilters(event.repository)) { + return; + } + + const repoName = event.repository.slug; + const repoUrl = event.repository.links!.html!.href!; + this.logger.info(`handle repo:push event for ${repoUrl}`); + + // The commit information at the webhook only contains some high level metadata. + // In order to understand whether relevant files have changed we would need to + // look up all commits which would cost additional API calls. + // The overall goal is to optimize the necessary amount of API calls. + // Hence, we will just trigger a refresh for catalog file(s) within the repository + // if we get notified about changes there. + + const targets = await this.findCatalogFiles(repoName); + + const { token } = await this.tokenManager!.getToken(); + const existing = await this.findExistingLocations(repoUrl, token); + + const added: DeferredEntity[] = this.toDeferredEntities( + targets.filter( + // All Locations are managed by this provider and only have `target`, never `targets`. + // All URLs (fileUrl, target) are created using `BitbucketCloudEntityProvider.toUrl`. + // Hence, we can keep the comparison simple and don't need to handle different + // casing or encoding, etc. + target => !existing.find(item => item.spec.target === target.fileUrl), + ), + ); + + const limiter = limiterFactory(10); + + const stillExisting: Entity[] = []; + const removed: DeferredEntity[] = []; + existing.forEach(item => { + if (targets.find(value => value.fileUrl === item.spec.target)) { + stillExisting.push(item); + } else { + removed.push({ + locationKey: this.getProviderName(), + entity: item, + }); + } + }); + + const promises: Promise[] = stillExisting.map(entity => + limiter(async () => + this.catalogApi!.refreshEntity(stringifyEntityRef(entity), { token }), + ), + ); + + if (added.length > 0 || removed.length > 0) { + const connection = this.connection; + promises.push( + limiter(async () => + connection.applyMutation({ + type: 'delta', + added: added, + removed: removed, + }), + ), + ); + } + + await Promise.all(promises); + } + + private async findExistingLocations( + repoUrl: string, + token: string, + ): Promise { + const filter: Record = {}; + filter.kind = 'Location'; + filter[`metadata.annotations.${ANNOTATION_BITBUCKET_CLOUD_REPO_URL}`] = + repoUrl; + + return this.catalogApi!.getEntities({ filter }, { token }).then( + result => result.items, + ) as Promise; + } + + private async findCatalogFiles( + repoName?: string, + ): Promise { const workspace = this.config.workspace; const catalogPath = this.config.catalogPath; @@ -197,12 +351,13 @@ export class BitbucketCloudEntityProvider implements EntityProvider { // ...except the one we need '+values.file.commit.repository.links.html.href', ].join(','); - const query = `"${catalogFilename}" path:${catalogPath}`; + const optRepoFilter = repoName ? ` repo:${repoName}` : ''; + const query = `"${catalogFilename}" path:${catalogPath}${optRepoFilter}`; const searchResults = this.client .searchCode(workspace, query, { fields }) .iterateResults(); - const result: string[] = []; + const result: IngestionTarget[] = []; for await (const searchResult of searchResults) { // not a file match, but a code match @@ -212,12 +367,13 @@ export class BitbucketCloudEntityProvider implements EntityProvider { const repository = searchResult.file!.commit!.repository!; if (this.matchesFilters(repository)) { - result.push( - BitbucketCloudEntityProvider.toUrl( + result.push({ + fileUrl: BitbucketCloudEntityProvider.toUrl( repository, searchResult.file!.path!, ), - ); + repoUrl: repository.links!.html!.href!, + }); } } @@ -234,11 +390,32 @@ export class BitbucketCloudEntityProvider implements EntityProvider { ); } + private toDeferredEntities(targets: IngestionTarget[]): DeferredEntity[] { + return targets + .map(target => { + const location = BitbucketCloudEntityProvider.toLocationSpec( + target.fileUrl, + ); + const entity = locationSpecToLocationEntity({ location }); + entity.metadata.annotations = { + ...entity.metadata.annotations, + [ANNOTATION_BITBUCKET_CLOUD_REPO_URL]: target.repoUrl, + }; + return entity; + }) + .map(entity => { + return { + locationKey: this.getProviderName(), + entity: entity, + }; + }); + } + private static toUrl( repository: Models.Repository, filePath: string, ): string { - const repoUrl = repository.links!.html!.href; + const repoUrl = repository.links!.html!.href!; const branch = repository.mainbranch?.name ?? DEFAULT_BRANCH; return `${repoUrl}/src/${branch}/${filePath}`; diff --git a/plugins/catalog-backend-module-bitbucket-cloud/src/service/BitbucketCloudCatalogModule.test.ts b/plugins/catalog-backend-module-bitbucket-cloud/src/service/BitbucketCloudEntityProviderCatalogModule.test.ts similarity index 74% rename from plugins/catalog-backend-module-bitbucket-cloud/src/service/BitbucketCloudCatalogModule.test.ts rename to plugins/catalog-backend-module-bitbucket-cloud/src/service/BitbucketCloudEntityProviderCatalogModule.test.ts index 6307bee282..3fcc39fdd0 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/src/service/BitbucketCloudCatalogModule.test.ts +++ b/plugins/catalog-backend-module-bitbucket-cloud/src/service/BitbucketCloudEntityProviderCatalogModule.test.ts @@ -15,11 +15,17 @@ */ import { ConfigReader } from '@backstage/config'; -import { getVoidLogger } from '@backstage/backend-common'; +import { + getVoidLogger, + PluginEndpointDiscovery, + TokenManager, +} from '@backstage/backend-common'; import { configServiceRef, + discoveryServiceRef, loggerServiceRef, schedulerServiceRef, + tokenManagerServiceRef, } from '@backstage/backend-plugin-api'; import { PluginTaskScheduler, @@ -27,20 +33,27 @@ import { } from '@backstage/backend-tasks'; import { startTestBackend } from '@backstage/backend-test-utils'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node'; -import { bitbucketCloudEntityProviderCatalogModule } from './BitbucketCloudEntityProviderCatalogModule'; +import { eventsExtensionPoint } from '@backstage/plugin-events-node'; import { Duration } from 'luxon'; +import { bitbucketCloudEntityProviderCatalogModule } from './BitbucketCloudEntityProviderCatalogModule'; import { BitbucketCloudEntityProvider } from '../BitbucketCloudEntityProvider'; describe('bitbucketCloudEntityProviderCatalogModule', () => { it('should register provider at the catalog extension point', async () => { let addedProviders: Array | undefined; + let addedSubscribers: Array | undefined; let usedSchedule: TaskScheduleDefinition | undefined; - const extensionPoint = { + const catalogExtensionPointImpl = { addEntityProvider: (providers: any) => { addedProviders = providers; }, }; + const eventsExtensionPointImpl = { + addSubscribers: (subscribers: any) => { + addedSubscribers = subscribers; + }, + }; const runner = jest.fn(); const scheduler = { createScheduledTaskRunner: (schedule: TaskScheduleDefinition) => { @@ -48,6 +61,8 @@ describe('bitbucketCloudEntityProviderCatalogModule', () => { return runner; }, } as unknown as PluginTaskScheduler; + const discovery = jest.fn() as any as PluginEndpointDiscovery; + const tokenManager = jest.fn() as any as TokenManager; const config = new ConfigReader({ catalog: { @@ -64,11 +79,16 @@ describe('bitbucketCloudEntityProviderCatalogModule', () => { }); await startTestBackend({ - extensionPoints: [[catalogProcessingExtensionPoint, extensionPoint]], + extensionPoints: [ + [catalogProcessingExtensionPoint, catalogExtensionPointImpl], + [eventsExtensionPoint, eventsExtensionPointImpl], + ], services: [ [configServiceRef, config], + [discoveryServiceRef, discovery], [loggerServiceRef, getVoidLogger()], [schedulerServiceRef, scheduler], + [tokenManagerServiceRef, tokenManager], ], features: [bitbucketCloudEntityProviderCatalogModule()], }); @@ -79,6 +99,7 @@ describe('bitbucketCloudEntityProviderCatalogModule', () => { expect(addedProviders?.pop()?.getProviderName()).toEqual( 'bitbucketCloud-provider:default', ); + expect(addedSubscribers).toEqual(addedProviders); expect(runner).not.toHaveBeenCalled(); }); }); diff --git a/plugins/catalog-backend-module-bitbucket-cloud/src/service/BitbucketCloudEntityProviderCatalogModule.ts b/plugins/catalog-backend-module-bitbucket-cloud/src/service/BitbucketCloudEntityProviderCatalogModule.ts index d137bd7166..1c005991a6 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/src/service/BitbucketCloudEntityProviderCatalogModule.ts +++ b/plugins/catalog-backend-module-bitbucket-cloud/src/service/BitbucketCloudEntityProviderCatalogModule.ts @@ -20,8 +20,13 @@ import { loggerServiceRef, loggerToWinstonLogger, schedulerServiceRef, + tokenManagerServiceRef, } from '@backstage/backend-plugin-api'; -import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node'; +import { + catalogProcessingExtensionPoint, + catalogServiceRef, +} from '@backstage/plugin-catalog-node'; +import { eventsExtensionPoint } from '@backstage/plugin-events-node'; import { BitbucketCloudEntityProvider } from '../BitbucketCloudEntityProvider'; /** @@ -34,18 +39,34 @@ export const bitbucketCloudEntityProviderCatalogModule = createBackendModule({ env.registerInit({ deps: { catalog: catalogProcessingExtensionPoint, + catalogApi: catalogServiceRef, config: configServiceRef, + // TODO(pjungermann): How to make this optional for those which only want the provider without event support? + // Do we even want to support this? + events: eventsExtensionPoint, logger: loggerServiceRef, scheduler: schedulerServiceRef, + tokenManager: tokenManagerServiceRef, }, - async init({ catalog, config, logger, scheduler }) { + async init({ + catalog, + catalogApi, + config, + events, + logger, + scheduler, + tokenManager, + }) { const winstonLogger = loggerToWinstonLogger(logger); const providers = BitbucketCloudEntityProvider.fromConfig(config, { + catalogApi, logger: winstonLogger, scheduler, + tokenManager, }); catalog.addEntityProvider(providers); + events.addSubscribers(providers); }, }); }, diff --git a/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md index 1224da8bdd..6bd52de4b1 100644 --- a/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md +++ b/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-catalog-backend-module-bitbucket-server +## 0.1.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + ## 0.1.3-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-bitbucket-server/package.json b/plugins/catalog-backend-module-bitbucket-server/package.json index 594b5f0852..b2e3f81f04 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.3-next.0", + "version": "0.1.3-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -50,7 +50,7 @@ "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "luxon": "^3.0.0", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "alpha", diff --git a/plugins/catalog-backend-module-bitbucket/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket/CHANGELOG.md index 571c18de00..6a238bba10 100644 --- a/plugins/catalog-backend-module-bitbucket/CHANGELOG.md +++ b/plugins/catalog-backend-module-bitbucket/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-catalog-backend-module-bitbucket +## 0.2.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/types@1.0.1-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.1-next.0 + ## 0.2.5-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-bitbucket/package.json b/plugins/catalog-backend-module-bitbucket/package.json index 8ee6661b01..c3e7b21a27 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.5-next.0", + "version": "0.2.5-next.1", "deprecated": true, "main": "src/index.ts", "types": "src/index.ts", @@ -42,14 +42,14 @@ "@backstage/plugin-catalog-backend": "workspace:^", "@backstage/types": "workspace:^", "lodash": "^4.17.21", - "msw": "^0.47.0", "node-fetch": "^2.6.7", "winston": "^3.2.1" }, "devDependencies": { "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", - "@types/lodash": "^4.14.151" + "@types/lodash": "^4.14.151", + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/catalog-backend-module-gerrit/CHANGELOG.md b/plugins/catalog-backend-module-gerrit/CHANGELOG.md index a6babaf4fc..d249c5a9cb 100644 --- a/plugins/catalog-backend-module-gerrit/CHANGELOG.md +++ b/plugins/catalog-backend-module-gerrit/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-catalog-backend-module-gerrit +## 0.1.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + ## 0.1.6-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-gerrit/package.json b/plugins/catalog-backend-module-gerrit/package.json index c6d342640f..8f0ef8e735 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.6-next.0", + "version": "0.1.6-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -39,7 +39,6 @@ "@backstage/plugin-catalog-backend": "workspace:^", "@backstage/plugin-catalog-node": "workspace:^", "fs-extra": "10.1.0", - "msw": "^0.47.0", "node-fetch": "^2.6.7", "uuid": "^8.0.0", "winston": "^3.2.1" @@ -48,7 +47,8 @@ "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "@types/fs-extra": "^9.0.1", - "luxon": "^3.0.0" + "luxon": "^3.0.0", + "msw": "^0.48.0" }, "files": [ "dist", diff --git a/plugins/catalog-backend-module-github/CHANGELOG.md b/plugins/catalog-backend-module-github/CHANGELOG.md index b89231a422..fe13d4fb2a 100644 --- a/plugins/catalog-backend-module-github/CHANGELOG.md +++ b/plugins/catalog-backend-module-github/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-catalog-backend-module-github +## 0.2.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/types@1.0.1-next.0 + ## 0.2.0-next.0 ### Minor Changes diff --git a/plugins/catalog-backend-module-github/api-report.md b/plugins/catalog-backend-module-github/api-report.md index a9587e172b..e749549646 100644 --- a/plugins/catalog-backend-module-github/api-report.md +++ b/plugins/catalog-backend-module-github/api-report.md @@ -13,6 +13,8 @@ import { EntityProvider } from '@backstage/plugin-catalog-backend'; import { EntityProviderConnection } from '@backstage/plugin-catalog-backend'; import { GithubCredentialsProvider } from '@backstage/integration'; import { GithubIntegrationConfig } from '@backstage/integration'; +import { graphql } from '@octokit/graphql'; +import { GroupEntity } from '@backstage/catalog-model'; import { LocationSpec } from '@backstage/plugin-catalog-backend'; import { Logger } from 'winston'; import { PluginEndpointDiscovery } from '@backstage/backend-common'; @@ -21,6 +23,13 @@ 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; // @public export class GithubDiscoveryProcessor implements CatalogProcessor { @@ -129,6 +138,8 @@ export class GithubMultiOrgReaderProcessor implements CatalogProcessor { logger: Logger; orgs: GithubMultiOrgConfig; githubCredentialsProvider?: GithubCredentialsProvider; + userTransformer?: UserTransformer; + teamTransformer?: TeamTransformer; }); // (undocumented) static fromConfig( @@ -136,6 +147,8 @@ export class GithubMultiOrgReaderProcessor implements CatalogProcessor { options: { logger: Logger; githubCredentialsProvider?: GithubCredentialsProvider; + userTransformer?: UserTransformer; + teamTransformer?: TeamTransformer; }, ): GithubMultiOrgReaderProcessor; // (undocumented) @@ -165,6 +178,8 @@ export class GithubOrgEntityProvider implements EntityProvider { gitHubConfig: GithubIntegrationConfig; logger: Logger; githubCredentialsProvider?: GithubCredentialsProvider; + userTransformer?: UserTransformer; + teamTransformer?: TeamTransformer; }); // (undocumented) connect(connection: EntityProviderConnection): Promise; @@ -188,6 +203,8 @@ export interface GithubOrgEntityProviderOptions { logger: Logger; orgUrl: string; schedule?: 'manual' | TaskRunner; + teamTransformer?: TeamTransformer; + userTransformer?: UserTransformer; } // @public @@ -214,4 +231,48 @@ export class GithubOrgReaderProcessor implements CatalogProcessor { emit: CatalogProcessorEmit, ): Promise; } + +// @public +export type GithubTeam = { + slug: string; + combinedSlug: string; + name?: string; + description?: string; + avatarUrl?: string; + editTeamUrl?: string; + parentTeam?: GithubTeam; + members: GithubUser[]; +}; + +// @public +export type GithubUser = { + login: string; + bio?: string; + avatarUrl?: string; + email?: string; + name?: string; + organizationVerifiedDomainEmails?: string[]; +}; + +// @public +export type TeamTransformer = ( + item: GithubTeam, + ctx: TransformerContext, +) => Promise; + +// @public +export interface TransformerContext { + // (undocumented) + client: typeof graphql; + // (undocumented) + org: string; + // (undocumented) + query: string; +} + +// @public +export type UserTransformer = ( + item: GithubUser, + ctx: TransformerContext, +) => Promise; ``` diff --git a/plugins/catalog-backend-module-github/package.json b/plugins/catalog-backend-module-github/package.json index 60185636ea..68b5bad5cc 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.2.0-next.0", + "version": "0.2.0-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -48,7 +48,6 @@ "@octokit/rest": "^19.0.3", "git-url-parse": "^13.0.0", "lodash": "^4.17.21", - "msw": "^0.47.0", "node-fetch": "^2.6.7", "uuid": "^8.0.0", "winston": "^3.2.1" @@ -57,7 +56,8 @@ "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "@types/lodash": "^4.14.151", - "luxon": "^3.0.0" + "luxon": "^3.0.0", + "msw": "^0.48.0" }, "files": [ "dist", diff --git a/plugins/catalog-backend-module-github/src/index.ts b/plugins/catalog-backend-module-github/src/index.ts index f38035db15..5e2e55fc24 100644 --- a/plugins/catalog-backend-module-github/src/index.ts +++ b/plugins/catalog-backend-module-github/src/index.ts @@ -15,20 +15,31 @@ */ /** - * A Backstage catalog backend module that helps integrate towards GitHub + * A Backstage catalog backend module that helps integrate towards Github * * @packageDocumentation */ export { GithubLocationAnalyzer } from './analyzers/GithubLocationAnalyzer'; export type { GithubLocationAnalyzerOptions } from './analyzers/GithubLocationAnalyzer'; -export type { GithubMultiOrgConfig } from './lib'; export { GithubDiscoveryProcessor } from './processors/GithubDiscoveryProcessor'; export { GithubMultiOrgReaderProcessor } from './processors/GithubMultiOrgReaderProcessor'; export { GithubOrgReaderProcessor } from './processors/GithubOrgReaderProcessor'; export { GithubEntityProvider } from './providers/GithubEntityProvider'; -export { GithubOrgEntityProvider } from './providers/GithubOrgEntityProvider'; -export type { GithubOrgEntityProviderOptions } from './providers/GithubOrgEntityProvider'; +export type { + GithubOrgEntityProvider, + GithubOrgEntityProviderOptions, +} from './providers/GithubOrgEntityProvider'; export { githubEntityProviderCatalogModule } from './service/GithubEntityProviderCatalogModule'; +export { + type GithubMultiOrgConfig, + type GithubTeam, + type GithubUser, + type UserTransformer, + defaultUserTransformer, + type TeamTransformer, + defaultOrganizationTeamTransformer, + type TransformerContext, +} from './lib'; export * from './deprecated'; diff --git a/plugins/catalog-backend-module-github/src/lib/defaultTransformers.ts b/plugins/catalog-backend-module-github/src/lib/defaultTransformers.ts new file mode 100644 index 0000000000..efd3eedd5d --- /dev/null +++ b/plugins/catalog-backend-module-github/src/lib/defaultTransformers.ts @@ -0,0 +1,127 @@ +/* + * 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 { GroupEntity, UserEntity } from '@backstage/catalog-model'; +import { graphql } from '@octokit/graphql'; +import { GithubTeam, GithubUser } from './github'; + +/** + * Context passed to Transformers + * + * @public + */ +export interface TransformerContext { + client: typeof graphql; + query: string; + org: string; +} + +/** + * Transformer for GitHub users to UserEntity + * + * @public + */ +export type UserTransformer = ( + item: GithubUser, + ctx: TransformerContext, +) => Promise; + +/** + * Transformer for GitHub Team to GroupEntity + * + * @public + */ +export type TeamTransformer = ( + item: GithubTeam, + ctx: TransformerContext, +) => Promise; + +/** + * Default transformer for GitHub users to UserEntity + * + * @public + */ +export const defaultUserTransformer: UserTransformer = async ( + item: GithubUser, +) => { + const entity: UserEntity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'User', + metadata: { + name: item.login, + annotations: { + 'github.com/user-login': item.login, + }, + }, + spec: { + profile: {}, + memberOf: [], + }, + }; + + if (item.bio) entity.metadata.description = item.bio; + if (item.name) entity.spec.profile!.displayName = item.name; + if (item.email) entity.spec.profile!.email = item.email; + if (item.avatarUrl) entity.spec.profile!.picture = item.avatarUrl; + return entity; +}; + +/** + * Default transformer for GitHub Team to GroupEntity + * + * @public + */ +export const defaultOrganizationTeamTransformer: TeamTransformer = + async team => { + const annotations: { [annotationName: string]: string } = { + 'github.com/team-slug': team.combinedSlug, + }; + + if (team.editTeamUrl) { + annotations['backstage.io/edit-url'] = team.editTeamUrl; + } + + const entity: GroupEntity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Group', + metadata: { + name: team.slug, + annotations, + }, + spec: { + type: 'team', + profile: {}, + children: [], + }, + }; + + if (team.description) { + entity.metadata.description = team.description; + } + if (team.name) { + entity.spec.profile!.displayName = team.name; + } + if (team.avatarUrl) { + entity.spec.profile!.picture = team.avatarUrl; + } + if (team.parentTeam) { + entity.spec.parent = team.parentTeam.slug; + } + + entity.spec.members = team.members.map(user => user.login); + + return entity; + }; diff --git a/plugins/catalog-backend-module-github/src/lib/github.test.ts b/plugins/catalog-backend-module-github/src/lib/github.test.ts index 0002c4cef0..d07d2f6af8 100644 --- a/plugins/catalog-backend-module-github/src/lib/github.test.ts +++ b/plugins/catalog-backend-module-github/src/lib/github.test.ts @@ -15,15 +15,20 @@ */ import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; +import { GroupEntity, UserEntity } from '@backstage/catalog-model'; import { graphql } from '@octokit/graphql'; import { graphql as graphqlMsw } from 'msw'; import { setupServer } from 'msw/node'; +import { TeamTransformer, UserTransformer } from './defaultTransformers'; + import { getOrganizationTeams, getOrganizationUsers, getTeamMembers, getOrganizationRepositories, QueryResponse, + GithubUser, + GithubTeam, } from './github'; import fetch from 'node-fetch'; @@ -35,7 +40,7 @@ describe('github', () => { const server = setupServer(); setupRequestMockHandlers(server); - describe('getOrganizationUsers', () => { + describe('getOrganizationUsers using defaultUserMapper', () => { it('reads members', async () => { const input: QueryResponse = { organization: { @@ -76,7 +81,120 @@ describe('github', () => { }); }); - describe('getOrganizationTeams', () => { + describe('getOrganizationUsers using custom UserTransformer', () => { + const customUserTransformer: UserTransformer = async ( + item: GithubUser, + {}, + ) => { + if (item.login === 'aa') { + return undefined; + } + + return { + apiVersion: 'backstage.io/v1alpha1', + kind: 'User', + metadata: { + name: `${item.login}-custom`, + annotations: { + 'github.com/user-login': item.login, + }, + }, + spec: { + profile: {}, + memberOf: [], + }, + } as UserEntity; + }; + + it('reads members', async () => { + const input: QueryResponse = { + organization: { + membersWithRole: { + pageInfo: { hasNextPage: false }, + nodes: [ + { + login: 'a', + name: 'b', + bio: 'c', + email: 'd', + avatarUrl: 'e', + }, + ], + }, + }, + }; + + const output = { + users: [ + expect.objectContaining({ + metadata: expect.objectContaining({ + name: 'a-custom', + }), + }), + ], + }; + + server.use( + graphqlMsw.query('users', (_req, res, ctx) => res(ctx.data(input))), + ); + + await expect( + getOrganizationUsers(graphql, 'a', 'token', customUserTransformer), + ).resolves.toEqual(output); + }); + + it('reads members if undefined is returned from transformer', async () => { + const input: QueryResponse = { + organization: { + membersWithRole: { + pageInfo: { hasNextPage: false }, + nodes: [ + { + login: 'a', + name: 'b', + bio: 'c', + email: 'd', + avatarUrl: 'e', + }, + { + login: 'aa', + name: 'bb', + bio: 'cc', + email: 'dd', + avatarUrl: 'ee', + }, + ], + }, + }, + }; + + const output = { + users: [ + expect.objectContaining({ + metadata: expect.objectContaining({ + name: 'a-custom', + }), + }), + ], + }; + + server.use( + graphqlMsw.query('users', (_req, res, ctx) => res(ctx.data(input))), + ); + + const users = await getOrganizationUsers( + graphql, + 'a', + 'token', + customUserTransformer, + ); + + expect(users.users).toHaveLength(1); + expect(users).toEqual(output); + }); + }); + + describe('getOrganizationTeams using default TeamTransformer', () => { let input: QueryResponse; beforeEach(() => { @@ -95,7 +213,7 @@ describe('github', () => { parentTeam: { slug: 'parent', combinedSlug: '', - members: { pageInfo: { hasNextPage: false }, nodes: [] }, + members: [], }, members: { pageInfo: { hasNextPage: false }, @@ -129,10 +247,10 @@ describe('github', () => { }, parent: 'parent', children: [], + members: ['user'], }, }), ], - groupMemberUsers: new Map([['team', ['user']]]), }; server.use( @@ -141,37 +259,192 @@ describe('github', () => { await expect(getOrganizationTeams(graphql, 'a')).resolves.toEqual(output); }); + }); - it('applies namespaces', async () => { + describe('getOrganizationTeams using custom TeamTransformer', () => { + let input: QueryResponse; + + const customTeamTransformer: TeamTransformer = async ( + item: GithubTeam, + {}, + ) => { + if (item.name === 'aa') { + return undefined; + } + + return { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Group', + metadata: { + name: `${item.name}-custom`, + annotations: { + 'github.com/team-slug': 'blah/team', + 'backstage.io/edit-url': + 'http://example.com/orgs/blah/teams/team/edit', + }, + description: item.description, + }, + spec: { + type: 'team', + profile: { + displayName: `${item.name}-custom`, + picture: 'http://example.com/team.jpeg', + }, + parent: 'parent', + children: [], + members: ['user'], + }, + } as GroupEntity; + }; + + beforeEach(() => { + input = { + organization: { + teams: { + pageInfo: { hasNextPage: false }, + nodes: [ + { + slug: 'team', + combinedSlug: 'blah/team', + name: 'Team', + description: 'The one and only team', + avatarUrl: 'http://example.com/team.jpeg', + editTeamUrl: 'http://example.com/orgs/blah/teams/team/edit', + parentTeam: { + slug: 'parent', + combinedSlug: '', + members: [], + }, + members: { + pageInfo: { hasNextPage: false }, + nodes: [{ login: 'user' }], + }, + }, + ], + }, + }, + }; + }); + + it('reads teams', async () => { const output = { groups: [ expect.objectContaining({ metadata: expect.objectContaining({ - name: 'team', - namespace: 'foo', + name: 'Team-custom', description: 'The one and only team', + annotations: { + 'github.com/team-slug': 'blah/team', + 'backstage.io/edit-url': + 'http://example.com/orgs/blah/teams/team/edit', + }, }), spec: { type: 'team', profile: { - displayName: 'Team', + displayName: 'Team-custom', picture: 'http://example.com/team.jpeg', }, parent: 'parent', children: [], + members: ['user'], }, }), ], - groupMemberUsers: new Map([['foo/team', ['user']]]), }; server.use( graphqlMsw.query('teams', (_req, res, ctx) => res(ctx.data(input))), ); - await expect(getOrganizationTeams(graphql, 'a', 'foo')).resolves.toEqual( - output, + await expect( + getOrganizationTeams(graphql, 'a', customTeamTransformer), + ).resolves.toEqual(output); + }); + + it('reads teams if undefined is returned', async () => { + input = { + organization: { + teams: { + pageInfo: { hasNextPage: false }, + nodes: [ + { + slug: 'team', + combinedSlug: 'blah/team', + name: 'Team', + description: 'The one and only team', + avatarUrl: 'http://example.com/team.jpeg', + editTeamUrl: 'http://example.com/orgs/blah/teams/team/edit', + parentTeam: { + slug: 'parent', + combinedSlug: '', + members: [], + }, + members: { + pageInfo: { hasNextPage: false }, + nodes: [{ login: 'user' }], + }, + }, + { + slug: 'team', + combinedSlug: 'blah/team', + name: 'aa', + description: 'The one and only team', + avatarUrl: 'http://example.com/team.jpeg', + editTeamUrl: 'http://example.com/orgs/blah/teams/team/edit', + parentTeam: { + slug: 'parent', + combinedSlug: '', + members: [], + }, + members: { + pageInfo: { hasNextPage: false }, + nodes: [{ login: 'user' }], + }, + }, + ], + }, + }, + }; + + const output = { + groups: [ + expect.objectContaining({ + metadata: expect.objectContaining({ + name: 'Team-custom', + description: 'The one and only team', + annotations: { + 'github.com/team-slug': 'blah/team', + 'backstage.io/edit-url': + 'http://example.com/orgs/blah/teams/team/edit', + }, + }), + spec: { + type: 'team', + profile: { + displayName: 'Team-custom', + picture: 'http://example.com/team.jpeg', + }, + parent: 'parent', + children: [], + members: ['user'], + }, + }), + ], + }; + + server.use( + graphqlMsw.query('teams', (_req, res, ctx) => res(ctx.data(input))), ); + + const teams = await getOrganizationTeams( + graphql, + 'a', + customTeamTransformer, + ); + + expect(teams.groups).toHaveLength(1); + expect(teams).toEqual(output); }); }); @@ -191,7 +464,7 @@ describe('github', () => { }; const output = { - members: ['user'], + members: [{ login: 'user' }], }; server.use( diff --git a/plugins/catalog-backend-module-github/src/lib/github.ts b/plugins/catalog-backend-module-github/src/lib/github.ts index ef6a7f817a..4d583d0730 100644 --- a/plugins/catalog-backend-module-github/src/lib/github.ts +++ b/plugins/catalog-backend-module-github/src/lib/github.ts @@ -17,19 +17,30 @@ import { GroupEntity, UserEntity } from '@backstage/catalog-model'; import { GithubCredentialType } from '@backstage/integration'; import { graphql } from '@octokit/graphql'; +import { + defaultOrganizationTeamTransformer, + defaultUserTransformer, + TeamTransformer, + TransformerContext, + UserTransformer, +} from './defaultTransformers'; // Graphql types export type QueryResponse = { - organization?: Organization; - repositoryOwner?: Organization | User; + organization?: OrganizationResponse; + repositoryOwner?: RepositoryOwnerResponse; }; -export type Organization = { - membersWithRole?: Connection; - team?: Team; - teams?: Connection; - repositories?: Connection; +type RepositoryOwnerResponse = { + repositories?: Connection; +}; + +export type OrganizationResponse = { + membersWithRole?: Connection; + team?: GithubTeamResponse; + teams?: Connection; + repositories?: Connection; }; export type PageInfo = { @@ -37,27 +48,41 @@ export type PageInfo = { endCursor?: string; }; -export type User = { +/** + * Github User + * + * @public + */ +export type GithubUser = { login: string; bio?: string; avatarUrl?: string; email?: string; name?: string; - repositories?: Connection; + organizationVerifiedDomainEmails?: string[]; }; -export type Team = { +/** + * Github Team + * + * @public + */ +export type GithubTeam = { slug: string; combinedSlug: string; name?: string; description?: string; avatarUrl?: string; editTeamUrl?: string; - parentTeam?: Team; - members: Connection; + parentTeam?: GithubTeam; + members: GithubUser[]; }; -export type Repository = { +export type GithubTeamResponse = Omit & { + members: Connection; +}; + +export type RepositoryResponse = { name: string; url: string; isArchived: boolean; @@ -88,7 +113,7 @@ export type Connection = { }; /** - * Gets all the users out of a GitHub organization. + * Gets all the users out of a Github organization. * * Note that the users will not have their memberships filled in. * @@ -99,7 +124,7 @@ export async function getOrganizationUsers( client: typeof graphql, org: string, tokenType: GithubCredentialType, - userNamespace?: string, + userTransformer: UserTransformer = defaultUserTransformer, ): Promise<{ users: UserEntity[] }> { const query = ` query users($org: String!, $email: Boolean!, $cursor: String) { @@ -111,7 +136,8 @@ export async function getOrganizationUsers( bio, email @include(if: $email), login, - name + name, + organizationVerifiedDomainEmails(login: $org) } } } @@ -119,44 +145,24 @@ export async function getOrganizationUsers( // There is no user -> teams edge, so we leave the memberships empty for // now and let the team iteration handle it instead - const mapper = (user: User) => { - const entity: UserEntity = { - apiVersion: 'backstage.io/v1alpha1', - kind: 'User', - metadata: { - name: user.login, - annotations: { - 'github.com/user-login': user.login, - }, - }, - spec: { - profile: {}, - memberOf: [], - }, - }; - - if (userNamespace) entity.metadata.namespace = userNamespace; - if (user.bio) entity.metadata.description = user.bio; - if (user.name) entity.spec.profile!.displayName = user.name; - if (user.email) entity.spec.profile!.email = user.email; - if (user.avatarUrl) entity.spec.profile!.picture = user.avatarUrl; - - return entity; - }; const users = await queryWithPaging( client, query, + org, r => r.organization?.membersWithRole, - mapper, - { org, email: tokenType === 'token' }, + userTransformer, + { + org, + email: tokenType === 'token', + }, ); return { users }; } /** - * Gets all the teams out of a GitHub organization. + * Gets all the teams out of a Github organization. * * Note that the teams will not have any relations apart from parent filled in. * @@ -166,10 +172,9 @@ export async function getOrganizationUsers( export async function getOrganizationTeams( client: typeof graphql, org: string, - orgNamespace?: string, + teamTransformer: TeamTransformer = defaultOrganizationTeamTransformer, ): Promise<{ groups: GroupEntity[]; - groupMemberUsers: Map; }> { const query = ` query teams($org: String!, $cursor: String) { @@ -193,86 +198,51 @@ export async function getOrganizationTeams( } }`; - // Gets populated inside the mapper below - const groupMemberUsers = new Map(); + const materialisedTeams = async ( + item: GithubTeamResponse, + ctx: TransformerContext, + ): Promise => { + const memberNames: GithubUser[] = []; - const mapper = async (team: Team) => { - const annotations: { [annotationName: string]: string } = { - 'github.com/team-slug': team.combinedSlug, - }; - - if (team.editTeamUrl) { - annotations['backstage.io/edit-url'] = team.editTeamUrl; - } - - const entity: GroupEntity = { - apiVersion: 'backstage.io/v1alpha1', - kind: 'Group', - metadata: { - name: team.slug, - annotations, - }, - spec: { - type: 'team', - profile: {}, - children: [], - }, - }; - - if (orgNamespace) { - entity.metadata.namespace = orgNamespace; - } - - if (team.description) { - entity.metadata.description = team.description; - } - if (team.name) { - entity.spec.profile!.displayName = team.name; - } - if (team.avatarUrl) { - entity.spec.profile!.picture = team.avatarUrl; - } - if (team.parentTeam) { - entity.spec.parent = team.parentTeam.slug; - } - - const memberNames: string[] = []; - const groupKey = orgNamespace ? `${orgNamespace}/${team.slug}` : team.slug; - groupMemberUsers.set(groupKey, memberNames); - - if (!team.members.pageInfo.hasNextPage) { + if (!item.members.pageInfo.hasNextPage) { // We got all the members in one go, run the fast path - for (const user of team.members.nodes) { - memberNames.push(user.login); + for (const user of item.members.nodes) { + memberNames.push(user); } } else { // There were more than a hundred immediate members - run the slow // path of fetching them explicitly - const { members } = await getTeamMembers(client, org, team.slug); + const { members } = await getTeamMembers(ctx.client, ctx.org, item.slug); for (const userLogin of members) { memberNames.push(userLogin); } } - return entity; + const team: GithubTeam = { + ...item, + members: memberNames, + }; + + return await teamTransformer(team, ctx); }; const groups = await queryWithPaging( client, query, + org, r => r.organization?.teams, - mapper, + materialisedTeams, { org }, ); - return { groups, groupMemberUsers }; + return { groups }; } export async function getOrganizationRepositories( client: typeof graphql, org: string, catalogPath: string, -): Promise<{ repositories: Repository[] }> { +): Promise<{ repositories: RepositoryResponse[] }> { let relativeCatalogPathRef: string; // We must strip the leading slash or the query for objects does not work if (catalogPath.startsWith('/')) { @@ -321,8 +291,9 @@ export async function getOrganizationRepositories( const repositories = await queryWithPaging( client, query, + org, r => r.repositoryOwner?.repositories, - x => x, + async x => x, { org, catalogPathRef }, ); @@ -330,7 +301,7 @@ export async function getOrganizationRepositories( } /** - * Gets all the users out of a GitHub organization. + * Gets all the users out of a Github organization. * * Note that the users will not have their memberships filled in. * @@ -342,7 +313,7 @@ export async function getTeamMembers( client: typeof graphql, org: string, teamSlug: string, -): Promise<{ members: string[] }> { +): Promise<{ members: GithubUser[] }> { const query = ` query members($org: String!, $teamSlug: String!, $cursor: String) { organization(login: $org) { @@ -358,8 +329,9 @@ export async function getTeamMembers( const members = await queryWithPaging( client, query, + org, r => r.organization?.team?.members, - user => user.login, + async user => user, { org, teamSlug }, ); @@ -379,7 +351,7 @@ export async function getTeamMembers( * @param query - The query to execute * @param connection - A function that, given the response, picks out the actual * Connection object that's being iterated - * @param mapper - A function that, given one of the nodes in the Connection, + * @param transformer - A function that, given one of the nodes in the Connection, * returns the model mapped form of it * @param variables - The variable values that the query needs, minus the cursor */ @@ -391,8 +363,12 @@ export async function queryWithPaging< >( client: typeof graphql, query: string, + org: string, connection: (response: Response) => Connection | undefined, - mapper: (item: GraphqlType) => Promise | OutputType, + transformer: ( + item: GraphqlType, + ctx: TransformerContext, + ) => Promise, variables: Variables, ): Promise { const result: OutputType[] = []; @@ -410,7 +386,15 @@ export async function queryWithPaging< } for (const node of conn.nodes) { - result.push(await mapper(node)); + const transformedNode = await transformer(node, { + client, + query, + org, + }); + + if (transformedNode) { + result.push(transformedNode); + } } if (!conn.pageInfo.hasNextPage) { diff --git a/plugins/catalog-backend-module-github/src/lib/index.ts b/plugins/catalog-backend-module-github/src/lib/index.ts index 6402b69121..14f78fdeee 100644 --- a/plugins/catalog-backend-module-github/src/lib/index.ts +++ b/plugins/catalog-backend-module-github/src/lib/index.ts @@ -20,6 +20,15 @@ export { getOrganizationRepositories, getOrganizationTeams, getOrganizationUsers, + type GithubUser, + type GithubTeam, } from './github'; +export { + type UserTransformer, + defaultUserTransformer, + type TeamTransformer, + defaultOrganizationTeamTransformer, + type TransformerContext, +} from './defaultTransformers'; export { assignGroupsToUsers, buildOrgHierarchy } from './org'; export { parseGithubOrgUrl } from './util'; diff --git a/plugins/catalog-backend-module-github/src/lib/org.test.ts b/plugins/catalog-backend-module-github/src/lib/org.test.ts index 8a8f47642a..712c7c0b88 100644 --- a/plugins/catalog-backend-module-github/src/lib/org.test.ts +++ b/plugins/catalog-backend-module-github/src/lib/org.test.ts @@ -68,13 +68,47 @@ describe('buildOrgHierarchy', () => { describe('assignGroupsToUsers', () => { it('should assign groups to users', () => { const users: UserEntity[] = [u('u1'), u('u2')]; - const groupMemberUsers = new Map([ - ['g1', ['u1', 'u2']], - ['g2', ['u2']], - ['g3', ['u3']], - ]); - assignGroupsToUsers(users, groupMemberUsers); + const groups: GroupEntity[] = [ + { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Group', + metadata: { + name: 'g1', + }, + spec: { + type: 'team', + children: [], + members: ['u1', 'u2'], + }, + }, + { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Group', + metadata: { + name: 'g2', + }, + spec: { + type: 'team', + children: [], + members: ['u2'], + }, + }, + { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Group', + metadata: { + name: 'g3', + }, + spec: { + type: 'team', + children: [], + members: ['u3'], + }, + }, + ]; + + assignGroupsToUsers(users, groups); expect(users[0].spec.memberOf).toEqual(['g1']); expect(users[1].spec.memberOf).toEqual(['g1', 'g2']); diff --git a/plugins/catalog-backend-module-github/src/lib/org.ts b/plugins/catalog-backend-module-github/src/lib/org.ts index 79a96b5e71..275c5f4aeb 100644 --- a/plugins/catalog-backend-module-github/src/lib/org.ts +++ b/plugins/catalog-backend-module-github/src/lib/org.ts @@ -14,7 +14,11 @@ * limitations under the License. */ -import { GroupEntity, UserEntity } from '@backstage/catalog-model'; +import { + DEFAULT_NAMESPACE, + GroupEntity, + UserEntity, +} from '@backstage/catalog-model'; export function buildOrgHierarchy(groups: GroupEntity[]) { const groupsByName = new Map(groups.map(g => [g.metadata.name, g])); @@ -52,8 +56,19 @@ export function buildOrgHierarchy(groups: GroupEntity[]) { // Ensure that users have their direct group memberships. export function assignGroupsToUsers( users: UserEntity[], - groupMemberUsers: Map, + groups: GroupEntity[], ) { + const groupMemberUsers = new Map( + groups.map(group => { + const groupKey = + group.metadata.namespace && + group.metadata.namespace !== DEFAULT_NAMESPACE + ? `${group.metadata.namespace}/${group.metadata.name}` + : group.metadata.name; + return [groupKey, group.spec.members || []]; + }), + ); + const usersByName = new Map(users.map(u => [u.metadata.name, u])); for (const [groupName, userNames] of groupMemberUsers.entries()) { for (const userName of userNames) { diff --git a/plugins/catalog-backend-module-github/src/processors/GithubMultiOrgReaderProcessor.ts b/plugins/catalog-backend-module-github/src/processors/GithubMultiOrgReaderProcessor.ts index 7bb73990b3..745f52d6c5 100644 --- a/plugins/catalog-backend-module-github/src/processors/GithubMultiOrgReaderProcessor.ts +++ b/plugins/catalog-backend-module-github/src/processors/GithubMultiOrgReaderProcessor.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +import { GroupEntity } from '@backstage/catalog-model'; import { Config } from '@backstage/config'; import { DefaultGithubCredentialsProvider, @@ -32,11 +33,15 @@ import { import { graphql } from '@octokit/graphql'; import { Logger } from 'winston'; import { + assignGroupsToUsers, buildOrgHierarchy, + defaultOrganizationTeamTransformer, getOrganizationTeams, getOrganizationUsers, GithubMultiOrgConfig, readGithubMultiOrgConfig, + TeamTransformer, + UserTransformer, } from '../lib'; /** @@ -57,6 +62,8 @@ export class GithubMultiOrgReaderProcessor implements CatalogProcessor { options: { logger: Logger; githubCredentialsProvider?: GithubCredentialsProvider; + userTransformer?: UserTransformer; + teamTransformer?: TeamTransformer; }, ) { const c = config.getOptionalConfig('catalog.processors.githubMultiOrg'); @@ -69,12 +76,16 @@ export class GithubMultiOrgReaderProcessor implements CatalogProcessor { }); } - constructor(options: { - integrations: ScmIntegrationRegistry; - logger: Logger; - orgs: GithubMultiOrgConfig; - githubCredentialsProvider?: GithubCredentialsProvider; - }) { + constructor( + private options: { + integrations: ScmIntegrationRegistry; + logger: Logger; + orgs: GithubMultiOrgConfig; + githubCredentialsProvider?: GithubCredentialsProvider; + userTransformer?: UserTransformer; + teamTransformer?: TeamTransformer; + }, + ) { this.integrations = options.integrations; this.logger = options.logger; this.orgs = options.orgs; @@ -130,12 +141,22 @@ export class GithubMultiOrgReaderProcessor implements CatalogProcessor { client, orgConfig.name, tokenType, - orgConfig.userNamespace, + this.options.userTransformer, ); - const { groups, groupMemberUsers } = await getOrganizationTeams( + const { groups } = await getOrganizationTeams( client, orgConfig.name, - orgConfig.groupNamespace, + async (team, ctx): Promise => { + const result = this.options.teamTransformer + ? await this.options.teamTransformer(team, ctx) + : await defaultOrganizationTeamTransformer(team, ctx); + + if (result) { + result.metadata.namespace = orgConfig.groupNamespace; + } + + return result; + }, ); const duration = ((Date.now() - startTimestamp) / 1000).toFixed(1); @@ -151,15 +172,7 @@ export class GithubMultiOrgReaderProcessor implements CatalogProcessor { allUsersMap.set(prefix + u.metadata.name, u); } }); - - for (const [groupName, userNames] of groupMemberUsers.entries()) { - for (const userName of userNames) { - const user = allUsersMap.get(prefix + userName); - if (user && !user.spec.memberOf.includes(groupName)) { - user.spec.memberOf.push(groupName); - } - } - } + assignGroupsToUsers(users, groups); buildOrgHierarchy(groups); for (const group of groups) { diff --git a/plugins/catalog-backend-module-github/src/processors/GithubOrgReaderProcessor.ts b/plugins/catalog-backend-module-github/src/processors/GithubOrgReaderProcessor.ts index 0ef81ac907..90c168ccf4 100644 --- a/plugins/catalog-backend-module-github/src/processors/GithubOrgReaderProcessor.ts +++ b/plugins/catalog-backend-module-github/src/processors/GithubOrgReaderProcessor.ts @@ -101,17 +101,14 @@ export class GithubOrgReaderProcessor implements CatalogProcessor { this.logger.info('Reading GitHub users and groups'); const { users } = await getOrganizationUsers(client, org, tokenType); - const { groups, groupMemberUsers } = await getOrganizationTeams( - client, - org, - ); + const { groups } = await getOrganizationTeams(client, org); const duration = ((Date.now() - startTimestamp) / 1000).toFixed(1); this.logger.debug( `Read ${users.length} GitHub users and ${groups.length} GitHub groups in ${duration} seconds`, ); - assignGroupsToUsers(users, groupMemberUsers); + assignGroupsToUsers(users, groups); buildOrgHierarchy(groups); // Done! diff --git a/plugins/catalog-backend-module-github/src/providers/GithubEntityProvider.ts b/plugins/catalog-backend-module-github/src/providers/GithubEntityProvider.ts index 6d3badf865..9a75f52afa 100644 --- a/plugins/catalog-backend-module-github/src/providers/GithubEntityProvider.ts +++ b/plugins/catalog-backend-module-github/src/providers/GithubEntityProvider.ts @@ -37,7 +37,7 @@ import { readProviderConfigs, GithubEntityProviderConfig, } from './GithubEntityProviderConfig'; -import { getOrganizationRepositories, Repository } from '../lib/github'; +import { getOrganizationRepositories, RepositoryResponse } from '../lib/github'; import { satisfiesTopicFilter } from '../lib/util'; /** @@ -175,7 +175,7 @@ export class GithubEntityProvider implements EntityProvider { } // go to the server and get all of the repositories - private async findCatalogFiles(): Promise { + private async findCatalogFiles(): Promise { const organization = this.config.organization; const host = this.integration.host; const catalogPath = this.config.catalogPath; @@ -208,7 +208,7 @@ export class GithubEntityProvider implements EntityProvider { return repositories; } - private matchesFilters(repositories: Repository[]) { + private matchesFilters(repositories: RepositoryResponse[]) { const repositoryFilter = this.config.filters?.repository; const topicFilters = this.config.filters?.topic; @@ -226,7 +226,7 @@ export class GithubEntityProvider implements EntityProvider { return matchingRepositories; } - private createLocationUrl(repository: Repository): string { + private createLocationUrl(repository: RepositoryResponse): string { const branch = this.config.filters?.branch || repository.defaultBranchRef?.name || '-'; const catalogFile = this.config.catalogPath.startsWith('/') diff --git a/plugins/catalog-backend-module-github/src/providers/GithubOrgEntityProvider.test.ts b/plugins/catalog-backend-module-github/src/providers/GithubOrgEntityProvider.test.ts index b3fc5022ec..0b8765b93e 100644 --- a/plugins/catalog-backend-module-github/src/providers/GithubOrgEntityProvider.test.ts +++ b/plugins/catalog-backend-module-github/src/providers/GithubOrgEntityProvider.test.ts @@ -163,6 +163,7 @@ describe('GithubOrgEntityProvider', () => { picture: 'http://example.com/team.jpeg', }, type: 'team', + members: ['a'], }, }, locationKey: 'github-org-provider:my-id', diff --git a/plugins/catalog-backend-module-github/src/providers/GithubOrgEntityProvider.ts b/plugins/catalog-backend-module-github/src/providers/GithubOrgEntityProvider.ts index 2fc8ce7300..210df46363 100644 --- a/plugins/catalog-backend-module-github/src/providers/GithubOrgEntityProvider.ts +++ b/plugins/catalog-backend-module-github/src/providers/GithubOrgEntityProvider.ts @@ -43,6 +43,7 @@ import { getOrganizationUsers, parseGithubOrgUrl, } from '../lib'; +import { TeamTransformer, UserTransformer } from '../lib/defaultTransformers'; /** * Options for {@link GithubOrgEntityProvider}. @@ -88,6 +89,16 @@ export interface GithubOrgEntityProviderOptions { * Optionally supply a custom credentials provider, replacing the default one. */ githubCredentialsProvider?: GithubCredentialsProvider; + + /** + * Optionally include a user transformer for transforming from GitHub users to User Entities + */ + userTransformer?: UserTransformer; + + /** + * Optionally include a team transformer for transforming from GitHub teams to Group Entities + */ + teamTransformer?: TeamTransformer; } // TODO: Consider supporting an (optional) webhook that reacts on org changes @@ -123,6 +134,8 @@ export class GithubOrgEntityProvider implements EntityProvider { githubCredentialsProvider: options.githubCredentialsProvider || DefaultGithubCredentialsProvider.fromIntegrations(integrations), + userTransformer: options.userTransformer, + teamTransformer: options.teamTransformer, }); provider.schedule(options.schedule); @@ -137,6 +150,8 @@ export class GithubOrgEntityProvider implements EntityProvider { gitHubConfig: GithubIntegrationConfig; logger: Logger; githubCredentialsProvider?: GithubCredentialsProvider; + userTransformer?: UserTransformer; + teamTransformer?: TeamTransformer; }, ) { this.credentialsProvider = @@ -177,12 +192,19 @@ export class GithubOrgEntityProvider implements EntityProvider { }); const { org } = parseGithubOrgUrl(this.options.orgUrl); - const { users } = await getOrganizationUsers(client, org, tokenType); - const { groups, groupMemberUsers } = await getOrganizationTeams( + const { users } = await getOrganizationUsers( client, org, + tokenType, + this.options.userTransformer, ); - assignGroupsToUsers(users, groupMemberUsers); + const { groups } = await getOrganizationTeams( + client, + org, + this.options.teamTransformer, + ); + + assignGroupsToUsers(users, groups); buildOrgHierarchy(groups); const { markCommitComplete } = markReadComplete({ users, groups }); diff --git a/plugins/catalog-backend-module-gitlab/CHANGELOG.md b/plugins/catalog-backend-module-gitlab/CHANGELOG.md index 18cce9e01e..e4faffa798 100644 --- a/plugins/catalog-backend-module-gitlab/CHANGELOG.md +++ b/plugins/catalog-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-catalog-backend-module-gitlab +## 0.1.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/types@1.0.1-next.0 + ## 0.1.9-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-gitlab/package.json b/plugins/catalog-backend-module-gitlab/package.json index e556d4b2de..9ac4f39d86 100644 --- a/plugins/catalog-backend-module-gitlab/package.json +++ b/plugins/catalog-backend-module-gitlab/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-gitlab", "description": "A Backstage catalog backend module that helps integrate towards GitLab", - "version": "0.1.9-next.0", + "version": "0.1.9-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -44,7 +44,6 @@ "@backstage/plugin-catalog-node": "workspace:^", "@backstage/types": "workspace:^", "lodash": "^4.17.21", - "msw": "^0.47.0", "node-fetch": "^2.6.7", "uuid": "^8.0.0", "winston": "^3.2.1" @@ -54,7 +53,8 @@ "@backstage/cli": "workspace:^", "@types/lodash": "^4.14.151", "@types/uuid": "^8.0.0", - "luxon": "^3.0.0" + "luxon": "^3.0.0", + "msw": "^0.48.0" }, "files": [ "alpha", diff --git a/plugins/catalog-backend-module-ldap/CHANGELOG.md b/plugins/catalog-backend-module-ldap/CHANGELOG.md index 8a58fce1f5..b440841f88 100644 --- a/plugins/catalog-backend-module-ldap/CHANGELOG.md +++ b/plugins/catalog-backend-module-ldap/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-catalog-backend-module-ldap +## 0.5.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/types@1.0.1-next.0 + ## 0.5.5-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-ldap/package.json b/plugins/catalog-backend-module-ldap/package.json index d095be6b5c..9154272cac 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.5-next.0", + "version": "0.5.5-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-msgraph/CHANGELOG.md b/plugins/catalog-backend-module-msgraph/CHANGELOG.md index 8b8d4479d3..cf0885b81a 100644 --- a/plugins/catalog-backend-module-msgraph/CHANGELOG.md +++ b/plugins/catalog-backend-module-msgraph/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-catalog-backend-module-msgraph +## 0.4.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + ## 0.4.4-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-msgraph/package.json b/plugins/catalog-backend-module-msgraph/package.json index cf301c71a0..1aa5bc82c7 100644 --- a/plugins/catalog-backend-module-msgraph/package.json +++ b/plugins/catalog-backend-module-msgraph/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-msgraph", "description": "A Backstage catalog backend module that helps integrate towards Microsoft Graph", - "version": "0.4.4-next.0", + "version": "0.4.4-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -55,7 +55,7 @@ "@backstage/cli": "workspace:^", "@types/lodash": "^4.14.151", "luxon": "^3.0.0", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "alpha", diff --git a/plugins/catalog-backend-module-openapi/CHANGELOG.md b/plugins/catalog-backend-module-openapi/CHANGELOG.md index 0dc46b07a7..9be6f527f7 100644 --- a/plugins/catalog-backend-module-openapi/CHANGELOG.md +++ b/plugins/catalog-backend-module-openapi/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-catalog-backend-module-openapi +## 0.1.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/types@1.0.1-next.0 + ## 0.1.4-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-openapi/package.json b/plugins/catalog-backend-module-openapi/package.json index 6f21b8b2e0..86039aa2c7 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.4-next.0", + "version": "0.1.4-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 494f332c12..ef86889498 100644 --- a/plugins/catalog-backend/CHANGELOG.md +++ b/plugins/catalog-backend/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-catalog-backend +## 1.5.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/plugin-permission-node@0.7.1-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/types@1.0.1-next.0 + - @backstage/plugin-catalog-common@1.0.8-next.0 + - @backstage/plugin-permission-common@0.7.1-next.0 + - @backstage/plugin-scaffolder-common@1.2.2-next.0 + - @backstage/plugin-search-common@1.1.1-next.0 + ## 1.5.1-next.0 ### Patch Changes diff --git a/plugins/catalog-backend/package.json b/plugins/catalog-backend/package.json index b18a133505..abfd64c20f 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.5.1-next.0", + "version": "1.5.1-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -80,7 +80,7 @@ "@types/uuid": "^8.0.0", "better-sqlite3": "^7.5.0", "luxon": "^3.0.0", - "msw": "^0.47.0", + "msw": "^0.48.0", "supertest": "^6.1.3", "wait-for-expect": "^3.0.2" }, diff --git a/plugins/catalog-backend/src/processing/DefaultCatalogProcessingEngine.ts b/plugins/catalog-backend/src/processing/DefaultCatalogProcessingEngine.ts index 2cc0e2dc40..bef2878099 100644 --- a/plugins/catalog-backend/src/processing/DefaultCatalogProcessingEngine.ts +++ b/plugins/catalog-backend/src/processing/DefaultCatalogProcessingEngine.ts @@ -14,7 +14,11 @@ * limitations under the License. */ -import { Entity, stringifyEntityRef } from '@backstage/catalog-model'; +import { + ANNOTATION_LOCATION, + Entity, + stringifyEntityRef, +} from '@backstage/catalog-model'; import { assertError, serializeError, stringifyError } from '@backstage/errors'; import { Hash } from 'crypto'; import stableStringify from 'fast-json-stable-stringify'; @@ -116,11 +120,12 @@ export class DefaultCatalogProcessingEngine implements CatalogProcessingEngine { }); } + const location = + unprocessedEntity?.metadata?.annotations?.[ANNOTATION_LOCATION]; for (const error of result.errors) { - // TODO(freben): Try to extract the location out of the unprocessed - // entity and add as meta to the log lines this.logger.warn(error.message, { entity: entityRef, + location, }); } const errorsString = JSON.stringify( diff --git a/plugins/catalog-customized/CHANGELOG.md b/plugins/catalog-customized/CHANGELOG.md index 04be429ab6..f515902ead 100644 --- a/plugins/catalog-customized/CHANGELOG.md +++ b/plugins/catalog-customized/CHANGELOG.md @@ -1,5 +1,13 @@ # @internal/plugin-catalog-customized +## 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 diff --git a/plugins/catalog-customized/package.json b/plugins/catalog-customized/package.json index 537180f05e..ea61d95bdd 100644 --- a/plugins/catalog-customized/package.json +++ b/plugins/catalog-customized/package.json @@ -1,7 +1,7 @@ { "name": "@internal/plugin-catalog-customized", "description": "The internal Backstage Customizable plugin for browsing the Backstage catalog", - "version": "0.0.4-next.0", + "version": "0.0.4-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-graph/CHANGELOG.md b/plugins/catalog-graph/CHANGELOG.md index 7f8e1e0277..38b921bb1f 100644 --- a/plugins/catalog-graph/CHANGELOG.md +++ b/plugins/catalog-graph/CHANGELOG.md @@ -1,5 +1,26 @@ # @backstage/plugin-catalog-graph +## 0.2.23-next.1 + +### Patch Changes + +- da0bf25d1a: Preserve graph options and increment `maxDepth` by 1. + + The change will preserve options used at the `CatalogGraphCard` + (displayed at the entity page) and additionally, increments the + `maxDepth` option by 1 to increase the scope slightly compared to + the graph already seen by the users. + + The default for `maxDepth` at `CatalogGraphCard` is 1. + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.2.23-next.0 ### Patch Changes diff --git a/plugins/catalog-graph/package.json b/plugins/catalog-graph/package.json index 3b78d5d7ba..43983c171a 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.23-next.0", + "version": "0.2.23-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-graph/src/components/CatalogGraphCard/CatalogGraphCard.tsx b/plugins/catalog-graph/src/components/CatalogGraphCard/CatalogGraphCard.tsx index 5cb86db69f..40ee90d784 100644 --- a/plugins/catalog-graph/src/components/CatalogGraphCard/CatalogGraphCard.tsx +++ b/plugins/catalog-graph/src/components/CatalogGraphCard/CatalogGraphCard.tsx @@ -39,18 +39,21 @@ import { RelationPairs, } from '../EntityRelationsGraph'; -const useStyles = makeStyles({ - card: ({ height }) => ({ - display: 'flex', - flexDirection: 'column', - maxHeight: height, - minHeight: height, - }), - graph: { - flex: 1, - minHeight: 0, +const useStyles = makeStyles( + { + card: ({ height }) => ({ + display: 'flex', + flexDirection: 'column', + maxHeight: height, + minHeight: height, + }), + graph: { + flex: 1, + minHeight: 0, + }, }, -}); + { name: 'PluginCatalogGraphCatalogGraphCard' }, +); export const CatalogGraphCard = (props: { variant?: InfoCardVariants; diff --git a/plugins/catalog-graph/src/components/CatalogGraphPage/CatalogGraphPage.tsx b/plugins/catalog-graph/src/components/CatalogGraphPage/CatalogGraphPage.tsx index a6a6c2a711..4a36d516e2 100644 --- a/plugins/catalog-graph/src/components/CatalogGraphPage/CatalogGraphPage.tsx +++ b/plugins/catalog-graph/src/components/CatalogGraphPage/CatalogGraphPage.tsx @@ -48,57 +48,60 @@ import { SelectedRelationsFilter } from './SelectedRelationsFilter'; import { SwitchFilter } from './SwitchFilter'; import { useCatalogGraphPage } from './useCatalogGraphPage'; -const useStyles = makeStyles(theme => ({ - content: { - minHeight: 0, - }, - container: { - height: '100%', - maxHeight: '100%', - minHeight: 0, - }, - fullHeight: { - maxHeight: '100%', - display: 'flex', - minHeight: 0, - }, - graphWrapper: { - position: 'relative', - flex: 1, - minHeight: 0, - display: 'flex', - }, - graph: { - flex: 1, - minHeight: 0, - }, - legend: { - position: 'absolute', - bottom: 0, - right: 0, - padding: theme.spacing(1), - '& .icon': { - verticalAlign: 'bottom', +const useStyles = makeStyles( + theme => ({ + content: { + minHeight: 0, }, - }, - filters: { - display: 'grid', - gridGap: theme.spacing(1), - gridAutoRows: 'auto', - [theme.breakpoints.up('lg')]: { - display: 'block', + container: { + height: '100%', + maxHeight: '100%', + minHeight: 0, }, - [theme.breakpoints.only('md')]: { - gridTemplateColumns: 'repeat(3, 1fr)', + fullHeight: { + maxHeight: '100%', + display: 'flex', + minHeight: 0, }, - [theme.breakpoints.only('sm')]: { - gridTemplateColumns: 'repeat(2, 1fr)', + graphWrapper: { + position: 'relative', + flex: 1, + minHeight: 0, + display: 'flex', }, - [theme.breakpoints.down('xs')]: { - gridTemplateColumns: 'repeat(1, 1fr)', + graph: { + flex: 1, + minHeight: 0, }, - }, -})); + legend: { + position: 'absolute', + bottom: 0, + right: 0, + padding: theme.spacing(1), + '& .icon': { + verticalAlign: 'bottom', + }, + }, + filters: { + display: 'grid', + gridGap: theme.spacing(1), + gridAutoRows: 'auto', + [theme.breakpoints.up('lg')]: { + display: 'block', + }, + [theme.breakpoints.only('md')]: { + gridTemplateColumns: 'repeat(3, 1fr)', + }, + [theme.breakpoints.only('sm')]: { + gridTemplateColumns: 'repeat(2, 1fr)', + }, + [theme.breakpoints.down('xs')]: { + gridTemplateColumns: 'repeat(1, 1fr)', + }, + }, + }), + { name: 'PluginCatalogGraphCatalogGraphPage' }, +); export const CatalogGraphPage = (props: { relationPairs?: RelationPairs; diff --git a/plugins/catalog-graph/src/components/CatalogGraphPage/MaxDepthFilter.tsx b/plugins/catalog-graph/src/components/CatalogGraphPage/MaxDepthFilter.tsx index 7828a60fb6..b6b03d8831 100644 --- a/plugins/catalog-graph/src/components/CatalogGraphPage/MaxDepthFilter.tsx +++ b/plugins/catalog-graph/src/components/CatalogGraphPage/MaxDepthFilter.tsx @@ -30,12 +30,15 @@ export type Props = { onChange: (value: number) => void; }; -const useStyles = makeStyles({ - formControl: { - width: '100%', - maxWidth: 300, +const useStyles = makeStyles( + { + formControl: { + width: '100%', + maxWidth: 300, + }, }, -}); + { name: 'PluginCatalogGraphMaxDepthFilter' }, +); export const MaxDepthFilter = ({ value, onChange }: Props) => { const classes = useStyles(); diff --git a/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedKindsFilter.tsx b/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedKindsFilter.tsx index 316f83da62..0817a01e0b 100644 --- a/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedKindsFilter.tsx +++ b/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedKindsFilter.tsx @@ -30,11 +30,14 @@ import { Autocomplete } from '@material-ui/lab'; import React, { useCallback, useEffect, useMemo } from 'react'; import useAsync from 'react-use/lib/useAsync'; -const useStyles = makeStyles({ - formControl: { - maxWidth: 300, +const useStyles = makeStyles( + { + formControl: { + maxWidth: 300, + }, }, -}); + { name: 'PluginCatalogGraphSelectedKindsFilter' }, +); export type Props = { value: string[] | undefined; diff --git a/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedRelationsFilter.tsx b/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedRelationsFilter.tsx index 839bfbe425..197f65cef8 100644 --- a/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedRelationsFilter.tsx +++ b/plugins/catalog-graph/src/components/CatalogGraphPage/SelectedRelationsFilter.tsx @@ -28,11 +28,14 @@ import { Autocomplete } from '@material-ui/lab'; import React, { useCallback, useMemo } from 'react'; import { RelationPairs } from '../EntityRelationsGraph'; -const useStyles = makeStyles({ - formControl: { - maxWidth: 300, +const useStyles = makeStyles( + { + formControl: { + maxWidth: 300, + }, }, -}); + { name: 'PluginCatalogGraphSelectedRelationsFilter' }, +); export type Props = { relationPairs: RelationPairs; diff --git a/plugins/catalog-graph/src/components/CatalogGraphPage/SwitchFilter.tsx b/plugins/catalog-graph/src/components/CatalogGraphPage/SwitchFilter.tsx index 214080db6e..495f6b4db2 100644 --- a/plugins/catalog-graph/src/components/CatalogGraphPage/SwitchFilter.tsx +++ b/plugins/catalog-graph/src/components/CatalogGraphPage/SwitchFilter.tsx @@ -22,12 +22,15 @@ export type Props = { onChange: (value: boolean) => void; }; -const useStyles = makeStyles({ - root: { - width: '100%', - maxWidth: 300, +const useStyles = makeStyles( + { + root: { + width: '100%', + maxWidth: 300, + }, }, -}); + { name: 'PluginCatalogGraphSwitchFilter' }, +); export const SwitchFilter = ({ label, value, onChange }: Props) => { const classes = useStyles(); diff --git a/plugins/catalog-graph/src/components/EntityRelationsGraph/CustomLabel.tsx b/plugins/catalog-graph/src/components/EntityRelationsGraph/CustomLabel.tsx index 60a858eee6..19082cfe81 100644 --- a/plugins/catalog-graph/src/components/EntityRelationsGraph/CustomLabel.tsx +++ b/plugins/catalog-graph/src/components/EntityRelationsGraph/CustomLabel.tsx @@ -20,14 +20,17 @@ import React from 'react'; import { EntityEdgeData } from './types'; import classNames from 'classnames'; -const useStyles = makeStyles((theme: BackstageTheme) => ({ - text: { - fill: theme.palette.textContrast, - }, - secondary: { - fill: theme.palette.textSubtle, - }, -})); +const useStyles = makeStyles( + (theme: BackstageTheme) => ({ + text: { + fill: theme.palette.textContrast, + }, + secondary: { + fill: theme.palette.textSubtle, + }, + }), + { name: 'PluginCatalogGraphCustomLabel' }, +); export function CustomLabel({ edge: { relations }, diff --git a/plugins/catalog-graph/src/components/EntityRelationsGraph/CustomNode.tsx b/plugins/catalog-graph/src/components/EntityRelationsGraph/CustomNode.tsx index ae541fa997..edcdb97fcb 100644 --- a/plugins/catalog-graph/src/components/EntityRelationsGraph/CustomNode.tsx +++ b/plugins/catalog-graph/src/components/EntityRelationsGraph/CustomNode.tsx @@ -22,37 +22,40 @@ import React, { useLayoutEffect, useRef, useState } from 'react'; import { EntityKindIcon } from './EntityKindIcon'; import { EntityNodeData } from './types'; -const useStyles = makeStyles((theme: BackstageTheme) => ({ - node: { - fill: theme.palette.grey[300], - stroke: theme.palette.grey[300], +const useStyles = makeStyles( + (theme: BackstageTheme) => ({ + node: { + fill: theme.palette.grey[300], + stroke: theme.palette.grey[300], - '&.primary': { - fill: theme.palette.primary.light, - stroke: theme.palette.primary.light, + '&.primary': { + fill: theme.palette.primary.light, + stroke: theme.palette.primary.light, + }, + '&.secondary': { + fill: theme.palette.secondary.light, + stroke: theme.palette.secondary.light, + }, }, - '&.secondary': { - fill: theme.palette.secondary.light, - stroke: theme.palette.secondary.light, - }, - }, - text: { - fill: theme.palette.getContrastText(theme.palette.grey[300]), + text: { + fill: theme.palette.getContrastText(theme.palette.grey[300]), - '&.primary': { - fill: theme.palette.primary.contrastText, + '&.primary': { + fill: theme.palette.primary.contrastText, + }, + '&.secondary': { + fill: theme.palette.secondary.contrastText, + }, + '&.focused': { + fontWeight: 'bold', + }, }, - '&.secondary': { - fill: theme.palette.secondary.contrastText, + clickable: { + cursor: 'pointer', }, - '&.focused': { - fontWeight: 'bold', - }, - }, - clickable: { - cursor: 'pointer', - }, -})); + }), + { name: 'PluginCatalogGraphCustomNode' }, +); export function CustomNode({ node: { diff --git a/plugins/catalog-graph/src/components/EntityRelationsGraph/EntityRelationsGraph.tsx b/plugins/catalog-graph/src/components/EntityRelationsGraph/EntityRelationsGraph.tsx index c0e2f610c1..72ec4b4aed 100644 --- a/plugins/catalog-graph/src/components/EntityRelationsGraph/EntityRelationsGraph.tsx +++ b/plugins/catalog-graph/src/components/EntityRelationsGraph/EntityRelationsGraph.tsx @@ -32,36 +32,39 @@ import { ALL_RELATION_PAIRS, RelationPairs } from './relations'; import { Direction, EntityEdge, EntityNode } from './types'; import { useEntityRelationNodesAndEdges } from './useEntityRelationNodesAndEdges'; -const useStyles = makeStyles(theme => ({ - progress: { - position: 'absolute', - left: '50%', - top: '50%', - marginLeft: '-20px', - marginTop: '-20px', - }, - container: { - position: 'relative', - width: '100%', - display: 'flex', - flexDirection: 'column', - }, - graph: { - width: '100%', - flex: 1, - // Right now there is no good way to style edges between nodes, we have to - // fallback to these hacks: - '& path[marker-end]': { - transition: 'filter 0.1s ease-in-out', +const useStyles = makeStyles( + theme => ({ + progress: { + position: 'absolute', + left: '50%', + top: '50%', + marginLeft: '-20px', + marginTop: '-20px', }, - '& path[marker-end]:hover': { - filter: `drop-shadow(2px 2px 4px ${theme.palette.primary.dark});`, + container: { + position: 'relative', + width: '100%', + display: 'flex', + flexDirection: 'column', }, - '& g[data-testid=label]': { - transition: 'transform 0s', + graph: { + width: '100%', + flex: 1, + // Right now there is no good way to style edges between nodes, we have to + // fallback to these hacks: + '& path[marker-end]': { + transition: 'filter 0.1s ease-in-out', + }, + '& path[marker-end]:hover': { + filter: `drop-shadow(2px 2px 4px ${theme.palette.primary.dark});`, + }, + '& g[data-testid=label]': { + transition: 'transform 0s', + }, }, - }, -})); + }), + { name: 'PluginCatalogGraphEntityRelationsGraph' }, +); /** * Core building block for custom entity relations diagrams. diff --git a/plugins/catalog-graphql/package.json b/plugins/catalog-graphql/package.json index 503c7eb3b0..1accb40a49 100644 --- a/plugins/catalog-graphql/package.json +++ b/plugins/catalog-graphql/package.json @@ -53,7 +53,7 @@ "@graphql-codegen/typescript": "^2.4.2", "@graphql-codegen/typescript-resolvers": "^2.4.3", "@graphql-tools/schema": "^9.0.0", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/catalog-import/CHANGELOG.md b/plugins/catalog-import/CHANGELOG.md index 8562b77510..1d0d1d56af 100644 --- a/plugins/catalog-import/CHANGELOG.md +++ b/plugins/catalog-import/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-catalog-import +## 0.9.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/integration-react@1.1.6-next.1 + - @backstage/plugin-catalog-common@1.0.8-next.0 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.9.1-next.0 ### Patch Changes diff --git a/plugins/catalog-import/package.json b/plugins/catalog-import/package.json index b8cacc4450..a097e2efeb 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.9.1-next.0", + "version": "0.9.1-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -68,7 +68,7 @@ "@testing-library/react-hooks": "^8.0.0", "@testing-library/user-event": "^14.0.0", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist", diff --git a/plugins/catalog-node/CHANGELOG.md b/plugins/catalog-node/CHANGELOG.md index ffbd18cd8e..f145bf6595 100644 --- a/plugins/catalog-node/CHANGELOG.md +++ b/plugins/catalog-node/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-catalog-node +## 1.2.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/types@1.0.1-next.0 + - @backstage/plugin-catalog-common@1.0.8-next.0 + ## 1.2.1-next.0 ### Patch Changes diff --git a/plugins/catalog-node/package.json b/plugins/catalog-node/package.json index 320f372249..3e64105dff 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.2.1-next.0", + "version": "1.2.1-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-react/CHANGELOG.md b/plugins/catalog-react/CHANGELOG.md index 3019049086..df8ae144a0 100644 --- a/plugins/catalog-react/CHANGELOG.md +++ b/plugins/catalog-react/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-catalog-react +## 1.2.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/types@1.0.1-next.0 + - @backstage/version-bridge@1.0.1 + - @backstage/plugin-catalog-common@1.0.8-next.0 + - @backstage/plugin-permission-common@0.7.1-next.0 + - @backstage/plugin-permission-react@0.4.7-next.0 + ## 1.2.1-next.0 ### Patch Changes diff --git a/plugins/catalog-react/package.json b/plugins/catalog-react/package.json index c2363fdc76..c15190eaca 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.2.1-next.0", + "version": "1.2.1-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 e95afd8617..8251b94a22 100644 --- a/plugins/catalog/CHANGELOG.md +++ b/plugins/catalog/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-catalog +## 1.6.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration-react@1.1.6-next.1 + - @backstage/theme@0.2.16 + - @backstage/types@1.0.1-next.0 + - @backstage/plugin-catalog-common@1.0.8-next.0 + - @backstage/plugin-catalog-react@1.2.1-next.1 + - @backstage/plugin-search-common@1.1.1-next.0 + - @backstage/plugin-search-react@1.2.1-next.1 + ## 1.6.1-next.0 ### Patch Changes diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json index de2833c470..9354e6ca5a 100644 --- a/plugins/catalog/package.json +++ b/plugins/catalog/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog", "description": "The Backstage plugin for browsing the Backstage catalog", - "version": "1.6.1-next.0", + "version": "1.6.1-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/cicd-statistics-module-gitlab/CHANGELOG.md b/plugins/cicd-statistics-module-gitlab/CHANGELOG.md index e394418c24..ede5ef942a 100644 --- a/plugins/cicd-statistics-module-gitlab/CHANGELOG.md +++ b/plugins/cicd-statistics-module-gitlab/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-cicd-statistics-module-gitlab +## 0.1.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/plugin-cicd-statistics@0.1.13-next.1 + ## 0.1.7-next.0 ### Patch Changes diff --git a/plugins/cicd-statistics-module-gitlab/package.json b/plugins/cicd-statistics-module-gitlab/package.json index 5f6d5039bf..e6a0b84833 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.7-next.0", + "version": "0.1.7-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 29852c597f..028ac177e7 100644 --- a/plugins/cicd-statistics/CHANGELOG.md +++ b/plugins/cicd-statistics/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-cicd-statistics +## 0.1.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.1.13-next.0 ### Patch Changes diff --git a/plugins/cicd-statistics/package.json b/plugins/cicd-statistics/package.json index 5cfac4666e..b12bbb7643 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.13-next.0", + "version": "0.1.13-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 b9d916f75a..5bd5ed01fa 100644 --- a/plugins/circleci/CHANGELOG.md +++ b/plugins/circleci/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-circleci +## 0.3.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.3.11-next.0 ### Patch Changes diff --git a/plugins/circleci/package.json b/plugins/circleci/package.json index d5f36ba7d6..fa4fa12d07 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.11-next.0", + "version": "0.3.11-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -63,7 +63,7 @@ "@types/humanize-duration": "^3.25.1", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/cloudbuild/CHANGELOG.md b/plugins/cloudbuild/CHANGELOG.md index bc83c46375..1f91ea1d5d 100644 --- a/plugins/cloudbuild/CHANGELOG.md +++ b/plugins/cloudbuild/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-cloudbuild +## 0.3.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.3.11-next.0 ### Patch Changes diff --git a/plugins/cloudbuild/package.json b/plugins/cloudbuild/package.json index ee2cf54177..5727c55bc7 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.11-next.0", + "version": "0.3.11-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -60,7 +60,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/code-climate/CHANGELOG.md b/plugins/code-climate/CHANGELOG.md index 20965a33a5..b4f701f7fa 100644 --- a/plugins/code-climate/CHANGELOG.md +++ b/plugins/code-climate/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-code-climate +## 0.1.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.1.11-next.0 ### Patch Changes diff --git a/plugins/code-climate/package.json b/plugins/code-climate/package.json index 735c5d2c5e..8cde9a28ed 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.11-next.0", + "version": "0.1.11-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -49,7 +49,7 @@ "@types/luxon": "^3.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/code-coverage-backend/CHANGELOG.md b/plugins/code-coverage-backend/CHANGELOG.md index 251cfa1b33..d798c3ec74 100644 --- a/plugins/code-coverage-backend/CHANGELOG.md +++ b/plugins/code-coverage-backend/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-code-coverage-backend +## 0.2.4-next.1 + +### Patch Changes + +- fcab2579a0: Adds installation instructions +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + ## 0.2.4-next.0 ### Patch Changes diff --git a/plugins/code-coverage-backend/README.md b/plugins/code-coverage-backend/README.md index 4cfc187a3d..ae6021b07c 100644 --- a/plugins/code-coverage-backend/README.md +++ b/plugins/code-coverage-backend/README.md @@ -2,6 +2,68 @@ This is the backend part of the `code-coverage` plugin. It takes care of processing various coverage formats and standardizing them into a single json format, used by the frontend. +## Installation + +`yarn workspace backend add @backstage/plugin-code-coverage-backend` + +First create a `codecoverage.ts` file here: `packages/backend/src/plugins`. Now add the following as its content: + +```diff +diff --git a/packages/backend/src/plugins/codecoverage.ts b/packages/backend/src/plugins/codecoverage.ts +--- /dev/null ++++ b/packages/backend/src/plugins/codecoverage.ts +@@ -0,0 +1,15 @@ ++import { createRouter } from '@backstage/plugin-code-coverage-backend'; ++import { Router } from 'express'; ++import { PluginEnvironment } from '../types'; ++ ++export default async function createPlugin( ++ env: PluginEnvironment, ++): Promise { ++ return await createRouter({ ++ config: env.config, ++ discovery: env.discovery, ++ database: env.database, ++ urlReader: env.reader, ++ logger: env.logger, ++ }); ++} + +``` + +Finally we need to load the plugin in `packages/backend/src/index.ts`, make the following edits: + +```diff +diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts +--- a/packages/backend/src/index.ts ++++ b/packages/backend/src/index.ts +@@ -28,6 +28,7 @@ import scaffolder from './plugins/scaffolder'; + import proxy from './plugins/proxy'; + import techdocs from './plugins/techdocs'; + import search from './plugins/search'; ++import codeCoverage from './plugins/codecoverage'; + import { PluginEnvironment } from './types'; + import { ServerPermissionClient } from '@backstage/plugin-permission-node'; + import { DefaultIdentityClient } from '@backstage/plugin-auth-node'; +@@ -85,6 +86,9 @@ async function main() { + const techdocsEnv = useHotMemoize(module, () => createEnv('techdocs')); + const searchEnv = useHotMemoize(module, () => createEnv('search')); + const appEnv = useHotMemoize(module, () => createEnv('app')); ++ const codeCoverageEnv = useHotMemoize(module, () => ++ createEnv('code-coverage'), ++ ); + + const apiRouter = Router(); + apiRouter.use('/catalog', await catalog(catalogEnv)); +@@ -93,6 +97,7 @@ async function main() { + apiRouter.use('/techdocs', await techdocs(techdocsEnv)); + apiRouter.use('/proxy', await proxy(proxyEnv)); + apiRouter.use('/search', await search(searchEnv)); ++ apiRouter.use('/code-coverage', await codeCoverage(codeCoverageEnv)); + + apiRouter.use(notFoundHandler()); +``` + ## Configuring your entity In order to use this plugin, you must set the `backstage.io/code-coverage` annotation. diff --git a/plugins/code-coverage-backend/package.json b/plugins/code-coverage-backend/package.json index 70be7268cf..d6b9fa99b5 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.4-next.0", + "version": "0.2.4-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -42,7 +42,7 @@ "@backstage/cli": "workspace:^", "@types/express-xml-bodyparser": "^0.3.2", "@types/supertest": "^2.0.8", - "msw": "^0.47.0", + "msw": "^0.48.0", "supertest": "^6.1.6", "xml2js": "^0.4.23" }, diff --git a/plugins/code-coverage/CHANGELOG.md b/plugins/code-coverage/CHANGELOG.md index 5ccbf4eed0..5a379e423f 100644 --- a/plugins/code-coverage/CHANGELOG.md +++ b/plugins/code-coverage/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-code-coverage +## 0.2.4-next.1 + +### Patch Changes + +- fcab2579a0: Adds installation instructions +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.2.4-next.0 ### Patch Changes diff --git a/plugins/code-coverage/README.md b/plugins/code-coverage/README.md index 8903668507..ce793a78d3 100644 --- a/plugins/code-coverage/README.md +++ b/plugins/code-coverage/README.md @@ -2,6 +2,31 @@ This is the frontend part of the code-coverage plugin. It displays code coverage summaries for your entities. +## Installation + +`yarn workspace app add @backstage/plugin-code-coverage` + +Finally you need to import and render the code coverage entity, in `packages/app/src/components/catalog/EntityPage.tsx` add the following: + +```diff +@@ -70,6 +70,7 @@ import { + + import { TechDocsAddons } from '@backstage/plugin-techdocs-react'; + import { ReportIssue } from '@backstage/plugin-techdocs-module-addons-contrib'; ++import { EntityCodeCoverageContent } from '@backstage/plugin-code-coverage'; + +@@ -226,6 +227,10 @@ const defaultEntityPage = ( + + {techdocsContent} + ++ ++ ++ ++ + + ); +``` + ## Configuring your entity In order to use this plugin, you must set the `backstage.io/code-coverage` annotation on entities for which coverage ingestion has been enabled. diff --git a/plugins/code-coverage/package.json b/plugins/code-coverage/package.json index 647c7d2fb0..fbb24dcd94 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.4-next.0", + "version": "0.2.4-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -56,7 +56,7 @@ "@types/node": "^16.11.26", "@types/recharts": "^1.8.15", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/codescene/CHANGELOG.md b/plugins/codescene/CHANGELOG.md index d21ec8c71d..7ddd7f5d4a 100644 --- a/plugins/codescene/CHANGELOG.md +++ b/plugins/codescene/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-codescene +## 0.1.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + ## 0.1.6-next.0 ### Patch Changes diff --git a/plugins/codescene/package.json b/plugins/codescene/package.json index ffd297e8ed..31970219e3 100644 --- a/plugins/codescene/package.json +++ b/plugins/codescene/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-codescene", - "version": "0.1.6-next.0", + "version": "0.1.6-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -47,7 +47,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "*", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist", diff --git a/plugins/config-schema/CHANGELOG.md b/plugins/config-schema/CHANGELOG.md index 6d62429875..f5f5872e55 100644 --- a/plugins/config-schema/CHANGELOG.md +++ b/plugins/config-schema/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-config-schema +## 0.1.34-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/types@1.0.1-next.0 + ## 0.1.34-next.0 ### Patch Changes diff --git a/plugins/config-schema/dev/example-schema.json b/plugins/config-schema/dev/example-schema.json index 2a722205fc..0b96fdbe0a 100644 --- a/plugins/config-schema/dev/example-schema.json +++ b/plugins/config-schema/dev/example-schema.json @@ -19,12 +19,6 @@ "visibility": "frontend", "description": "The title of the app." }, - "googleAnalyticsTrackingId": { - "type": "string", - "visibility": "frontend", - "description": "Tracking ID for Google Analytics", - "examples": ["UA-000000-0"] - }, "listen": { "type": "object", "description": "Listening configuration for local development", diff --git a/plugins/config-schema/package.json b/plugins/config-schema/package.json index b111738405..a4e4f6f715 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.34-next.0", + "version": "0.1.34-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -49,7 +49,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/cost-insights/CHANGELOG.md b/plugins/cost-insights/CHANGELOG.md index ce062fa7e1..a7eb444f37 100644 --- a/plugins/cost-insights/CHANGELOG.md +++ b/plugins/cost-insights/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-cost-insights +## 0.12.0-next.1 + +### Patch Changes + +- e92aa15f01: Bumped `canvas` dependency to the latest version, which has better Node.js v18 support. +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-cost-insights-common@0.1.1 + ## 0.12.0-next.0 ### Minor Changes diff --git a/plugins/cost-insights/api-report.md b/plugins/cost-insights/api-report.md index f50f0b0c81..dd4e404450 100644 --- a/plugins/cost-insights/api-report.md +++ b/plugins/cost-insights/api-report.md @@ -267,6 +267,10 @@ export type CostInsightsApi = { getLastCompleteBillingDate(): Promise; getUserGroups(userId: string): Promise; getGroupProjects(group: string): Promise; + getCatalogEntityDailyCost?( + catalogEntityRef: string, + intervals: string, + ): Promise; getGroupDailyCost(group: string, intervals: string): Promise; getProjectDailyCost(project: string, intervals: string): Promise; getDailyMetricData(metric: string, intervals: string): Promise; @@ -404,11 +408,19 @@ export const EngineerThreshold = 0.5; // @public @deprecated (undocumented) export type Entity = common.Entity; +// @public +export const EntityCostInsightsContent: () => JSX.Element; + // @public (undocumented) export class ExampleCostInsightsClient implements CostInsightsApi { // (undocumented) getAlerts(group: string): Promise; // (undocumented) + getCatalogEntityDailyCost( + entityRef: string, + intervals: string, + ): Promise; + // (undocumented) getDailyMetricData(metric: string, intervals: string): Promise; // (undocumented) getGroupDailyCost(group: string, intervals: string): Promise; diff --git a/plugins/cost-insights/dev/index.tsx b/plugins/cost-insights/dev/index.tsx index 4be788427a..622abaffc9 100644 --- a/plugins/cost-insights/dev/index.tsx +++ b/plugins/cost-insights/dev/index.tsx @@ -23,7 +23,26 @@ import { CostInsightsPage, CostInsightsProjectGrowthInstructionsPage, CostInsightsLabelDataflowInstructionsPage, + EntityCostInsightsContent, } from '../src/plugin'; +import { Content, Header, Page } from '@backstage/core-components'; +import { Grid } from '@material-ui/core'; +import { EntityProvider } from '@backstage/plugin-catalog-react'; +import { Entity } from '@backstage/catalog-model'; + +const mockEntity: Entity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'backstage', + description: 'backstage.io', + }, + spec: { + lifecycle: 'production', + type: 'service', + owner: 'user:guest', + }, +}; createDevApp() .registerPlugin(costInsightsPlugin) @@ -44,4 +63,22 @@ createDevApp() title: 'Labelling', element: , }) + .addPage({ + title: 'Entity', + element: ( + +
+ + + + + + + + + + + + ), + }) .render(); diff --git a/plugins/cost-insights/package.json b/plugins/cost-insights/package.json index aac87aa10f..b6ced5cc7e 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.0-next.0", + "version": "0.12.0-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -36,6 +36,7 @@ "@backstage/config": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", + "@backstage/plugin-catalog-react": "workspace:^", "@backstage/plugin-cost-insights-common": "workspace:^", "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", @@ -73,7 +74,7 @@ "@types/yup": "^0.29.13", "canvas": "^2.10.2", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist", diff --git a/plugins/cost-insights/src/api/CostInsightsApi.ts b/plugins/cost-insights/src/api/CostInsightsApi.ts index 3c97407f08..a7065a04aa 100644 --- a/plugins/cost-insights/src/api/CostInsightsApi.ts +++ b/plugins/cost-insights/src/api/CostInsightsApi.ts @@ -77,6 +77,29 @@ export type CostInsightsApi = { */ getGroupProjects(group: string): Promise; + /** + * Get daily cost aggregations for a given catalog entity and interval time frame. + * + * The return type includes an array of daily cost aggregations as well as statistics about the + * change in cost over the intervals. Calculating these statistics requires us to bucket costs + * into two or more time periods, hence a repeating interval format rather than just a start and + * end date. + * + * The rate of change in this comparison allows teams to reason about their cost growth (or + * reduction) and compare it to metrics important to the business. + * + * Note: implementing this is only required when using the `EntityCostInsightsContent` extension. + * + * @param catalogEntityRef - A reference to the catalog entity, as described in + * https://backstage.io/docs/features/software-catalog/references + * @param intervals - An ISO 8601 repeating interval string, such as R2/P30D/2020-09-01 + * https://en.wikipedia.org/wiki/ISO_8601#Repeating_intervals + */ + getCatalogEntityDailyCost?( + catalogEntityRef: string, + intervals: string, + ): Promise; + /** * Get daily cost aggregations for a given group and interval time frame. * diff --git a/plugins/cost-insights/src/components/CostOverviewCard/CostOverviewBreakdownChart.tsx b/plugins/cost-insights/src/components/CostOverviewCard/CostOverviewBreakdownChart.tsx index f6463b65ed..962dc6b332 100644 --- a/plugins/cost-insights/src/components/CostOverviewCard/CostOverviewBreakdownChart.tsx +++ b/plugins/cost-insights/src/components/CostOverviewCard/CostOverviewBreakdownChart.tsx @@ -54,12 +54,14 @@ import { TooltipRenderer } from '../../types/Tooltip'; export type CostOverviewBreakdownChartProps = { costBreakdown: Cost[]; + responsive?: boolean; }; const LOW_COST_THRESHOLD = 0.1; export const CostOverviewBreakdownChart = ({ costBreakdown, + responsive = true, }: CostOverviewBreakdownChartProps) => { const theme = useTheme(); const classes = useStyles(theme); @@ -228,7 +230,7 @@ export const CostOverviewBreakdownChart = ({ /> diff --git a/plugins/cost-insights/src/components/EntityCosts/EntityCost.test.tsx b/plugins/cost-insights/src/components/EntityCosts/EntityCost.test.tsx new file mode 100644 index 0000000000..53e1a13ebf --- /dev/null +++ b/plugins/cost-insights/src/components/EntityCosts/EntityCost.test.tsx @@ -0,0 +1,99 @@ +/* + * 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 { renderInTestApp } from '@backstage/test-utils'; +import { + changeOf, + MockAggregatedDailyCosts, + MockBillingDateProvider, + MockConfigProvider, + MockFilterProvider, + MockScrollProvider, + trendlineOf, +} from '../../testUtils'; +import { CostInsightsThemeProvider } from '../CostInsightsPage/CostInsightsThemeProvider'; +import { EntityCostsCard } from './EntityCosts'; +import { TestApiProvider } from '@backstage/test-utils'; +import { CostInsightsApi, costInsightsApiRef } from '../../api'; +import { EntityProvider } from '@backstage/plugin-catalog-react'; +import { Entity } from '@backstage/catalog-model'; +import { LoadingProvider } from '../../hooks'; +import { Cost } from '@backstage/plugin-cost-insights-common'; + +function renderInContext(children: JSX.Element) { + const mockEntity = { + metadata: { name: 'mock' }, + kind: 'MockKind', + } as Entity; + const mockGroupDailyCost: Cost = { + id: 'test-group', + aggregation: MockAggregatedDailyCosts, + change: changeOf(MockAggregatedDailyCosts), + trendline: trendlineOf(MockAggregatedDailyCosts), + }; + const mockApi: jest.Mocked = { + getLastCompleteBillingDate: jest.fn().mockResolvedValue('2022-10-30'), + getUserGroups: jest.fn().mockResolvedValue(['team-a']), + getGroupProjects: jest.fn().mockResolvedValue(['project-a', 'project-b']), + getCatalogEntityDailyCost: jest.fn().mockResolvedValue(mockGroupDailyCost), + getGroupDailyCost: jest.fn().mockResolvedValue({}), + getProjectDailyCost: jest.fn().mockResolvedValue({}), + getDailyMetricData: jest.fn().mockResolvedValue({}), + getProductInsights: jest.fn().mockResolvedValue({}), + getAlerts: jest.fn().mockResolvedValue({}), + }; + + return renderInTestApp( + + + + + + + + {children} + + + + + + + , + ); +} + +describe('', () => { + beforeEach(() => { + // @ts-expect-error: Since we have strictNullChecks enabled, this will throw an error as window.ResizeObserver + // it's not an optional operand + delete window.ResizeObserver; + window.ResizeObserver = jest.fn().mockImplementation(() => ({ + observe: jest.fn(), + unobserve: jest.fn(), + disconnect: jest.fn(), + })); + }); + + afterEach(() => { + window.ResizeObserver = ResizeObserver; + jest.restoreAllMocks(); + }); + + it('Renders without exploding', async () => { + const { getByText } = await renderInContext(); + expect(getByText('Cloud Cost')).toBeInTheDocument(); + }); +}); diff --git a/plugins/cost-insights/src/components/EntityCosts/EntityCosts.tsx b/plugins/cost-insights/src/components/EntityCosts/EntityCosts.tsx new file mode 100644 index 0000000000..9dda1c65e3 --- /dev/null +++ b/plugins/cost-insights/src/components/EntityCosts/EntityCosts.tsx @@ -0,0 +1,161 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React, { useCallback, useEffect, useState } from 'react'; +import { CostOverviewCard } from '../CostOverviewCard'; +import { + BillingDateProvider, + ConfigProvider, + CurrencyProvider, + FilterProvider, + GroupsProvider, + LoadingProvider, + ScrollProvider, + useFilters, + useLastCompleteBillingDate, + useLoading, +} from '../../hooks'; +import { CostInsightsThemeProvider } from '../CostInsightsPage/CostInsightsThemeProvider'; +import { Progress, WarningPanel } from '@backstage/core-components'; +import { default as MaterialAlert } from '@material-ui/lab/Alert'; +import { mapLoadingToProps } from '../CostInsightsPage/selector'; +import { intervalsOf } from '../../utils/duration'; +import { costInsightsApiRef } from '../../api'; +import { useApi } from '@backstage/core-plugin-api'; +import { useEntity } from '@backstage/plugin-catalog-react'; +import { Cost, Maybe } from '@backstage/plugin-cost-insights-common'; +import { stringifyEntityRef } from '@backstage/catalog-model'; + +export const EntityCostsCard = () => { + const client = useApi(costInsightsApiRef); + const { entity } = useEntity(); + + const { + loadingActions, + loadingGroups, + loadingBillingDate, + loadingInitial, + dispatchInitial, + dispatchInsights, + dispatchNone, + } = useLoading(mapLoadingToProps); + + /* eslint-disable react-hooks/exhaustive-deps */ + // The dispatchLoading functions are derived from loading state using mapLoadingToProps, to + // provide nicer props for the component. These are re-derived whenever loading state changes, + // which causes an infinite loop as product panels load and re-trigger the useEffect below. + // Since the functions don't change, we can memoize - but we trigger the same loop if we satisfy + // exhaustive-deps by including the function itself in dependencies. + + const dispatchLoadingInitial = useCallback(dispatchInitial, []); + const dispatchLoadingInsights = useCallback(dispatchInsights, []); + const dispatchLoadingNone = useCallback(dispatchNone, []); + /* eslint-enable react-hooks/exhaustive-deps */ + + const lastCompleteBillingDate = useLastCompleteBillingDate(); + const [dailyCost, setDailyCost] = useState>(null); + const [error, setError] = useState>(null); + const { pageFilters } = useFilters(p => p); + + useEffect(() => { + async function getInsights() { + setError(null); + try { + dispatchLoadingInsights(true); + const intervals = intervalsOf( + pageFilters.duration, + lastCompleteBillingDate, + ); + + const fetchedDailyCost = await client.getCatalogEntityDailyCost!( + stringifyEntityRef(entity), + intervals, + ); + setDailyCost(fetchedDailyCost); + } catch (e) { + setError(e); + dispatchLoadingNone(loadingActions); + } finally { + dispatchLoadingNone(loadingActions); + dispatchLoadingInitial(false); + dispatchLoadingInsights(false); + } + } + + // Wait for metadata to finish loading + if (!loadingBillingDate) { + getInsights(); + } + }, [ + client, + entity, + pageFilters, + loadingActions, + loadingGroups, + loadingBillingDate, + dispatchLoadingInsights, + dispatchLoadingInitial, + dispatchLoadingNone, + lastCompleteBillingDate, + ]); + + if (loadingInitial) { + return ; + } + + if (error) { + return {error.message}; + } + + if (!dailyCost) { + return No daily costs; + } + + return ; +}; + +export const EntityCosts = () => { + const client = useApi(costInsightsApiRef); + + if (!client.getCatalogEntityDailyCost) { + return ( + + ); + } + + return ( + + + + + + + + + + + + + + + + + + ); +}; diff --git a/plugins/cost-insights/src/components/EntityCosts/index.ts b/plugins/cost-insights/src/components/EntityCosts/index.ts new file mode 100644 index 0000000000..b8d5106090 --- /dev/null +++ b/plugins/cost-insights/src/components/EntityCosts/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { EntityCosts } from './EntityCosts'; diff --git a/plugins/cost-insights/src/example/client.ts b/plugins/cost-insights/src/example/client.ts index 9c3e20c2b3..e2a183b682 100644 --- a/plugins/cost-insights/src/example/client.ts +++ b/plugins/cost-insights/src/example/client.ts @@ -92,6 +92,29 @@ export class ExampleCostInsightsClient implements CostInsightsApi { return cost; } + async getCatalogEntityDailyCost( + entityRef: string, + intervals: string, + ): Promise { + const aggregation = aggregationFor(intervals, 8_000); + const groupDailyCost: Cost = await this.request( + { entityRef, intervals }, + { + aggregation: aggregation, + change: changeOf(aggregation), + trendline: trendlineOf(aggregation), + // Optional field providing cost groupings / breakdowns keyed by the type. In this example, + // daily cost grouped by cloud product OR by project / billing account. + groupedCosts: { + product: getGroupedProducts(intervals), + project: getGroupedProjects(intervals), + }, + }, + ); + + return groupDailyCost; + } + async getGroupDailyCost(group: string, intervals: string): Promise { const aggregation = aggregationFor(intervals, 8_000); const groupDailyCost: Cost = await this.request( diff --git a/plugins/cost-insights/src/example/templates/CostInsightsClient.ts b/plugins/cost-insights/src/example/templates/CostInsightsClient.ts index fc68eb62c7..50c3bb1470 100644 --- a/plugins/cost-insights/src/example/templates/CostInsightsClient.ts +++ b/plugins/cost-insights/src/example/templates/CostInsightsClient.ts @@ -87,6 +87,17 @@ export class CostInsightsClient implements CostInsightsApi { } } + async getCatalogEntityDailyCost(catalogEntityRef: string, intervals: string): Promise { + return { + id: 'remove-me', + aggregation: [], + change: { + ratio: 0, + amount: 0 + } + } + } + async getProductInsights(options: ProductInsightsOptions): Promise { return { id: 'remove-me', diff --git a/plugins/cost-insights/src/index.ts b/plugins/cost-insights/src/index.ts index 2c46156005..8a17b1bf43 100644 --- a/plugins/cost-insights/src/index.ts +++ b/plugins/cost-insights/src/index.ts @@ -24,6 +24,7 @@ export { costInsightsPlugin, costInsightsPlugin as plugin, CostInsightsPage, + EntityCostInsightsContent, CostInsightsProjectGrowthInstructionsPage, CostInsightsLabelDataflowInstructionsPage, } from './plugin'; diff --git a/plugins/cost-insights/src/plugin.ts b/plugins/cost-insights/src/plugin.ts index 789d803438..04d58d1877 100644 --- a/plugins/cost-insights/src/plugin.ts +++ b/plugins/cost-insights/src/plugin.ts @@ -53,6 +53,20 @@ export const CostInsightsPage = costInsightsPlugin.provide( }), ); +/** + * An extension for displaying costs on an entity page. + * + * @public + */ +export const EntityCostInsightsContent = costInsightsPlugin.provide( + createRoutableExtension({ + name: 'EntityCostInsightsContent', + component: () => + import('./components/EntityCosts').then(m => m.EntityCosts), + mountPoint: rootRouteRef, + }), +); + /** @public */ export const CostInsightsProjectGrowthInstructionsPage = costInsightsPlugin.provide( diff --git a/plugins/dynatrace/CHANGELOG.md b/plugins/dynatrace/CHANGELOG.md index 4ab45e9df6..9274a296db 100644 --- a/plugins/dynatrace/CHANGELOG.md +++ b/plugins/dynatrace/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-dynatrace +## 1.0.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 1.0.1-next.0 ### Patch Changes diff --git a/plugins/dynatrace/package.json b/plugins/dynatrace/package.json index bdd54bf865..6b7d4f3781 100644 --- a/plugins/dynatrace/package.json +++ b/plugins/dynatrace/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-dynatrace", - "version": "1.0.1-next.0", + "version": "1.0.1-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -45,7 +45,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "*", "express": "^4.18.1", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist", diff --git a/plugins/events-backend-module-aws-sqs/.eslintrc.js b/plugins/events-backend-module-aws-sqs/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/events-backend-module-aws-sqs/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/events-backend-module-aws-sqs/README.md b/plugins/events-backend-module-aws-sqs/README.md new file mode 100644 index 0000000000..cb3a5045c0 --- /dev/null +++ b/plugins/events-backend-module-aws-sqs/README.md @@ -0,0 +1,42 @@ +# events-backend-module-aws-sqs + +Welcome to the `events-backend-module-aws-sqs` backend plugin! + +This plugin is a module for the `events-backend` backend plugin +and extends it with an `AwsSqsConsumingEventPublisher`. + +This event publisher will allow you to receive events from +an AWS SQS queue and will publish these to the used event broker. + +## Configuration + +The polled AWS SQS queues depend on your configuration: + +```yaml +events: + modules: + awsSqs: + awsSqsConsumingEventPublisher: + topics: + topicName1: # replace with actual topic name as expected by subscribers + queue: + url: 'https://sqs.us-east-2.amazonaws.com/123456789012/MyQueue' + region: us-east-2 + # visibilityTimeout - as HumanDuration; defaults to queue-based config + # waitTime - as HumanDuration; defaults to max of 20 seconds (long polling) + # timeout - as HumanDuration; timeout for the task execution + # waitTimeAfterEmptyReceive - as HumanDuration; time to wait before a retry when there was no message. + topicName2: + # [...] +``` + +## Installation + +1. Install the [`events-backend` plugin](../events-backend/README.md). +2. Install this module +3. Add your configuration. + +```bash +# From your Backstage root directory +yarn add --cwd packages/backend @backstage/plugin-events-backend-module-aws-sqs +``` diff --git a/plugins/events-backend-module-aws-sqs/api-report.md b/plugins/events-backend-module-aws-sqs/api-report.md new file mode 100644 index 0000000000..79a422c9f3 --- /dev/null +++ b/plugins/events-backend-module-aws-sqs/api-report.md @@ -0,0 +1,29 @@ +## API Report File for "@backstage/plugin-events-backend-module-aws-sqs" + +> 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 { EventBroker } from '@backstage/plugin-events-node'; +import { EventPublisher } from '@backstage/plugin-events-node'; +import { Logger } from 'winston'; +import { PluginTaskScheduler } from '@backstage/backend-tasks'; + +// @public +export class AwsSqsConsumingEventPublisher implements EventPublisher { + // (undocumented) + static fromConfig(env: { + config: Config; + logger: Logger; + scheduler: PluginTaskScheduler; + }): AwsSqsConsumingEventPublisher[]; + // (undocumented) + setEventBroker(eventBroker: EventBroker): Promise; +} + +// @alpha +export const awsSqsConsumingEventPublisherEventsModule: ( + options?: undefined, +) => BackendFeature; +``` diff --git a/plugins/events-backend-module-aws-sqs/config.d.ts b/plugins/events-backend-module-aws-sqs/config.d.ts new file mode 100644 index 0000000000..dfef35bf22 --- /dev/null +++ b/plugins/events-backend-module-aws-sqs/config.d.ts @@ -0,0 +1,78 @@ +/* + * 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 { HumanDuration } from '@backstage/types'; + +export interface Config { + events?: { + modules?: { + /** + * events-backend-module-aws-sqs plugin configuration. + */ + awsSqs?: { + /** + * Configuration for AwsSqsConsumingEventPublisher. + */ + awsSqsConsumingEventPublisher?: { + /** + * Contains a record per topic for which an AWS SQS queue + * should be used as source of events. + */ + topics: Record< + string, + { + /** + * (Required) Queue-related configuration. + */ + queue: { + /** + * (Required) The region of the AWS SQS queue. + */ + region: string; + /** + * (Required) The absolute URL for the AWS SQS queue to be used. + */ + url: string; + /** + * (Optional) Visibility timeout for messages in flight. + */ + visibilityTimeout: HumanDuration; + /** + * (Optional) Wait time when polling for available messages. + * Default: 20 seconds. + */ + waitTime: HumanDuration; + }; + /** + * (Optional) Timeout for the task execution which includes polling for messages + * and publishing the events to the event broker + * and the wait time after empty receives. + * + * Must be greater than `queue.waitTime` + `waitTimeAfterEmptyReceive`. + */ + timeout: HumanDuration; + /** + * (Optional) Wait time before polling again if no message was received. + * Default: 1 minute. + */ + waitTimeAfterEmptyReceive: HumanDuration; + } + >; + }; + }; + }; + }; +} diff --git a/plugins/events-backend-module-aws-sqs/package.json b/plugins/events-backend-module-aws-sqs/package.json new file mode 100644 index 0000000000..ecce75d9a3 --- /dev/null +++ b/plugins/events-backend-module-aws-sqs/package.json @@ -0,0 +1,48 @@ +{ + "name": "@backstage/plugin-events-backend-module-aws-sqs", + "version": "0.0.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "alphaTypes": "dist/index.alpha.d.ts", + "main": "dist/index.cjs.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "backend-plugin-module" + }, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build --experimental-type-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": { + "@aws-sdk/client-sqs": "^3.0.0", + "@backstage/backend-plugin-api": "workspace:^", + "@backstage/backend-tasks": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/plugin-events-node": "workspace:^", + "@backstage/types": "workspace:^", + "luxon": "^3.0.0", + "winston": "^3.2.1" + }, + "devDependencies": { + "@backstage/backend-common": "workspace:^", + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", + "@backstage/plugin-events-backend-test-utils": "workspace:^", + "aws-sdk-client-mock": "^2.0.0" + }, + "files": [ + "alpha", + "config.d.ts", + "dist" + ], + "configSchema": "config.d.ts" +} diff --git a/plugins/events-backend-module-aws-sqs/src/index.ts b/plugins/events-backend-module-aws-sqs/src/index.ts new file mode 100644 index 0000000000..73b950856b --- /dev/null +++ b/plugins/events-backend-module-aws-sqs/src/index.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * The module "sqs" for the Backstage backend plugin "events" + * adding an AWS SQS-based publisher, + * receiving events from an AWS SQS queue and passing it to the + * internal event broker. + * + * @packageDocumentation + */ + +export { AwsSqsConsumingEventPublisher } from './publisher/AwsSqsConsumingEventPublisher'; +export { awsSqsConsumingEventPublisherEventsModule } from './service/AwsSqsConsumingEventPublisherEventsModule'; diff --git a/plugins/events-backend-module-aws-sqs/src/publisher/AwsSqsConsumingEventPublisher.test.ts b/plugins/events-backend-module-aws-sqs/src/publisher/AwsSqsConsumingEventPublisher.test.ts new file mode 100644 index 0000000000..e32245b483 --- /dev/null +++ b/plugins/events-backend-module-aws-sqs/src/publisher/AwsSqsConsumingEventPublisher.test.ts @@ -0,0 +1,227 @@ +/* + * 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 { + DeleteMessageBatchCommand, + ReceiveMessageCommand, + SQSClient, +} from '@aws-sdk/client-sqs'; +import { getVoidLogger } from '@backstage/backend-common'; +import { PluginTaskScheduler } from '@backstage/backend-tasks'; +import { ConfigReader } from '@backstage/config'; +import { TestEventBroker } from '@backstage/plugin-events-backend-test-utils'; +import { mockClient } from 'aws-sdk-client-mock'; +import { AwsSqsConsumingEventPublisher } from './AwsSqsConsumingEventPublisher'; + +describe('AwsSqsConsumingEventPublisher', () => { + it('creates one publisher instance per configured topic', async () => { + const config = new ConfigReader({ + events: { + modules: { + awsSqs: { + awsSqsConsumingEventPublisher: { + topics: { + fake1: { + queue: { + region: 'eu-west-1', + url: 'https://fake1.queue.url', + }, + }, + fake2: { + queue: { + region: 'us-east-1', + url: 'https://fake2.queue.url', + }, + }, + }, + }, + }, + }, + }, + }); + const logger = getVoidLogger(); + const scheduler = { + scheduleTask: jest.fn(), + } as unknown as PluginTaskScheduler; + + const publishers = AwsSqsConsumingEventPublisher.fromConfig({ + config, + logger, + scheduler, + }); + expect(publishers.length).toEqual(2); + }); + + it('polling will be scheduled after connecting to the EventBroker', async () => { + const config = new ConfigReader({ + events: { + modules: { + awsSqs: { + awsSqsConsumingEventPublisher: { + topics: { + fake1: { + queue: { + region: 'eu-west-1', + url: 'https://fake1.queue.url', + }, + }, + }, + }, + }, + }, + }, + }); + const logger = getVoidLogger(); + const scheduler = { + scheduleTask: jest.fn(), + } as unknown as PluginTaskScheduler; + + const publishers = AwsSqsConsumingEventPublisher.fromConfig({ + config, + logger, + scheduler, + }); + expect(publishers.length).toEqual(1); + + const publisher = publishers[0]; + + const eventBroker = new TestEventBroker(); + await publisher.setEventBroker(eventBroker); + + // publisher.connect(..) was causing the polling for events to be scheduled + expect(scheduler.scheduleTask).toHaveBeenCalledWith( + expect.objectContaining({ + id: 'events.awsSqs.publisher:fake1', + frequency: { seconds: 0 }, + timeout: { seconds: 260 }, + scope: 'local', + }), + ); + }); + + it('publishes events for received messages and deletes them in bulk', async () => { + const config = new ConfigReader({ + events: { + modules: { + awsSqs: { + awsSqsConsumingEventPublisher: { + topics: { + fake1: { + queue: { + region: 'eu-west-1', + url: 'https://fake1.queue.url', + }, + waitTimeAfterEmptyReceive: { seconds: 1 }, + }, + }, + }, + }, + }, + }, + }); + const logger = getVoidLogger(); + let taskFn: (() => Promise) | undefined = undefined; + const scheduler = { + scheduleTask: (spec: { fn: () => Promise }) => { + taskFn = spec.fn; + }, + } as unknown as PluginTaskScheduler; + + // on the first attempt, we will return 1 message and 0 messages afterwards + const sqsMock = mockClient(SQSClient); + sqsMock + .on(ReceiveMessageCommand, { + MaxNumberOfMessages: 10, + QueueUrl: 'https://fake1.queue.url', + WaitTimeSeconds: 20, + }) + .resolvesOnce({ + Messages: [], + }) + .resolvesOnce({ + Messages: [ + { + Body: '{"event":"payload1"}', + ReceiptHandle: 'fake-handle1', + MessageAttributes: { + 'X-Custom-Attr': { + DataType: 'String', + StringValue: 'value', + }, + }, + }, + { + Body: '{"event":"payload2"}', + ReceiptHandle: 'fake-handle2', + }, + ], + }) + .on(DeleteMessageBatchCommand, { + Entries: [ + { + Id: 'message-0', + ReceiptHandle: 'fake-handle1', + }, + { + Id: 'message-1', + ReceiptHandle: 'fake-handle2', + }, + ], + QueueUrl: 'https://fake1.queue.url', + }) + .resolvesOnce({ + Failed: [ + { + Id: 'message-1', + Message: 'test failure', + SenderFault: true, + Code: '400', + }, + ], + Successful: [{ Id: 'message-0' }], + }); + + const publishers = AwsSqsConsumingEventPublisher.fromConfig({ + config, + logger, + scheduler, + }); + expect(publishers.length).toEqual(1); + const publisher = publishers[0]; + + const eventBroker = new TestEventBroker(); + await publisher.setEventBroker(eventBroker); + + await taskFn!(); + await taskFn!(); + await taskFn!(); + + expect(eventBroker.published.length).toEqual(2); + expect(eventBroker.published[0].topic).toEqual('fake1'); + expect(eventBroker.published[0].eventPayload).toEqual({ + event: 'payload1', + }); + expect(eventBroker.published[0].metadata).toEqual({ + 'X-Custom-Attr': 'value', + }); + + expect(eventBroker.published[1].topic).toEqual('fake1'); + expect(eventBroker.published[1].eventPayload).toEqual({ + event: 'payload2', + }); + expect(eventBroker.published[1].metadata).toEqual({}); + }); +}); diff --git a/plugins/events-backend-module-aws-sqs/src/publisher/AwsSqsConsumingEventPublisher.ts b/plugins/events-backend-module-aws-sqs/src/publisher/AwsSqsConsumingEventPublisher.ts new file mode 100644 index 0000000000..4638769c45 --- /dev/null +++ b/plugins/events-backend-module-aws-sqs/src/publisher/AwsSqsConsumingEventPublisher.ts @@ -0,0 +1,191 @@ +/* + * 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 { + DeleteMessageBatchCommand, + Message, + ReceiveMessageCommand, + ReceiveMessageCommandInput, + SQSClient, +} from '@aws-sdk/client-sqs'; +import { PluginTaskScheduler } from '@backstage/backend-tasks'; +import { Config } from '@backstage/config'; +import { EventBroker, EventPublisher } from '@backstage/plugin-events-node'; +import { Logger } from 'winston'; +import { AwsSqsEventSourceConfig, readConfig } from './config'; + +/** + * Publishes events received from an AWS SQS queue. + * The message payload will be used as event payload and passed to registered subscribers. + * + * @public + */ +// TODO(pjungermann): add prom metrics? (see plugins/catalog-backend/src/util/metrics.ts, etc.) +export class AwsSqsConsumingEventPublisher implements EventPublisher { + private readonly topic: string; + private readonly receiveParams: ReceiveMessageCommandInput; + private readonly sqs: SQSClient; + private readonly queueUrl: string; + private readonly taskTimeoutSeconds: number; + private readonly waitTimeAfterEmptyReceiveMs; + private eventBroker?: EventBroker; + + static fromConfig(env: { + config: Config; + logger: Logger; + scheduler: PluginTaskScheduler; + }): AwsSqsConsumingEventPublisher[] { + return readConfig(env.config).map( + config => + new AwsSqsConsumingEventPublisher(env.logger, env.scheduler, config), + ); + } + + private constructor( + private readonly logger: Logger, + private readonly scheduler: PluginTaskScheduler, + config: AwsSqsEventSourceConfig, + ) { + this.topic = config.topic; + + this.receiveParams = { + MaxNumberOfMessages: 10, + MessageAttributeNames: ['All'], + QueueUrl: config.queueUrl, + VisibilityTimeout: config.visibilityTimeout?.as('seconds'), + WaitTimeSeconds: config.pollingWaitTime.as('seconds'), + }; + this.sqs = new SQSClient({ region: config.region }); + this.queueUrl = config.queueUrl; + + this.taskTimeoutSeconds = config.timeout.as('seconds'); + this.waitTimeAfterEmptyReceiveMs = + config.waitTimeAfterEmptyReceive.as('milliseconds'); + } + + async setEventBroker(eventBroker: EventBroker): Promise { + this.eventBroker = eventBroker; + return this.start(); + } + + private async start(): Promise { + const id = `events.awsSqs.publisher:${this.topic}`; + const logger = this.logger.child({ + class: AwsSqsConsumingEventPublisher.prototype.constructor.name, + taskId: id, + }); + + await this.scheduler.scheduleTask({ + id: id, + frequency: { seconds: 0 }, + timeout: { seconds: this.taskTimeoutSeconds }, + scope: 'local', + fn: async () => { + try { + const numMessages = await this.consumeMessages(); + if (numMessages === 0) { + await this.sleep(this.waitTimeAfterEmptyReceiveMs); + } + } catch (error) { + logger.error(error); + } + }, + }); + } + + private async deleteMessages(messages?: Message[]): Promise { + if (!messages) { + return; + } + + const deleteParams = { + QueueUrl: this.queueUrl, + Entries: messages.map((message, index) => { + return { + Id: message.MessageId ?? `message-${index}`, + ReceiptHandle: message.ReceiptHandle, + }; + }), + }; + + try { + const result = await this.sqs.send( + new DeleteMessageBatchCommand(deleteParams), + ); + if (result.Failed) { + this.logger.error( + `Failed to delete ${result.Failed!.length} of ${ + messages.length + } messages from AWS SQS ${this.queueUrl}. First: ${ + result.Failed[0].Message + }`, + ); + } + } catch (error) { + this.logger.error( + `Failed to delete message from AWS SQS ${this.queueUrl}`, + error, + ); + } + } + + private async consumeMessages(): Promise { + try { + const data = await this.sqs.send( + new ReceiveMessageCommand(this.receiveParams), + ); + + data.Messages?.forEach(message => { + const eventPayload = JSON.parse(message.Body!); + + const metadata: Record = {}; + Object.keys(message.MessageAttributes ?? {}).forEach(key => { + const attrValue = message.MessageAttributes![key]; + if ( + !attrValue || + !attrValue.DataType || + !['String', 'Number'].includes(attrValue.DataType) + ) { + return; + } + + const value = attrValue.StringListValues ?? attrValue.StringValue; + if (value !== undefined) { + metadata[key] = value; + } + }); + + this.eventBroker!.publish({ + topic: this.topic, + eventPayload, + metadata, + }); + }); + await this.deleteMessages(data.Messages); + return data.Messages?.length ?? 0; + } catch (error) { + this.logger.error( + `Failed to receive events from AWS SQS ${this.queueUrl}`, + error, + ); + return 0; + } + } + + private sleep(ms: number): Promise { + return new Promise(resolve => setTimeout(resolve, ms)); + } +} diff --git a/plugins/events-backend-module-aws-sqs/src/publisher/config.test.ts b/plugins/events-backend-module-aws-sqs/src/publisher/config.test.ts new file mode 100644 index 0000000000..1fa9df4ce3 --- /dev/null +++ b/plugins/events-backend-module-aws-sqs/src/publisher/config.test.ts @@ -0,0 +1,222 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ConfigReader } from '@backstage/config'; +import { readConfig } from './config'; + +describe('readConfig', () => { + it('not configured', () => { + const config = new ConfigReader({}); + + const publisherConfigs = readConfig(config); + + expect(publisherConfigs.length).toBe(0); + }); + + it('only required fields configured', () => { + const config = new ConfigReader({ + events: { + modules: { + awsSqs: { + awsSqsConsumingEventPublisher: { + topics: { + fake1: { + queue: { + region: 'eu-west-1', + url: 'https://fake1.queue.url', + }, + }, + fake2: { + queue: { + region: 'us-east-1', + url: 'https://fake2.queue.url', + }, + }, + }, + }, + }, + }, + }, + }); + + const publisherConfigs = readConfig(config); + + expect(publisherConfigs.length).toBe(2); + + expect(publisherConfigs[0].topic).toEqual('fake1'); + expect(publisherConfigs[0].region).toEqual('eu-west-1'); + expect(publisherConfigs[0].queueUrl).toEqual('https://fake1.queue.url'); + expect(publisherConfigs[0].pollingWaitTime.as('seconds')).toBe(20); + expect(publisherConfigs[0].timeout.as('seconds')).toBe(260); + expect(publisherConfigs[0].waitTimeAfterEmptyReceive.as('seconds')).toBe( + 60, + ); + }); + + it('all fields configured', () => { + const config = new ConfigReader({ + events: { + modules: { + awsSqs: { + awsSqsConsumingEventPublisher: { + topics: { + fake1: { + queue: { + region: 'eu-west-1', + url: 'https://fake1.queue.url', + visibilityTimeout: { minutes: 5 }, + waitTime: { seconds: 10 }, + }, + timeout: { minutes: 5 }, + waitTimeAfterEmptyReceive: { seconds: 30 }, + }, + }, + }, + }, + }, + }, + }); + + const publisherConfigs = readConfig(config); + + expect(publisherConfigs.length).toBe(1); + + expect(publisherConfigs[0].topic).toEqual('fake1'); + expect(publisherConfigs[0].region).toEqual('eu-west-1'); + expect(publisherConfigs[0].queueUrl).toEqual('https://fake1.queue.url'); + expect(publisherConfigs[0].pollingWaitTime.as('seconds')).toBe(10); + expect(publisherConfigs[0].timeout.as('seconds')).toBe(300); + expect(publisherConfigs[0].waitTimeAfterEmptyReceive.as('seconds')).toBe( + 30, + ); + }); + + it('fail on negative queue.waitTime', () => { + const config = new ConfigReader({ + events: { + modules: { + awsSqs: { + awsSqsConsumingEventPublisher: { + topics: { + fake1: { + queue: { + region: 'eu-west-1', + url: 'https://fake1.queue.url', + visibilityTimeout: { minutes: 5 }, + waitTime: { seconds: -10 }, + }, + timeout: { minutes: 5 }, + waitTimeAfterEmptyReceive: { seconds: 30 }, + }, + }, + }, + }, + }, + }, + }); + + expect(() => readConfig(config)).toThrow( + 'events.modules.awsSqs.awsSqsConsumingEventPublisher.topics.fake1.queue.waitTime must be within 0..20 seconds', + ); + }); + + it('fail on too high queue.waitTime', () => { + const config = new ConfigReader({ + events: { + modules: { + awsSqs: { + awsSqsConsumingEventPublisher: { + topics: { + fake1: { + queue: { + region: 'eu-west-1', + url: 'https://fake1.queue.url', + visibilityTimeout: { minutes: 5 }, + waitTime: { seconds: 30 }, + }, + timeout: { minutes: 5 }, + waitTimeAfterEmptyReceive: { seconds: 30 }, + }, + }, + }, + }, + }, + }, + }); + + expect(() => readConfig(config)).toThrow( + 'events.modules.awsSqs.awsSqsConsumingEventPublisher.topics.fake1.queue.waitTime must be within 0..20 seconds', + ); + }); + + it('fail on too low timeout', () => { + const config = new ConfigReader({ + events: { + modules: { + awsSqs: { + awsSqsConsumingEventPublisher: { + topics: { + fake1: { + queue: { + region: 'eu-west-1', + url: 'https://fake1.queue.url', + visibilityTimeout: { minutes: 5 }, + waitTime: { seconds: 10 }, + }, + timeout: { seconds: 10 }, + waitTimeAfterEmptyReceive: { seconds: 30 }, + }, + }, + }, + }, + }, + }, + }); + + expect(() => readConfig(config)).toThrow( + 'The events.modules.awsSqs.awsSqsConsumingEventPublisher.topics.fake1.timeout must be greater than events.modules.awsSqs.awsSqsConsumingEventPublisher.topics.fake1.queue.waitTime', + ); + }); + + it('fail on negative waitTimeAfterEmptyReceive', () => { + const config = new ConfigReader({ + events: { + modules: { + awsSqs: { + awsSqsConsumingEventPublisher: { + topics: { + fake1: { + queue: { + region: 'eu-west-1', + url: 'https://fake1.queue.url', + visibilityTimeout: { minutes: 5 }, + waitTime: { seconds: 10 }, + }, + timeout: { minutes: 5 }, + waitTimeAfterEmptyReceive: { seconds: -30 }, + }, + }, + }, + }, + }, + }, + }); + + expect(() => readConfig(config)).toThrow( + 'The events.modules.awsSqs.awsSqsConsumingEventPublisher.topics.fake1.waitTimeAfterEmptyReceive must not be negative', + ); + }); +}); diff --git a/plugins/events-backend-module-aws-sqs/src/publisher/config.ts b/plugins/events-backend-module-aws-sqs/src/publisher/config.ts new file mode 100644 index 0000000000..c6b74ea8d3 --- /dev/null +++ b/plugins/events-backend-module-aws-sqs/src/publisher/config.ts @@ -0,0 +1,117 @@ +/* + * 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 { Config } from '@backstage/config'; +import { HumanDuration, JsonObject } from '@backstage/types'; +import { Duration } from 'luxon'; + +const CONFIG_PREFIX_MODULE = 'events.modules.awsSqs.'; +const CONFIG_PREFIX_PUBLISHER = `${CONFIG_PREFIX_MODULE}awsSqsConsumingEventPublisher.`; +const DEFAULT_WAIT_TIME_AFTER_EMPTY_RECEIVE = { minutes: 1 }; +const MAX_WAIT_SECONDS = 20; + +export interface AwsSqsEventSourceConfig { + pollingWaitTime: Duration; + queueUrl: string; + region: string; + timeout: Duration; + topic: string; + visibilityTimeout?: Duration; + waitTimeAfterEmptyReceive: Duration; +} + +// TODO(pjungermann): validation could be improved similar to `convertToHumanDuration` at @backstage/backend-tasks +function readOptionalHumanDuration( + config: Config, + key: string, +): HumanDuration | undefined { + return config.getOptional(key) as HumanDuration; +} + +function readOptionalDuration( + config: Config, + key: string, +): Duration | undefined { + const duration = readOptionalHumanDuration(config, key); + return duration ? Duration.fromObject(duration) : undefined; +} + +export function readConfig(config: Config): AwsSqsEventSourceConfig[] { + const key = `${CONFIG_PREFIX_PUBLISHER}topics`; + const topics = config.getOptionalConfig(key); + + return ( + topics?.keys()?.map(topic => { + const topicConfig = topics.getConfig(topic); + const keyPrefix = `${key}.${topic}.`; + + // queue config: + const pollingWaitTime = Duration.fromObject( + readOptionalHumanDuration(topicConfig, 'queue.waitTime') ?? { + seconds: MAX_WAIT_SECONDS, + }, + ); + if ( + pollingWaitTime.valueOf() < 0 || + pollingWaitTime.as('seconds') > MAX_WAIT_SECONDS + ) { + throw new Error( + `${keyPrefix}queue.waitTime must be within 0..${MAX_WAIT_SECONDS} seconds.`, + ); + } + const queueUrl = topicConfig.getString('queue.url'); + const region = topicConfig.getString('queue.region'); + const visibilityTimeout = readOptionalDuration( + topicConfig, + 'queue.visibilityTimeout', + ); + + // task: + const waitTimeAfterEmptyReceive = Duration.fromObject( + readOptionalHumanDuration(topicConfig, 'waitTimeAfterEmptyReceive') ?? + DEFAULT_WAIT_TIME_AFTER_EMPTY_RECEIVE, + ); + if (waitTimeAfterEmptyReceive.valueOf() < 0) { + throw new Error( + `The ${keyPrefix}waitTimeAfterEmptyReceive must not be negative.`, + ); + } + const timeout = + readOptionalDuration(topicConfig, 'timeout') ?? + pollingWaitTime + .plus(waitTimeAfterEmptyReceive) + .plus(Duration.fromObject({ seconds: 180 })); + if ( + timeout.valueOf() <= + pollingWaitTime.valueOf() + waitTimeAfterEmptyReceive.valueOf() + ) { + throw new Error( + `The ${keyPrefix}timeout must be greater than ${keyPrefix}queue.waitTime + ${keyPrefix}waitTimeAfterEmptyReceive.`, + ); + } + + return { + pollingWaitTime, + queueUrl, + region, + timeout, + topic, + visibilityTimeout, + waitTimeAfterEmptyReceive, + }; + }) ?? [] + ); +} diff --git a/plugins/events-backend-module-aws-sqs/src/service/AwsSqsConsumingEventPublisherEventsModule.test.ts b/plugins/events-backend-module-aws-sqs/src/service/AwsSqsConsumingEventPublisherEventsModule.test.ts new file mode 100644 index 0000000000..584b62a2c6 --- /dev/null +++ b/plugins/events-backend-module-aws-sqs/src/service/AwsSqsConsumingEventPublisherEventsModule.test.ts @@ -0,0 +1,94 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { getVoidLogger } from '@backstage/backend-common'; +import { + configServiceRef, + loggerServiceRef, + schedulerServiceRef, +} from '@backstage/backend-plugin-api'; +import { startTestBackend } from '@backstage/backend-test-utils'; +import { ConfigReader } from '@backstage/config'; +import { eventsExtensionPoint } from '@backstage/plugin-events-node'; +import { TestEventBroker } from '@backstage/plugin-events-backend-test-utils'; +import { awsSqsConsumingEventPublisherEventsModule } from './AwsSqsConsumingEventPublisherEventsModule'; +import { AwsSqsConsumingEventPublisher } from '../publisher/AwsSqsConsumingEventPublisher'; + +describe('awsSqsEventsModule', () => { + it('should be correctly wired and set up', async () => { + const config = new ConfigReader({ + events: { + modules: { + awsSqs: { + awsSqsConsumingEventPublisher: { + topics: { + fake1: { + queue: { + region: 'eu-west-1', + url: 'https://fake1.queue.url', + }, + }, + fake2: { + queue: { + region: 'us-east-1', + url: 'https://fake2.queue.url', + }, + }, + }, + }, + }, + }, + }, + }); + + let addedPublishers: AwsSqsConsumingEventPublisher[] | undefined; + const extensionPoint = { + addPublishers: (publishers: any) => { + addedPublishers = publishers; + }, + }; + + const scheduler = { + scheduleTask: jest.fn(), + }; + + await startTestBackend({ + extensionPoints: [[eventsExtensionPoint, extensionPoint]], + services: [ + [configServiceRef, config], + [loggerServiceRef, getVoidLogger()], + [schedulerServiceRef, scheduler], + ], + features: [awsSqsConsumingEventPublisherEventsModule()], + }); + + expect(addedPublishers).not.toBeUndefined(); + expect(addedPublishers!.length).toEqual(2); + + const eventBroker = new TestEventBroker(); + await Promise.all( + addedPublishers!.map(publisher => publisher.setEventBroker(eventBroker)), + ); + + // publisher.connect(..) was causing the polling for events to be scheduled + expect(scheduler.scheduleTask).toHaveBeenCalledWith( + expect.objectContaining({ id: 'events.awsSqs.publisher:fake1' }), + ); + expect(scheduler.scheduleTask).toHaveBeenCalledWith( + expect.objectContaining({ id: 'events.awsSqs.publisher:fake2' }), + ); + }); +}); diff --git a/plugins/events-backend-module-aws-sqs/src/service/AwsSqsConsumingEventPublisherEventsModule.ts b/plugins/events-backend-module-aws-sqs/src/service/AwsSqsConsumingEventPublisherEventsModule.ts new file mode 100644 index 0000000000..7c33d7baae --- /dev/null +++ b/plugins/events-backend-module-aws-sqs/src/service/AwsSqsConsumingEventPublisherEventsModule.ts @@ -0,0 +1,55 @@ +/* + * 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 { + configServiceRef, + createBackendModule, + loggerServiceRef, + loggerToWinstonLogger, + schedulerServiceRef, +} from '@backstage/backend-plugin-api'; +import { eventsExtensionPoint } from '@backstage/plugin-events-node'; +import { AwsSqsConsumingEventPublisher } from '../publisher/AwsSqsConsumingEventPublisher'; + +/** + * AWS SQS module for the Events plugin. + * + * @alpha + */ +export const awsSqsConsumingEventPublisherEventsModule = createBackendModule({ + pluginId: 'events', + moduleId: 'awsSqsConsumingEventPublisherEventsModule', + register(env) { + env.registerInit({ + deps: { + config: configServiceRef, + events: eventsExtensionPoint, + logger: loggerServiceRef, + scheduler: schedulerServiceRef, + }, + async init({ config, events, logger, scheduler }) { + const winstonLogger = loggerToWinstonLogger(logger); + const sqs = AwsSqsConsumingEventPublisher.fromConfig({ + config: config, + logger: winstonLogger, + scheduler: scheduler, + }); + + events.addPublishers(sqs); + }, + }); + }, +}); diff --git a/plugins/events-backend-module-aws-sqs/src/setupTests.ts b/plugins/events-backend-module-aws-sqs/src/setupTests.ts new file mode 100644 index 0000000000..d3232290a7 --- /dev/null +++ b/plugins/events-backend-module-aws-sqs/src/setupTests.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export {}; diff --git a/plugins/events-backend-module-azure/.eslintrc.js b/plugins/events-backend-module-azure/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/events-backend-module-azure/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/events-backend-module-azure/README.md b/plugins/events-backend-module-azure/README.md new file mode 100644 index 0000000000..d16315b6e7 --- /dev/null +++ b/plugins/events-backend-module-azure/README.md @@ -0,0 +1,43 @@ +# events-backend-module-azure + +Welcome to the `events-backend-module-azure` backend plugin! + +This plugin is a module for the `events-backend` backend plugin +and extends it with an `AzureDevOpsEventRouter`. + +The event router will subscribe to the topic `azureDevOps` +and route the events to more concrete topics based on the value +of the provided `$.eventType` payload field. + +Examples: + +| `$.eventType` | topic | +| ------------------------- | ------------------------------------- | +| `git.push` | `azureDevOps.git.push` | +| `git.pullrequest.created` | `azureDevOps.git.pullrequest.created` | + +Please find all possible webhook event types at the +[official documentation of events](https://learn.microsoft.com/en-us/azure/devops/service-hooks/events?source=recommendations&view=azure-devops) +and [webhooks](https://learn.microsoft.com/en-us/azure/devops/service-hooks/services/webhooks?view=azure-devops). + +## Installation + +Install the [`events-backend` plugin](../events-backend/README.md). + +Install this module: + +```bash +# From your Backstage root directory +yarn add --cwd packages/backend @backstage/plugin-events-backend-module-azure +``` + +Add the event router to the `EventsBackend`: + +```diff ++const githubEventRouter = new AzureDevOpsEventRouter(); + + EventsBackend ++ .addPublishers(githubEventRouter) ++ .addSubscribers(githubEventRouter); +// [...] +``` diff --git a/plugins/events-backend-module-azure/api-report.md b/plugins/events-backend-module-azure/api-report.md new file mode 100644 index 0000000000..510ec91c47 --- /dev/null +++ b/plugins/events-backend-module-azure/api-report.md @@ -0,0 +1,21 @@ +## API Report File for "@backstage/plugin-events-backend-module-azure" + +> 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 { EventParams } from '@backstage/plugin-events-node'; +import { SubTopicEventRouter } from '@backstage/plugin-events-node'; + +// @public +export class AzureDevOpsEventRouter extends SubTopicEventRouter { + constructor(); + // (undocumented) + protected determineSubTopic(params: EventParams): string | undefined; +} + +// @alpha +export const azureDevOpsEventRouterEventsModule: ( + options?: undefined, +) => BackendFeature; +``` diff --git a/plugins/events-backend-module-azure/package.json b/plugins/events-backend-module-azure/package.json new file mode 100644 index 0000000000..ffea618dd0 --- /dev/null +++ b/plugins/events-backend-module-azure/package.json @@ -0,0 +1,40 @@ +{ + "name": "@backstage/plugin-events-backend-module-azure", + "version": "0.0.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "alphaTypes": "dist/index.alpha.d.ts", + "main": "dist/index.cjs.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "backend-plugin-module" + }, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build --experimental-type-build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "dependencies": { + "@backstage/backend-plugin-api": "workspace:^", + "@backstage/plugin-events-node": "workspace:^", + "winston": "^3.2.1" + }, + "devDependencies": { + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", + "@backstage/plugin-events-backend-test-utils": "workspace:^", + "supertest": "^6.1.3" + }, + "files": [ + "alpha", + "dist" + ] +} diff --git a/plugins/events-backend-module-azure/src/index.ts b/plugins/events-backend-module-azure/src/index.ts new file mode 100644 index 0000000000..9a83f751f6 --- /dev/null +++ b/plugins/events-backend-module-azure/src/index.ts @@ -0,0 +1,25 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * The module "azure" for the Backstage backend plugin "events-backend" + * adding an event router for Azure DevOps. + * + * @packageDocumentation + */ + +export { AzureDevOpsEventRouter } from './router/AzureDevOpsEventRouter'; +export { azureDevOpsEventRouterEventsModule } from './service/AzureDevOpsEventRouterEventsModule'; diff --git a/plugins/events-backend-module-azure/src/router/AzureDevOpsEventRouter.test.ts b/plugins/events-backend-module-azure/src/router/AzureDevOpsEventRouter.test.ts new file mode 100644 index 0000000000..56e761a8fc --- /dev/null +++ b/plugins/events-backend-module-azure/src/router/AzureDevOpsEventRouter.test.ts @@ -0,0 +1,50 @@ +/* + * 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 { TestEventBroker } from '@backstage/plugin-events-backend-test-utils'; +import { AzureDevOpsEventRouter } from './AzureDevOpsEventRouter'; + +describe('AzureDevOpsEventRouter', () => { + const eventRouter = new AzureDevOpsEventRouter(); + const topic = 'azureDevOps'; + const eventPayload = { eventType: 'test.type', test: 'payload' }; + const metadata = {}; + + it('no $.eventType', () => { + const eventBroker = new TestEventBroker(); + eventRouter.setEventBroker(eventBroker); + + eventRouter.onEvent({ + topic, + eventPayload: { invalid: 'payload' }, + metadata, + }); + + expect(eventBroker.published).toEqual([]); + }); + + it('with $.eventType', () => { + const eventBroker = new TestEventBroker(); + eventRouter.setEventBroker(eventBroker); + + eventRouter.onEvent({ topic, eventPayload, metadata }); + + expect(eventBroker.published.length).toBe(1); + expect(eventBroker.published[0].topic).toEqual('azureDevOps.test.type'); + expect(eventBroker.published[0].eventPayload).toEqual(eventPayload); + expect(eventBroker.published[0].metadata).toEqual(metadata); + }); +}); diff --git a/plugins/events-backend-module-azure/src/router/AzureDevOpsEventRouter.ts b/plugins/events-backend-module-azure/src/router/AzureDevOpsEventRouter.ts new file mode 100644 index 0000000000..11dd7546dd --- /dev/null +++ b/plugins/events-backend-module-azure/src/router/AzureDevOpsEventRouter.ts @@ -0,0 +1,42 @@ +/* + * 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 { + EventParams, + SubTopicEventRouter, +} from '@backstage/plugin-events-node'; + +/** + * Subscribes to the generic `azureDevOps` topic + * and publishes the events under the more concrete sub-topic + * depending on the `$.eventType` provided. + * + * @public + */ +export class AzureDevOpsEventRouter extends SubTopicEventRouter { + constructor() { + super('azureDevOps'); + } + + protected determineSubTopic(params: EventParams): string | undefined { + if ('eventType' in (params.eventPayload as object)) { + const payload = params.eventPayload as { eventType: string }; + return payload.eventType; + } + + return undefined; + } +} diff --git a/plugins/events-backend-module-azure/src/service/AzureDevOpsEventRouterEventsModule.test.ts b/plugins/events-backend-module-azure/src/service/AzureDevOpsEventRouterEventsModule.test.ts new file mode 100644 index 0000000000..86ab7ea17d --- /dev/null +++ b/plugins/events-backend-module-azure/src/service/AzureDevOpsEventRouterEventsModule.test.ts @@ -0,0 +1,46 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { startTestBackend } from '@backstage/backend-test-utils'; +import { eventsExtensionPoint } from '@backstage/plugin-events-node'; +import { azureDevOpsEventRouterEventsModule } from './AzureDevOpsEventRouterEventsModule'; +import { AzureDevOpsEventRouter } from '../router/AzureDevOpsEventRouter'; + +describe('azureDevOpsEventRouterEventsModule', () => { + it('should be correctly wired and set up', async () => { + let addedPublisher: AzureDevOpsEventRouter | undefined; + let addedSubscriber: AzureDevOpsEventRouter | undefined; + const extensionPoint = { + addPublishers: (publisher: any) => { + addedPublisher = publisher; + }, + addSubscribers: (subscriber: any) => { + addedSubscriber = subscriber; + }, + }; + + await startTestBackend({ + extensionPoints: [[eventsExtensionPoint, extensionPoint]], + services: [], + features: [azureDevOpsEventRouterEventsModule()], + }); + + expect(addedPublisher).not.toBeUndefined(); + expect(addedPublisher).toBeInstanceOf(AzureDevOpsEventRouter); + expect(addedSubscriber).not.toBeUndefined(); + expect(addedSubscriber).toBeInstanceOf(AzureDevOpsEventRouter); + }); +}); diff --git a/plugins/events-backend-module-azure/src/service/AzureDevOpsEventRouterEventsModule.ts b/plugins/events-backend-module-azure/src/service/AzureDevOpsEventRouterEventsModule.ts new file mode 100644 index 0000000000..1219452bd8 --- /dev/null +++ b/plugins/events-backend-module-azure/src/service/AzureDevOpsEventRouterEventsModule.ts @@ -0,0 +1,44 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createBackendModule } from '@backstage/backend-plugin-api'; +import { eventsExtensionPoint } from '@backstage/plugin-events-node'; +import { AzureDevOpsEventRouter } from '../router/AzureDevOpsEventRouter'; + +/** + * Module for the events-backend plugin, adding an event router for Azure DevOps. + * + * Registers the {@link AzureDevOpsEventRouter}. + * + * @alpha + */ +export const azureDevOpsEventRouterEventsModule = createBackendModule({ + pluginId: 'events', + moduleId: 'azureDevOpsEventRouter', + register(env) { + env.registerInit({ + deps: { + events: eventsExtensionPoint, + }, + async init({ events }) { + const eventRouter = new AzureDevOpsEventRouter(); + + events.addPublishers(eventRouter); + events.addSubscribers(eventRouter); + }, + }); + }, +}); diff --git a/plugins/events-backend-module-azure/src/setupTests.ts b/plugins/events-backend-module-azure/src/setupTests.ts new file mode 100644 index 0000000000..d3232290a7 --- /dev/null +++ b/plugins/events-backend-module-azure/src/setupTests.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export {}; diff --git a/plugins/events-backend-module-bitbucket-cloud/.eslintrc.js b/plugins/events-backend-module-bitbucket-cloud/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/events-backend-module-bitbucket-cloud/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/events-backend-module-bitbucket-cloud/README.md b/plugins/events-backend-module-bitbucket-cloud/README.md new file mode 100644 index 0000000000..c58529ed7a --- /dev/null +++ b/plugins/events-backend-module-bitbucket-cloud/README.md @@ -0,0 +1,43 @@ +# events-backend-module-bitbucket-cloud + +Welcome to the `events-backend-module-bitbucket-cloud` backend plugin! + +This plugin is a module for the `events-backend` backend plugin +and extends it with an `BitbucketCloudEventRouter`. + +The event router will subscribe to the topic `bitbucketCloud` +and route the events to more concrete topics based on the value +of the provided `x-event-key` metadata field. + +Examples: + +| x-event-key | topic | +| --------------------- | ------------------------------------ | +| `repo:push` | `bitbucketCloud.repo:push` | +| `repo:updated` | `bitbucketCloud.repo:updated` | +| `pullrequest:created` | `bitbucketCloud.pullrequest:created` | + +Please find all possible webhook event types at the +[official documentation](https://support.atlassian.com/bitbucket-cloud/docs/event-payloads/). + +## Installation + +Install the [`events-backend` plugin](../events-backend/README.md). + +Install this module: + +```bash +# From your Backstage root directory +yarn add --cwd packages/backend @backstage/plugin-events-backend-module-bitbucket-cloud +``` + +Add the event router to the `EventsBackend`: + +```diff ++const bitbucketCloudEventRouter = new BitbucketCloudEventRouter(); + + EventsBackend ++ .addPublishers(bitbucketCloudEventRouter) ++ .addSubscribers(bitbucketCloudEventRouter); +// [...] +``` diff --git a/plugins/events-backend-module-bitbucket-cloud/api-report.md b/plugins/events-backend-module-bitbucket-cloud/api-report.md new file mode 100644 index 0000000000..0e4acfac91 --- /dev/null +++ b/plugins/events-backend-module-bitbucket-cloud/api-report.md @@ -0,0 +1,21 @@ +## API Report File for "@backstage/plugin-events-backend-module-bitbucket-cloud" + +> 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 { EventParams } from '@backstage/plugin-events-node'; +import { SubTopicEventRouter } from '@backstage/plugin-events-node'; + +// @public +export class BitbucketCloudEventRouter extends SubTopicEventRouter { + constructor(); + // (undocumented) + protected determineSubTopic(params: EventParams): string | undefined; +} + +// @alpha +export const bitbucketCloudEventRouterEventsModule: ( + options?: undefined, +) => BackendFeature; +``` diff --git a/plugins/events-backend-module-bitbucket-cloud/package.json b/plugins/events-backend-module-bitbucket-cloud/package.json new file mode 100644 index 0000000000..f43cd9c664 --- /dev/null +++ b/plugins/events-backend-module-bitbucket-cloud/package.json @@ -0,0 +1,40 @@ +{ + "name": "@backstage/plugin-events-backend-module-bitbucket-cloud", + "version": "0.0.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "alphaTypes": "dist/index.alpha.d.ts", + "main": "dist/index.cjs.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "backend-plugin-module" + }, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build --experimental-type-build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "dependencies": { + "@backstage/backend-plugin-api": "workspace:^", + "@backstage/plugin-events-node": "workspace:^", + "winston": "^3.2.1" + }, + "devDependencies": { + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", + "@backstage/plugin-events-backend-test-utils": "workspace:^", + "supertest": "^6.1.3" + }, + "files": [ + "alpha", + "dist" + ] +} diff --git a/plugins/events-backend-module-bitbucket-cloud/src/index.ts b/plugins/events-backend-module-bitbucket-cloud/src/index.ts new file mode 100644 index 0000000000..0a58212de2 --- /dev/null +++ b/plugins/events-backend-module-bitbucket-cloud/src/index.ts @@ -0,0 +1,25 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * The module "bitbucket-cloud" for the Backstage backend plugin "events-backend" + * adding an event router for Bitbucket Cloud. + * + * @packageDocumentation + */ + +export { BitbucketCloudEventRouter } from './router/BitbucketCloudEventRouter'; +export { bitbucketCloudEventRouterEventsModule } from './service/BitbucketCloudEventRouterEventsModule'; diff --git a/plugins/events-backend-module-bitbucket-cloud/src/router/BitbucketCloudEventRouter.test.ts b/plugins/events-backend-module-bitbucket-cloud/src/router/BitbucketCloudEventRouter.test.ts new file mode 100644 index 0000000000..b7a47984e4 --- /dev/null +++ b/plugins/events-backend-module-bitbucket-cloud/src/router/BitbucketCloudEventRouter.test.ts @@ -0,0 +1,46 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { TestEventBroker } from '@backstage/plugin-events-backend-test-utils'; +import { BitbucketCloudEventRouter } from './BitbucketCloudEventRouter'; + +describe('BitbucketCloudEventRouter', () => { + const eventRouter = new BitbucketCloudEventRouter(); + const topic = 'bitbucketCloud'; + const eventPayload = { test: 'payload' }; + const metadata = { 'x-event-key': 'test:type' }; + + it('no x-event-key', () => { + const eventBroker = new TestEventBroker(); + eventRouter.setEventBroker(eventBroker); + + eventRouter.onEvent({ topic, eventPayload }); + + expect(eventBroker.published).toEqual([]); + }); + + it('with x-event-key', () => { + const eventBroker = new TestEventBroker(); + eventRouter.setEventBroker(eventBroker); + + eventRouter.onEvent({ topic, eventPayload, metadata }); + + expect(eventBroker.published.length).toBe(1); + expect(eventBroker.published[0].topic).toEqual('bitbucketCloud.test:type'); + expect(eventBroker.published[0].eventPayload).toEqual(eventPayload); + expect(eventBroker.published[0].metadata).toEqual(metadata); + }); +}); diff --git a/plugins/events-backend-module-bitbucket-cloud/src/router/BitbucketCloudEventRouter.ts b/plugins/events-backend-module-bitbucket-cloud/src/router/BitbucketCloudEventRouter.ts new file mode 100644 index 0000000000..8350511d65 --- /dev/null +++ b/plugins/events-backend-module-bitbucket-cloud/src/router/BitbucketCloudEventRouter.ts @@ -0,0 +1,37 @@ +/* + * 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 { + EventParams, + SubTopicEventRouter, +} from '@backstage/plugin-events-node'; + +/** + * Subscribes to the generic `bitbucketCloud` topic + * and publishes the events under the more concrete sub-topic + * depending on the `x-event-key` provided. + * + * @public + */ +export class BitbucketCloudEventRouter extends SubTopicEventRouter { + constructor() { + super('bitbucketCloud'); + } + + protected determineSubTopic(params: EventParams): string | undefined { + return params.metadata?.['x-event-key'] as string | undefined; + } +} diff --git a/plugins/events-backend-module-bitbucket-cloud/src/service/BitbucketCloudEventRouterEventsModule.test.ts b/plugins/events-backend-module-bitbucket-cloud/src/service/BitbucketCloudEventRouterEventsModule.test.ts new file mode 100644 index 0000000000..e456607a2b --- /dev/null +++ b/plugins/events-backend-module-bitbucket-cloud/src/service/BitbucketCloudEventRouterEventsModule.test.ts @@ -0,0 +1,46 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { startTestBackend } from '@backstage/backend-test-utils'; +import { eventsExtensionPoint } from '@backstage/plugin-events-node'; +import { bitbucketCloudEventRouterEventsModule } from './BitbucketCloudEventRouterEventsModule'; +import { BitbucketCloudEventRouter } from '../router/BitbucketCloudEventRouter'; + +describe('bitbucketCloudEventRouterEventsModule', () => { + it('should be correctly wired and set up', async () => { + let addedPublisher: BitbucketCloudEventRouter | undefined; + let addedSubscriber: BitbucketCloudEventRouter | undefined; + const extensionPoint = { + addPublishers: (publisher: any) => { + addedPublisher = publisher; + }, + addSubscribers: (subscriber: any) => { + addedSubscriber = subscriber; + }, + }; + + await startTestBackend({ + extensionPoints: [[eventsExtensionPoint, extensionPoint]], + services: [], + features: [bitbucketCloudEventRouterEventsModule()], + }); + + expect(addedPublisher).not.toBeUndefined(); + expect(addedPublisher).toBeInstanceOf(BitbucketCloudEventRouter); + expect(addedSubscriber).not.toBeUndefined(); + expect(addedSubscriber).toBeInstanceOf(BitbucketCloudEventRouter); + }); +}); diff --git a/plugins/events-backend-module-bitbucket-cloud/src/service/BitbucketCloudEventRouterEventsModule.ts b/plugins/events-backend-module-bitbucket-cloud/src/service/BitbucketCloudEventRouterEventsModule.ts new file mode 100644 index 0000000000..7f755a28f4 --- /dev/null +++ b/plugins/events-backend-module-bitbucket-cloud/src/service/BitbucketCloudEventRouterEventsModule.ts @@ -0,0 +1,44 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createBackendModule } from '@backstage/backend-plugin-api'; +import { eventsExtensionPoint } from '@backstage/plugin-events-node'; +import { BitbucketCloudEventRouter } from '../router/BitbucketCloudEventRouter'; + +/** + * Module for the events-backend plugin, adding an event router for Bitbucket Cloud. + * + * Registers the {@link BitbucketCloudEventRouter}. + * + * @alpha + */ +export const bitbucketCloudEventRouterEventsModule = createBackendModule({ + pluginId: 'events', + moduleId: 'bitbucketCloudEventRouter', + register(env) { + env.registerInit({ + deps: { + events: eventsExtensionPoint, + }, + async init({ events }) { + const eventRouter = new BitbucketCloudEventRouter(); + + events.addPublishers(eventRouter); + events.addSubscribers(eventRouter); + }, + }); + }, +}); diff --git a/plugins/events-backend-module-bitbucket-cloud/src/setupTests.ts b/plugins/events-backend-module-bitbucket-cloud/src/setupTests.ts new file mode 100644 index 0000000000..d3232290a7 --- /dev/null +++ b/plugins/events-backend-module-bitbucket-cloud/src/setupTests.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export {}; diff --git a/plugins/events-backend-module-gerrit/.eslintrc.js b/plugins/events-backend-module-gerrit/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/events-backend-module-gerrit/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/events-backend-module-gerrit/README.md b/plugins/events-backend-module-gerrit/README.md new file mode 100644 index 0000000000..933b7a172f --- /dev/null +++ b/plugins/events-backend-module-gerrit/README.md @@ -0,0 +1,42 @@ +# events-backend-module-gerrit + +Welcome to the `events-backend-module-gerrit` backend plugin! + +This plugin is a module for the `events-backend` backend plugin +and extends it with an `GerritEventRouter`. + +The event router will subscribe to the topic `gerrit` +and route the events to more concrete topics based on the value +of the provided `$.type` payload field. + +Examples: + +| `$.type` | topic | +| ---------------- | ----------------------- | +| `change-created` | `gerrit.change-created` | +| `change-merged` | `gerrit.change-merged` | + +Please find all possible webhook event types at the +[official documentation](https://gerrit-review.googlesource.com/Documentation/cmd-stream-events.html#events). + +## Installation + +Install the [`events-backend` plugin](../events-backend/README.md). + +Install this module: + +```bash +# From your Backstage root directory +yarn add --cwd packages/backend @backstage/plugin-events-backend-module-gerrit +``` + +Add the event router to the `EventsBackend`: + +```diff ++const gerritEventRouter = new GerritEventRouter(); + + EventsBackend ++ .addPublishers(gerritEventRouter) ++ .addSubscribers(gerritEventRouter); +// [...] +``` diff --git a/plugins/events-backend-module-gerrit/api-report.md b/plugins/events-backend-module-gerrit/api-report.md new file mode 100644 index 0000000000..268e5970fa --- /dev/null +++ b/plugins/events-backend-module-gerrit/api-report.md @@ -0,0 +1,21 @@ +## API Report File for "@backstage/plugin-events-backend-module-gerrit" + +> 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 { EventParams } from '@backstage/plugin-events-node'; +import { SubTopicEventRouter } from '@backstage/plugin-events-node'; + +// @public +export class GerritEventRouter extends SubTopicEventRouter { + constructor(); + // (undocumented) + protected determineSubTopic(params: EventParams): string | undefined; +} + +// @alpha +export const gerritEventRouterEventsModule: ( + options?: undefined, +) => BackendFeature; +``` diff --git a/plugins/events-backend-module-gerrit/package.json b/plugins/events-backend-module-gerrit/package.json new file mode 100644 index 0000000000..f1808fc306 --- /dev/null +++ b/plugins/events-backend-module-gerrit/package.json @@ -0,0 +1,40 @@ +{ + "name": "@backstage/plugin-events-backend-module-gerrit", + "version": "0.0.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "alphaTypes": "dist/index.alpha.d.ts", + "main": "dist/index.cjs.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "backend-plugin-module" + }, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build --experimental-type-build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "dependencies": { + "@backstage/backend-plugin-api": "workspace:^", + "@backstage/plugin-events-node": "workspace:^", + "winston": "^3.2.1" + }, + "devDependencies": { + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", + "@backstage/plugin-events-backend-test-utils": "workspace:^", + "supertest": "^6.1.3" + }, + "files": [ + "alpha", + "dist" + ] +} diff --git a/plugins/events-backend-module-gerrit/src/index.ts b/plugins/events-backend-module-gerrit/src/index.ts new file mode 100644 index 0000000000..1a9ebb03ee --- /dev/null +++ b/plugins/events-backend-module-gerrit/src/index.ts @@ -0,0 +1,25 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * The module `gerrit` for the Backstage backend plugin "events-backend" + * adding an event router for Gerrit. + * + * @packageDocumentation + */ + +export { GerritEventRouter } from './router/GerritEventRouter'; +export { gerritEventRouterEventsModule } from './service/GerritEventRouterEventsModule'; diff --git a/plugins/events-backend-module-gerrit/src/router/GerritEventRouter.test.ts b/plugins/events-backend-module-gerrit/src/router/GerritEventRouter.test.ts new file mode 100644 index 0000000000..7302a26012 --- /dev/null +++ b/plugins/events-backend-module-gerrit/src/router/GerritEventRouter.test.ts @@ -0,0 +1,50 @@ +/* + * 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 { TestEventBroker } from '@backstage/plugin-events-backend-test-utils'; +import { GerritEventRouter } from './GerritEventRouter'; + +describe('GerritEventRouter', () => { + const eventRouter = new GerritEventRouter(); + const topic = 'gerrit'; + const eventPayload = { type: 'test-type', test: 'payload' }; + const metadata = {}; + + it('no $.type', () => { + const eventBroker = new TestEventBroker(); + eventRouter.setEventBroker(eventBroker); + + eventRouter.onEvent({ + topic, + eventPayload: { invalid: 'payload' }, + metadata, + }); + + expect(eventBroker.published).toEqual([]); + }); + + it('with $.type', () => { + const eventBroker = new TestEventBroker(); + eventRouter.setEventBroker(eventBroker); + + eventRouter.onEvent({ topic, eventPayload, metadata }); + + expect(eventBroker.published.length).toBe(1); + expect(eventBroker.published[0].topic).toEqual('gerrit.test-type'); + expect(eventBroker.published[0].eventPayload).toEqual(eventPayload); + expect(eventBroker.published[0].metadata).toEqual(metadata); + }); +}); diff --git a/plugins/events-backend-module-gerrit/src/router/GerritEventRouter.ts b/plugins/events-backend-module-gerrit/src/router/GerritEventRouter.ts new file mode 100644 index 0000000000..3d97508b62 --- /dev/null +++ b/plugins/events-backend-module-gerrit/src/router/GerritEventRouter.ts @@ -0,0 +1,42 @@ +/* + * 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 { + EventParams, + SubTopicEventRouter, +} from '@backstage/plugin-events-node'; + +/** + * Subscribes to the generic `gerrit` topic + * and publishes the events under the more concrete sub-topic + * depending on the `$.type` field provided. + * + * @public + */ +export class GerritEventRouter extends SubTopicEventRouter { + constructor() { + super('gerrit'); + } + + protected determineSubTopic(params: EventParams): string | undefined { + if ('type' in (params.eventPayload as object)) { + const payload = params.eventPayload as { type: string }; + return payload.type; + } + + return undefined; + } +} diff --git a/plugins/events-backend-module-gerrit/src/service/GerritEventRouterEventsModule.test.ts b/plugins/events-backend-module-gerrit/src/service/GerritEventRouterEventsModule.test.ts new file mode 100644 index 0000000000..b5fd6a80ca --- /dev/null +++ b/plugins/events-backend-module-gerrit/src/service/GerritEventRouterEventsModule.test.ts @@ -0,0 +1,46 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { startTestBackend } from '@backstage/backend-test-utils'; +import { eventsExtensionPoint } from '@backstage/plugin-events-node'; +import { gerritEventRouterEventsModule } from './GerritEventRouterEventsModule'; +import { GerritEventRouter } from '../router/GerritEventRouter'; + +describe('gerritEventRouterEventsModule', () => { + it('should be correctly wired and set up', async () => { + let addedPublisher: GerritEventRouter | undefined; + let addedSubscriber: GerritEventRouter | undefined; + const extensionPoint = { + addPublishers: (publisher: any) => { + addedPublisher = publisher; + }, + addSubscribers: (subscriber: any) => { + addedSubscriber = subscriber; + }, + }; + + await startTestBackend({ + extensionPoints: [[eventsExtensionPoint, extensionPoint]], + services: [], + features: [gerritEventRouterEventsModule()], + }); + + expect(addedPublisher).not.toBeUndefined(); + expect(addedPublisher).toBeInstanceOf(GerritEventRouter); + expect(addedSubscriber).not.toBeUndefined(); + expect(addedSubscriber).toBeInstanceOf(GerritEventRouter); + }); +}); diff --git a/plugins/events-backend-module-gerrit/src/service/GerritEventRouterEventsModule.ts b/plugins/events-backend-module-gerrit/src/service/GerritEventRouterEventsModule.ts new file mode 100644 index 0000000000..734b574edd --- /dev/null +++ b/plugins/events-backend-module-gerrit/src/service/GerritEventRouterEventsModule.ts @@ -0,0 +1,44 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createBackendModule } from '@backstage/backend-plugin-api'; +import { eventsExtensionPoint } from '@backstage/plugin-events-node'; +import { GerritEventRouter } from '../router/GerritEventRouter'; + +/** + * Module for the events-backend plugin, adding an event router for Gerrit. + * + * Registers the {@link GerritEventRouter}. + * + * @alpha + */ +export const gerritEventRouterEventsModule = createBackendModule({ + pluginId: 'events', + moduleId: 'gerritEventRouter', + register(env) { + env.registerInit({ + deps: { + events: eventsExtensionPoint, + }, + async init({ events }) { + const eventRouter = new GerritEventRouter(); + + events.addPublishers(eventRouter); + events.addSubscribers(eventRouter); + }, + }); + }, +}); diff --git a/plugins/events-backend-module-gerrit/src/setupTests.ts b/plugins/events-backend-module-gerrit/src/setupTests.ts new file mode 100644 index 0000000000..d3232290a7 --- /dev/null +++ b/plugins/events-backend-module-gerrit/src/setupTests.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export {}; diff --git a/plugins/events-backend-module-github/.eslintrc.js b/plugins/events-backend-module-github/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/events-backend-module-github/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/events-backend-module-github/README.md b/plugins/events-backend-module-github/README.md new file mode 100644 index 0000000000..b111b79dd0 --- /dev/null +++ b/plugins/events-backend-module-github/README.md @@ -0,0 +1,43 @@ +# events-backend-module-github + +Welcome to the `events-backend-module-github` backend plugin! + +This plugin is a module for the `events-backend` backend plugin +and extends it with an `GithubEventRouter`. + +The event router will subscribe to the topic `github` +and route the events to more concrete topics based on the value +of the provided `x-github-event` metadata field. + +Examples: + +| `x-github-event` | topic | +| ---------------- | --------------------- | +| `pull_request` | `github.pull_request` | +| `push` | `github.push` | +| `repository` | `github.repository` | + +Please find all possible webhook event types at the +[official documentation](https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads). + +## Installation + +Install the [`events-backend` plugin](../events-backend/README.md). + +Install this module: + +```bash +# From your Backstage root directory +yarn add --cwd packages/backend @backstage/plugin-events-backend-module-github +``` + +Add the event router to the `EventsBackend`: + +```diff ++const githubEventRouter = new GithubEventRouter(); + + EventsBackend ++ .addPublishers(githubEventRouter) ++ .addSubscribers(githubEventRouter); +// [...] +``` diff --git a/plugins/events-backend-module-github/api-report.md b/plugins/events-backend-module-github/api-report.md new file mode 100644 index 0000000000..25ce30523a --- /dev/null +++ b/plugins/events-backend-module-github/api-report.md @@ -0,0 +1,21 @@ +## API Report File for "@backstage/plugin-events-backend-module-github" + +> 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 { EventParams } from '@backstage/plugin-events-node'; +import { SubTopicEventRouter } from '@backstage/plugin-events-node'; + +// @public +export class GithubEventRouter extends SubTopicEventRouter { + constructor(); + // (undocumented) + protected determineSubTopic(params: EventParams): string | undefined; +} + +// @alpha +export const githubEventRouterEventsModule: ( + options?: undefined, +) => BackendFeature; +``` diff --git a/plugins/events-backend-module-github/package.json b/plugins/events-backend-module-github/package.json new file mode 100644 index 0000000000..7307826297 --- /dev/null +++ b/plugins/events-backend-module-github/package.json @@ -0,0 +1,40 @@ +{ + "name": "@backstage/plugin-events-backend-module-github", + "version": "0.0.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "alphaTypes": "dist/index.alpha.d.ts", + "main": "dist/index.cjs.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "backend-plugin-module" + }, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build --experimental-type-build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "dependencies": { + "@backstage/backend-plugin-api": "workspace:^", + "@backstage/plugin-events-node": "workspace:^", + "winston": "^3.2.1" + }, + "devDependencies": { + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", + "@backstage/plugin-events-backend-test-utils": "workspace:^", + "supertest": "^6.1.3" + }, + "files": [ + "alpha", + "dist" + ] +} diff --git a/plugins/events-backend-module-github/src/index.ts b/plugins/events-backend-module-github/src/index.ts new file mode 100644 index 0000000000..672d82e6dc --- /dev/null +++ b/plugins/events-backend-module-github/src/index.ts @@ -0,0 +1,25 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * The module `github` for the Backstage backend plugin "events-backend" + * adding an event router for GitHub. + * + * @packageDocumentation + */ + +export { GithubEventRouter } from './router/GithubEventRouter'; +export { githubEventRouterEventsModule } from './service/GithubEventRouterEventsModule'; diff --git a/plugins/events-backend-module-github/src/router/GithubEventRouter.test.ts b/plugins/events-backend-module-github/src/router/GithubEventRouter.test.ts new file mode 100644 index 0000000000..14cf6b9933 --- /dev/null +++ b/plugins/events-backend-module-github/src/router/GithubEventRouter.test.ts @@ -0,0 +1,46 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { TestEventBroker } from '@backstage/plugin-events-backend-test-utils'; +import { GithubEventRouter } from './GithubEventRouter'; + +describe('GithubEventRouter', () => { + const eventRouter = new GithubEventRouter(); + const topic = 'github'; + const eventPayload = { test: 'payload' }; + const metadata = { 'x-github-event': 'test_type' }; + + it('no x-github-event', () => { + const eventBroker = new TestEventBroker(); + eventRouter.setEventBroker(eventBroker); + + eventRouter.onEvent({ topic, eventPayload }); + + expect(eventBroker.published).toEqual([]); + }); + + it('with x-github-event', () => { + const eventBroker = new TestEventBroker(); + eventRouter.setEventBroker(eventBroker); + + eventRouter.onEvent({ topic, eventPayload, metadata }); + + expect(eventBroker.published.length).toBe(1); + expect(eventBroker.published[0].topic).toEqual('github.test_type'); + expect(eventBroker.published[0].eventPayload).toEqual(eventPayload); + expect(eventBroker.published[0].metadata).toEqual(metadata); + }); +}); diff --git a/plugins/events-backend-module-github/src/router/GithubEventRouter.ts b/plugins/events-backend-module-github/src/router/GithubEventRouter.ts new file mode 100644 index 0000000000..10dd1c55c6 --- /dev/null +++ b/plugins/events-backend-module-github/src/router/GithubEventRouter.ts @@ -0,0 +1,37 @@ +/* + * 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 { + EventParams, + SubTopicEventRouter, +} from '@backstage/plugin-events-node'; + +/** + * Subscribes to the generic `github` topic + * and publishes the events under the more concrete sub-topic + * depending on the `x-github-event` provided. + * + * @public + */ +export class GithubEventRouter extends SubTopicEventRouter { + constructor() { + super('github'); + } + + protected determineSubTopic(params: EventParams): string | undefined { + return params.metadata?.['x-github-event'] as string | undefined; + } +} diff --git a/plugins/events-backend-module-github/src/service/GithubEventRouterEventsModule.test.ts b/plugins/events-backend-module-github/src/service/GithubEventRouterEventsModule.test.ts new file mode 100644 index 0000000000..694f5e1dbe --- /dev/null +++ b/plugins/events-backend-module-github/src/service/GithubEventRouterEventsModule.test.ts @@ -0,0 +1,46 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { startTestBackend } from '@backstage/backend-test-utils'; +import { eventsExtensionPoint } from '@backstage/plugin-events-node'; +import { githubEventRouterEventsModule } from './GithubEventRouterEventsModule'; +import { GithubEventRouter } from '../router/GithubEventRouter'; + +describe('githubEventRouterEventsModule', () => { + it('should be correctly wired and set up', async () => { + let addedPublisher: GithubEventRouter | undefined; + let addedSubscriber: GithubEventRouter | undefined; + const extensionPoint = { + addPublishers: (publisher: any) => { + addedPublisher = publisher; + }, + addSubscribers: (subscriber: any) => { + addedSubscriber = subscriber; + }, + }; + + await startTestBackend({ + extensionPoints: [[eventsExtensionPoint, extensionPoint]], + services: [], + features: [githubEventRouterEventsModule()], + }); + + expect(addedPublisher).not.toBeUndefined(); + expect(addedPublisher).toBeInstanceOf(GithubEventRouter); + expect(addedSubscriber).not.toBeUndefined(); + expect(addedSubscriber).toBeInstanceOf(GithubEventRouter); + }); +}); diff --git a/plugins/events-backend-module-github/src/service/GithubEventRouterEventsModule.ts b/plugins/events-backend-module-github/src/service/GithubEventRouterEventsModule.ts new file mode 100644 index 0000000000..8914d07e71 --- /dev/null +++ b/plugins/events-backend-module-github/src/service/GithubEventRouterEventsModule.ts @@ -0,0 +1,44 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createBackendModule } from '@backstage/backend-plugin-api'; +import { eventsExtensionPoint } from '@backstage/plugin-events-node'; +import { GithubEventRouter } from '../router/GithubEventRouter'; + +/** + * Module for the events-backend plugin, adding an event router for GitHub. + * + * Registers the {@link GithubEventRouter}. + * + * @alpha + */ +export const githubEventRouterEventsModule = createBackendModule({ + pluginId: 'events', + moduleId: 'githubEventRouter', + register(env) { + env.registerInit({ + deps: { + events: eventsExtensionPoint, + }, + async init({ events }) { + const eventRouter = new GithubEventRouter(); + + events.addPublishers(eventRouter); + events.addSubscribers(eventRouter); + }, + }); + }, +}); diff --git a/plugins/events-backend-module-github/src/setupTests.ts b/plugins/events-backend-module-github/src/setupTests.ts new file mode 100644 index 0000000000..d3232290a7 --- /dev/null +++ b/plugins/events-backend-module-github/src/setupTests.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export {}; diff --git a/plugins/events-backend-module-gitlab/.eslintrc.js b/plugins/events-backend-module-gitlab/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/events-backend-module-gitlab/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/events-backend-module-gitlab/README.md b/plugins/events-backend-module-gitlab/README.md new file mode 100644 index 0000000000..dfbfcd9f4a --- /dev/null +++ b/plugins/events-backend-module-gitlab/README.md @@ -0,0 +1,42 @@ +# events-backend-module-gitlab + +Welcome to the `events-backend-module-gitlab` backend plugin! + +This plugin is a module for the `events-backend` backend plugin +and extends it with an `GitlabEventRouter`. + +The event router will subscribe to the topic `gitlab` +and route the events to more concrete topics based on the value +of the provided `$.event_name` payload field. + +Examples: + +| `$.event_name` | topic | +| --------------- | ---------------------- | +| `push` | `gitlab.push` | +| `merge_request` | `gitlab.merge_request` | + +Please find all possible webhook event types at the +[official documentation](https://docs.gitlab.com/ee/user/project/integrations/webhook_events.html). + +## Installation + +Install the [`events-backend` plugin](../events-backend/README.md). + +Install this module: + +```bash +# From your Backstage root directory +yarn add --cwd packages/backend @backstage/plugin-events-backend-module-gitlab +``` + +Add the event router to the `EventsBackend`: + +```diff ++const gitlabEventRouter = new GitlabEventRouter(); + + EventsBackend ++ .addPublishers(gitlabEventRouter) ++ .addSubscribers(gitlabEventRouter); +// [...] +``` diff --git a/plugins/events-backend-module-gitlab/api-report.md b/plugins/events-backend-module-gitlab/api-report.md new file mode 100644 index 0000000000..8b5183a8d0 --- /dev/null +++ b/plugins/events-backend-module-gitlab/api-report.md @@ -0,0 +1,21 @@ +## API Report File for "@backstage/plugin-events-backend-module-gitlab" + +> 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 { EventParams } from '@backstage/plugin-events-node'; +import { SubTopicEventRouter } from '@backstage/plugin-events-node'; + +// @public +export class GitlabEventRouter extends SubTopicEventRouter { + constructor(); + // (undocumented) + protected determineSubTopic(params: EventParams): string | undefined; +} + +// @alpha +export const gitlabEventRouterEventsModule: ( + options?: undefined, +) => BackendFeature; +``` diff --git a/plugins/events-backend-module-gitlab/package.json b/plugins/events-backend-module-gitlab/package.json new file mode 100644 index 0000000000..72f5a97a5d --- /dev/null +++ b/plugins/events-backend-module-gitlab/package.json @@ -0,0 +1,40 @@ +{ + "name": "@backstage/plugin-events-backend-module-gitlab", + "version": "0.0.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "alphaTypes": "dist/index.alpha.d.ts", + "main": "dist/index.cjs.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "backend-plugin-module" + }, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build --experimental-type-build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "dependencies": { + "@backstage/backend-plugin-api": "workspace:^", + "@backstage/plugin-events-node": "workspace:^", + "winston": "^3.2.1" + }, + "devDependencies": { + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", + "@backstage/plugin-events-backend-test-utils": "workspace:^", + "supertest": "^6.1.3" + }, + "files": [ + "alpha", + "dist" + ] +} diff --git a/plugins/events-backend-module-gitlab/src/index.ts b/plugins/events-backend-module-gitlab/src/index.ts new file mode 100644 index 0000000000..ea96244df4 --- /dev/null +++ b/plugins/events-backend-module-gitlab/src/index.ts @@ -0,0 +1,25 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * The module "gitlab" for the Backstage backend plugin "events-backend" + * adding an event router for GitLab. + * + * @packageDocumentation + */ + +export { GitlabEventRouter } from './router/GitlabEventRouter'; +export { gitlabEventRouterEventsModule } from './service/GitlabEventRouterEventsModule'; diff --git a/plugins/events-backend-module-gitlab/src/router/GitlabEventRouter.test.ts b/plugins/events-backend-module-gitlab/src/router/GitlabEventRouter.test.ts new file mode 100644 index 0000000000..6ced12d3cb --- /dev/null +++ b/plugins/events-backend-module-gitlab/src/router/GitlabEventRouter.test.ts @@ -0,0 +1,50 @@ +/* + * 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 { TestEventBroker } from '@backstage/plugin-events-backend-test-utils'; +import { GitlabEventRouter } from './GitlabEventRouter'; + +describe('GitlabEventRouter', () => { + const eventRouter = new GitlabEventRouter(); + const topic = 'gitlab'; + const eventPayload = { event_name: 'test_type', test: 'payload' }; + const metadata = {}; + + it('no $.event_name', () => { + const eventBroker = new TestEventBroker(); + eventRouter.setEventBroker(eventBroker); + + eventRouter.onEvent({ + topic, + eventPayload: { invalid: 'payload' }, + metadata, + }); + + expect(eventBroker.published).toEqual([]); + }); + + it('with $.event_name', () => { + const eventBroker = new TestEventBroker(); + eventRouter.setEventBroker(eventBroker); + + eventRouter.onEvent({ topic, eventPayload, metadata }); + + expect(eventBroker.published.length).toBe(1); + expect(eventBroker.published[0].topic).toEqual('gitlab.test_type'); + expect(eventBroker.published[0].eventPayload).toEqual(eventPayload); + expect(eventBroker.published[0].metadata).toEqual(metadata); + }); +}); diff --git a/plugins/events-backend-module-gitlab/src/router/GitlabEventRouter.ts b/plugins/events-backend-module-gitlab/src/router/GitlabEventRouter.ts new file mode 100644 index 0000000000..16324340ee --- /dev/null +++ b/plugins/events-backend-module-gitlab/src/router/GitlabEventRouter.ts @@ -0,0 +1,42 @@ +/* + * 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 { + EventParams, + SubTopicEventRouter, +} from '@backstage/plugin-events-node'; + +/** + * Subscribes to the generic `gitlab` topic + * and publishes the events under the more concrete sub-topic + * depending on the `$.event_name` field provided. + * + * @public + */ +export class GitlabEventRouter extends SubTopicEventRouter { + constructor() { + super('gitlab'); + } + + protected determineSubTopic(params: EventParams): string | undefined { + if ('event_name' in (params.eventPayload as object)) { + const payload = params.eventPayload as { event_name: string }; + return payload.event_name; + } + + return undefined; + } +} diff --git a/plugins/events-backend-module-gitlab/src/service/GitlabEventRouterEventsModule.test.ts b/plugins/events-backend-module-gitlab/src/service/GitlabEventRouterEventsModule.test.ts new file mode 100644 index 0000000000..f0ffca3397 --- /dev/null +++ b/plugins/events-backend-module-gitlab/src/service/GitlabEventRouterEventsModule.test.ts @@ -0,0 +1,46 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { startTestBackend } from '@backstage/backend-test-utils'; +import { eventsExtensionPoint } from '@backstage/plugin-events-node'; +import { gitlabEventRouterEventsModule } from './GitlabEventRouterEventsModule'; +import { GitlabEventRouter } from '../router/GitlabEventRouter'; + +describe('gitlabEventRouterEventsModule', () => { + it('should be correctly wired and set up', async () => { + let addedPublisher: GitlabEventRouter | undefined; + let addedSubscriber: GitlabEventRouter | undefined; + const extensionPoint = { + addPublishers: (publisher: any) => { + addedPublisher = publisher; + }, + addSubscribers: (subscriber: any) => { + addedSubscriber = subscriber; + }, + }; + + await startTestBackend({ + extensionPoints: [[eventsExtensionPoint, extensionPoint]], + services: [], + features: [gitlabEventRouterEventsModule()], + }); + + expect(addedPublisher).not.toBeUndefined(); + expect(addedPublisher).toBeInstanceOf(GitlabEventRouter); + expect(addedSubscriber).not.toBeUndefined(); + expect(addedSubscriber).toBeInstanceOf(GitlabEventRouter); + }); +}); diff --git a/plugins/events-backend-module-gitlab/src/service/GitlabEventRouterEventsModule.ts b/plugins/events-backend-module-gitlab/src/service/GitlabEventRouterEventsModule.ts new file mode 100644 index 0000000000..9ab2e1263e --- /dev/null +++ b/plugins/events-backend-module-gitlab/src/service/GitlabEventRouterEventsModule.ts @@ -0,0 +1,44 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createBackendModule } from '@backstage/backend-plugin-api'; +import { eventsExtensionPoint } from '@backstage/plugin-events-node'; +import { GitlabEventRouter } from '../router/GitlabEventRouter'; + +/** + * Module for the events-backend plugin, adding an event router for GitLab. + * + * Registers the {@link GitlabEventRouter}. + * + * @alpha + */ +export const gitlabEventRouterEventsModule = createBackendModule({ + pluginId: 'events', + moduleId: 'gitlabEventRouter', + register(env) { + env.registerInit({ + deps: { + events: eventsExtensionPoint, + }, + async init({ events }) { + const eventRouter = new GitlabEventRouter(); + + events.addPublishers(eventRouter); + events.addSubscribers(eventRouter); + }, + }); + }, +}); diff --git a/plugins/events-backend-module-gitlab/src/setupTests.ts b/plugins/events-backend-module-gitlab/src/setupTests.ts new file mode 100644 index 0000000000..d3232290a7 --- /dev/null +++ b/plugins/events-backend-module-gitlab/src/setupTests.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export {}; diff --git a/plugins/events-backend-test-utils/.eslintrc.js b/plugins/events-backend-test-utils/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/events-backend-test-utils/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/events-backend-test-utils/README.md b/plugins/events-backend-test-utils/README.md new file mode 100644 index 0000000000..c8727b536b --- /dev/null +++ b/plugins/events-backend-test-utils/README.md @@ -0,0 +1,4 @@ +# plugin-events-backend-test-utils + +Houses implementations of plugin-events-node interfaces +which can be useful for test for events-backend and its modules. diff --git a/plugins/events-backend-test-utils/api-report.md b/plugins/events-backend-test-utils/api-report.md new file mode 100644 index 0000000000..46131c4244 --- /dev/null +++ b/plugins/events-backend-test-utils/api-report.md @@ -0,0 +1,47 @@ +## API Report File for "@backstage/plugin-events-backend-test-utils" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { EventBroker } from '@backstage/plugin-events-node'; +import { EventParams } from '@backstage/plugin-events-node'; +import { EventPublisher } from '@backstage/plugin-events-node'; +import { EventSubscriber } from '@backstage/plugin-events-node'; + +// @public (undocumented) +export class TestEventBroker implements EventBroker { + // (undocumented) + publish(params: EventParams): Promise; + // (undocumented) + readonly published: EventParams[]; + // (undocumented) + subscribe( + ...subscribers: Array> + ): void; + // (undocumented) + readonly subscribed: EventSubscriber[]; +} + +// @public (undocumented) +export class TestEventPublisher implements EventPublisher { + // (undocumented) + get eventBroker(): EventBroker | undefined; + // (undocumented) + setEventBroker(eventBroker: EventBroker): Promise; +} + +// @public (undocumented) +export class TestEventSubscriber implements EventSubscriber { + constructor(name: string, topics: string[]); + // (undocumented) + readonly name: string; + // (undocumented) + onEvent(params: EventParams): Promise; + // (undocumented) + readonly receivedEvents: Record; + // (undocumented) + supportsEventTopics(): string[]; + // (undocumented) + readonly topics: string[]; +} +``` diff --git a/plugins/events-backend-test-utils/package.json b/plugins/events-backend-test-utils/package.json new file mode 100644 index 0000000000..c834ee39cf --- /dev/null +++ b/plugins/events-backend-test-utils/package.json @@ -0,0 +1,34 @@ +{ + "name": "@backstage/plugin-events-backend-test-utils", + "description": "The plugin-events-backend-test-utils for @backstage/plugin-events-node", + "version": "0.0.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "main": "dist/index.cjs.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "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": { + "@backstage/plugin-events-node": "workspace:^" + }, + "devDependencies": { + "@backstage/cli": "workspace:^" + }, + "files": [ + "dist" + ] +} diff --git a/plugins/events-backend-test-utils/src/index.ts b/plugins/events-backend-test-utils/src/index.ts new file mode 100644 index 0000000000..efba5be0d0 --- /dev/null +++ b/plugins/events-backend-test-utils/src/index.ts @@ -0,0 +1,23 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * The events-test-utils module for `@backstage/plugin-events-node`. + * + * @packageDocumentation + */ + +export * from './testUtils'; diff --git a/plugins/events-backend-test-utils/src/testUtils/TestEventBroker.ts b/plugins/events-backend-test-utils/src/testUtils/TestEventBroker.ts new file mode 100644 index 0000000000..c697a6506f --- /dev/null +++ b/plugins/events-backend-test-utils/src/testUtils/TestEventBroker.ts @@ -0,0 +1,37 @@ +/* + * 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 { + EventBroker, + EventParams, + EventSubscriber, +} from '@backstage/plugin-events-node'; + +/** @public */ +export class TestEventBroker implements EventBroker { + readonly published: EventParams[] = []; + readonly subscribed: EventSubscriber[] = []; + + async publish(params: EventParams): Promise { + this.published.push(params); + } + + subscribe( + ...subscribers: Array> + ): void { + this.subscribed.push(...subscribers.flat()); + } +} diff --git a/plugins/events-backend-test-utils/src/testUtils/TestEventPublisher.ts b/plugins/events-backend-test-utils/src/testUtils/TestEventPublisher.ts new file mode 100644 index 0000000000..c1b2038afb --- /dev/null +++ b/plugins/events-backend-test-utils/src/testUtils/TestEventPublisher.ts @@ -0,0 +1,30 @@ +/* + * 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 { EventBroker, EventPublisher } from '@backstage/plugin-events-node'; + +/** @public */ +export class TestEventPublisher implements EventPublisher { + #eventBroker?: EventBroker; + + async setEventBroker(eventBroker: EventBroker): Promise { + this.#eventBroker = eventBroker; + } + + get eventBroker() { + return this.#eventBroker; + } +} diff --git a/plugins/events-backend-test-utils/src/testUtils/TestEventSubscriber.ts b/plugins/events-backend-test-utils/src/testUtils/TestEventSubscriber.ts new file mode 100644 index 0000000000..ef5758b804 --- /dev/null +++ b/plugins/events-backend-test-utils/src/testUtils/TestEventSubscriber.ts @@ -0,0 +1,39 @@ +/* + * 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 { EventParams, EventSubscriber } from '@backstage/plugin-events-node'; + +/** @public */ +export class TestEventSubscriber implements EventSubscriber { + readonly name: string; + readonly topics: string[]; + + readonly receivedEvents: Record = {}; + + constructor(name: string, topics: string[]) { + this.name = name; + this.topics = topics; + } + + supportsEventTopics(): string[] { + return this.topics; + } + + async onEvent(params: EventParams): Promise { + this.receivedEvents[params.topic] = this.receivedEvents[params.topic] ?? []; + this.receivedEvents[params.topic].push(params); + } +} diff --git a/plugins/events-backend-test-utils/src/testUtils/index.ts b/plugins/events-backend-test-utils/src/testUtils/index.ts new file mode 100644 index 0000000000..a571ba3075 --- /dev/null +++ b/plugins/events-backend-test-utils/src/testUtils/index.ts @@ -0,0 +1,19 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { TestEventBroker } from './TestEventBroker'; +export { TestEventPublisher } from './TestEventPublisher'; +export { TestEventSubscriber } from './TestEventSubscriber'; diff --git a/plugins/events-backend/.eslintrc.js b/plugins/events-backend/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/events-backend/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/events-backend/README.md b/plugins/events-backend/README.md new file mode 100644 index 0000000000..f71df21517 --- /dev/null +++ b/plugins/events-backend/README.md @@ -0,0 +1,210 @@ +# events-backend + +Welcome to the events-backend backend plugin! + +This plugin provides the wiring of all extension points +for managing events as defined by [plugin-events-node](../events-node) +including backend plugin `EventsPlugin` and `EventsBackend`. + +Additionally, it uses a simple in-memory implementation for +the `EventBroker` by default which you can replace with a more sophisticated +implementation of your choice as you need (e.g., via module). + +Some of these (non-exhaustive) may provide added persistence, +or use external systems like AWS EventBridge, AWS SNS, Kafka, etc. + +By default, the plugin ships with support to receive events via HTTP endpoints +`POST /api/events/http/{topic}` and will publish these +to the used event broker. + +## Installation + +```bash +# From your Backstage root directory +yarn add --cwd packages/backend @backstage/plugin-events-backend +``` + +Add a file [`packages/backend/src/plugins/events.ts`](../../packages/backend/src/plugins/events.ts) +to your Backstage project. + +There, you can add all publishers, subscribers, etc. you want. + +Additionally, add the events plugin to your backend. + +```diff +// packages/backend/src/index.ts +// [...] ++import events from './plugins/events'; +// [...] ++ const eventsEnv = useHotMemoize(module, () => createEnv('events')); +// [...] ++ apiRouter.use('/events', await events(eventsEnv, [])); +// [...] +``` + +### With Event-based Entity Providers + +In case you use event-based `EntityProviders`, +you may need something like the following: + +```diff +// packages/backend/src/index.ts +- apiRouter.use('/events', await events(eventsEnv, [])); ++ apiRouter.use('/events', await events(eventsEnv, eventBasedEntityProviders)); +``` + +as well as a file +[`packages/backend/src/plugins/catalogEventBasedProviders.ts`](../../packages/backend/src/plugins/catalogEventBasedProviders.ts) +which contains event-based entity providers. + +In case you don't have this dependency added yet: + +```bash +# From your Backstage root directory +yarn add --cwd packages/backend @backstage/plugin-events-backend +``` + +```diff +// packages/backend/src/plugins/catalog.ts + import { CatalogBuilder } from '@backstage/plugin-catalog-backend'; ++import { EntityProvider } from '@backstage/plugin-catalog-node'; + import { ScaffolderEntitiesProcessor } from '@backstage/plugin-scaffolder-backend'; + import { Router } from 'express'; + import { PluginEnvironment } from '../types'; + + export default async function createPlugin( + env: PluginEnvironment, ++ providers?: Array, + ): Promise { + const builder = await CatalogBuilder.create(env); + builder.addProcessor(new ScaffolderEntitiesProcessor()); ++ builder.addEntityProvider(providers ?? []); + const { processingEngine, router } = await builder.build(); + await processingEngine.start(); + return router; + } +``` + +## Configuration + +In order to create HTTP endpoints to receive events for a certain +topic, you need to add them at your configuration: + +```yaml +events: + http: + topics: + - bitbucketCloud + - github + - whatever +``` + +Only those topics added to the configuration will result in +available endpoints. + +The example above would result in the following endpoints: + +``` +POST /api/events/http/bitbucketCloud +POST /api/events/http/github +POST /api/events/http/whatever +``` + +You may want to use these for webhooks by SCM providers +in combination with suitable event subscribers. + +However, it is not limited to these use cases. + +## Use Cases + +### Custom Event Broker + +Example using the `EventsBackend`: + +```ts +new EventsBackend(env.logger) + .setEventBroker(yourEventBroker) + // [...] + .start(); +``` + +Example using a module: + +```ts +import { eventsExtensionPoint } from '@backstage/plugin-events-node'; + +// [...] + +export const yourModuleEventsModule = createBackendModule({ + pluginId: 'events', + moduleId: 'yourModule', + register(env) { + // [...] + env.registerInit({ + deps: { + // [...] + events: eventsExtensionPoint, + // [...] + }, + async init({ /* ... */ events /*, ... */ }) { + // [...] + const yourEventBroker = new YourEventBroker(); + // [...] + events.setEventBroker(yourEventBroker); + }, + }); + }, +}); +``` + +### Request Validator + +Example using the `EventsBackend`: + +```ts +const http = HttpPostIngressEventPublisher.fromConfig({ + config: env.config, + ingresses: { + yourTopic: { + validator: yourValidator, + }, + }, + logger: env.logger, + router: httpRouter, +}); + +await new EventsBackend(env.logger) + .addPublishers(http) + // [...] + .start(); +``` + +Example using a module: + +```ts +import { eventsExtensionPoint } from '@backstage/plugin-events-node'; + +// [...] + +export const yourModuleEventsModule = createBackendModule({ + pluginId: 'events', + moduleId: 'yourModule', + register(env) { + // [...] + env.registerInit({ + deps: { + // [...] + events: eventsExtensionPoint, + // [...] + }, + async init({ /* ... */ events /*, ... */ }) { + // [...] + events.addHttpPostIngress({ + topic: 'your-topic', + validator: yourValidator, + }); + }, + }); + }, +}); +``` diff --git a/plugins/events-backend/api-report.md b/plugins/events-backend/api-report.md new file mode 100644 index 0000000000..4154168fa1 --- /dev/null +++ b/plugins/events-backend/api-report.md @@ -0,0 +1,48 @@ +## API Report File for "@backstage/plugin-events-backend" + +> 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 { EventBroker } from '@backstage/plugin-events-node'; +import { EventPublisher } from '@backstage/plugin-events-node'; +import { EventSubscriber } from '@backstage/plugin-events-node'; +import express from 'express'; +import { HttpPostIngressOptions } from '@backstage/plugin-events-node'; +import { Logger } from 'winston'; + +// @public +export class EventsBackend { + constructor(logger: Logger); + // (undocumented) + addPublishers( + ...publishers: Array> + ): EventsBackend; + // (undocumented) + addSubscribers( + ...subscribers: Array> + ): EventsBackend; + // (undocumented) + setEventBroker(eventBroker: EventBroker): EventsBackend; + start(): Promise; +} + +// @alpha +export const eventsPlugin: (options?: undefined) => BackendFeature; + +// @public +export class HttpPostIngressEventPublisher implements EventPublisher { + // (undocumented) + static fromConfig(env: { + config: Config; + ingresses?: { + [topic: string]: Omit; + }; + logger: Logger; + router: express.Router; + }): HttpPostIngressEventPublisher; + // (undocumented) + setEventBroker(eventBroker: EventBroker): Promise; +} +``` diff --git a/plugins/events-backend/config.d.ts b/plugins/events-backend/config.d.ts new file mode 100644 index 0000000000..3d26661855 --- /dev/null +++ b/plugins/events-backend/config.d.ts @@ -0,0 +1,28 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface Config { + events?: { + http?: { + /** + * Topics for which a route has to be registered + * at which we can receive events via HTTP POST requests + * (i.e. received from webhooks). + */ + topics?: string[]; + }; + }; +} diff --git a/plugins/events-backend/package.json b/plugins/events-backend/package.json new file mode 100644 index 0000000000..2d82953e71 --- /dev/null +++ b/plugins/events-backend/package.json @@ -0,0 +1,48 @@ +{ + "name": "@backstage/plugin-events-backend", + "version": "0.0.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "alphaTypes": "dist/index.alpha.d.ts", + "main": "dist/index.cjs.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "backend-plugin" + }, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build --experimental-type-build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "dependencies": { + "@backstage/backend-common": "workspace:^", + "@backstage/backend-plugin-api": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/plugin-events-node": "workspace:^", + "@types/express": "^4.17.6", + "express": "^4.17.1", + "express-promise-router": "^4.1.0", + "winston": "^3.2.1" + }, + "devDependencies": { + "@backstage/backend-common": "workspace:^", + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", + "@backstage/plugin-events-backend-test-utils": "workspace:^", + "supertest": "^6.1.3" + }, + "files": [ + "alpha", + "config.d.ts", + "dist" + ], + "configSchema": "config.d.ts" +} diff --git a/plugins/events-backend/src/index.ts b/plugins/events-backend/src/index.ts new file mode 100644 index 0000000000..5026729015 --- /dev/null +++ b/plugins/events-backend/src/index.ts @@ -0,0 +1,25 @@ +/* + * 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. + */ + +/** + * The Backstage backend plugin "events" that provides the event management. + * + * @packageDocumentation + */ + +export { EventsBackend } from './service/EventsBackend'; +export { eventsPlugin } from './service/EventsPlugin'; +export { HttpPostIngressEventPublisher } from './service/http'; diff --git a/plugins/events-backend/src/service/EventsBackend.test.ts b/plugins/events-backend/src/service/EventsBackend.test.ts new file mode 100644 index 0000000000..c2041b57ac --- /dev/null +++ b/plugins/events-backend/src/service/EventsBackend.test.ts @@ -0,0 +1,60 @@ +/* + * 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 { getVoidLogger } from '@backstage/backend-common'; +import { + TestEventBroker, + TestEventPublisher, + TestEventSubscriber, +} from '@backstage/plugin-events-backend-test-utils'; +import { EventsBackend } from './EventsBackend'; + +const logger = getVoidLogger(); + +describe('EventsBackend', () => { + it('wires up all components', async () => { + const eventBroker = new TestEventBroker(); + const publisher1 = new TestEventPublisher(); + const publisher2 = new TestEventPublisher(); + + await new EventsBackend(logger) + .setEventBroker(eventBroker) + .addPublishers(publisher1, [publisher2]) + .addSubscribers(new TestEventSubscriber('one', ['topicA']), [ + new TestEventSubscriber('two', ['topicA', 'topicB']), + ]) + .start(); + + await eventBroker.publish({ + topic: 'topicA', + eventPayload: { test: 'payload' }, + }); + + expect(eventBroker.published.length).toEqual(1); + expect(eventBroker.published[0].topic).toEqual('topicA'); + expect(eventBroker.published[0].eventPayload).toEqual({ test: 'payload' }); + + expect(eventBroker.subscribed.length).toEqual(2); + expect( + eventBroker.subscribed.map( + sub => (sub as unknown as TestEventSubscriber).name, + ), + ).toEqual(['one', 'two']); + + expect(publisher1.eventBroker).toBe(eventBroker); + expect(publisher2.eventBroker).toBe(eventBroker); + }); +}); diff --git a/plugins/events-backend/src/service/EventsBackend.ts b/plugins/events-backend/src/service/EventsBackend.ts new file mode 100644 index 0000000000..77b1b538f7 --- /dev/null +++ b/plugins/events-backend/src/service/EventsBackend.ts @@ -0,0 +1,67 @@ +/* + * 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 { + EventBroker, + EventPublisher, + EventSubscriber, +} from '@backstage/plugin-events-node'; +import { Logger } from 'winston'; +import { InMemoryEventBroker } from './InMemoryEventBroker'; + +/** + * A builder that helps wire up all component parts of the event management. + * + * @public + */ +export class EventsBackend { + private eventBroker: EventBroker; + private publishers: EventPublisher[] = []; + private subscribers: EventSubscriber[] = []; + + constructor(logger: Logger) { + this.eventBroker = new InMemoryEventBroker(logger); + } + + setEventBroker(eventBroker: EventBroker): EventsBackend { + this.eventBroker = eventBroker; + return this; + } + + addPublishers( + ...publishers: Array> + ): EventsBackend { + this.publishers.push(...publishers.flat()); + return this; + } + + addSubscribers( + ...subscribers: Array> + ): EventsBackend { + this.subscribers.push(...subscribers.flat()); + return this; + } + + /** + * Wires up and returns all component parts of the event management. + */ + async start(): Promise { + this.eventBroker.subscribe(this.subscribers); + this.publishers.forEach(publisher => + publisher.setEventBroker(this.eventBroker), + ); + } +} diff --git a/plugins/events-backend/src/service/EventsPlugin.test.ts b/plugins/events-backend/src/service/EventsPlugin.test.ts new file mode 100644 index 0000000000..f58f081742 --- /dev/null +++ b/plugins/events-backend/src/service/EventsPlugin.test.ts @@ -0,0 +1,97 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { errorHandler, getVoidLogger } from '@backstage/backend-common'; +import { ConfigReader } from '@backstage/config'; +import { + configServiceRef, + createBackendModule, + httpRouterServiceRef, + loggerServiceRef, +} from '@backstage/backend-plugin-api'; +import { startTestBackend } from '@backstage/backend-test-utils'; +import { eventsExtensionPoint } from '@backstage/plugin-events-node'; +import { + TestEventBroker, + TestEventPublisher, + TestEventSubscriber, +} from '@backstage/plugin-events-backend-test-utils'; +import express from 'express'; +import Router from 'express-promise-router'; +import request from 'supertest'; +import { eventsPlugin } from './EventsPlugin'; + +describe('eventPlugin', () => { + it('should be initialized properly', async () => { + const eventBroker = new TestEventBroker(); + const publisher = new TestEventPublisher(); + const subscriber = new TestEventSubscriber('sub', ['fake']); + + const config = new ConfigReader({ + events: { + http: { + topics: ['fake'], + }, + }, + }); + + const httpRouter = Router(); + httpRouter.use(express.json()); + httpRouter.use(errorHandler()); + const app = express().use(httpRouter); + + const testModule = createBackendModule({ + pluginId: 'events', + moduleId: 'test', + register(env) { + env.registerInit({ + deps: { + events: eventsExtensionPoint, + }, + async init({ events }) { + events.setEventBroker(eventBroker); + events.addPublishers(publisher); + events.addSubscribers(subscriber); + }, + }); + }, + }); + + await startTestBackend({ + extensionPoints: [], + services: [ + [configServiceRef, config], + [httpRouterServiceRef, httpRouter], + [loggerServiceRef, getVoidLogger()], + ], + features: [eventsPlugin(), testModule()], + }); + + expect(publisher.eventBroker).toBe(eventBroker); + expect(eventBroker.subscribed.length).toEqual(1); + expect(eventBroker.subscribed[0]).toBe(subscriber); + + const response = await request(app) + .post('/http/fake') + .timeout(100) + .send({ test: 'fake' }); + expect(response.status).toBe(202); + + expect(eventBroker.published.length).toEqual(1); + expect(eventBroker.published[0].topic).toEqual('fake'); + expect(eventBroker.published[0].eventPayload).toEqual({ test: 'fake' }); + }); +}); diff --git a/plugins/events-backend/src/service/EventsPlugin.ts b/plugins/events-backend/src/service/EventsPlugin.ts new file mode 100644 index 0000000000..d5a38a7fd7 --- /dev/null +++ b/plugins/events-backend/src/service/EventsPlugin.ts @@ -0,0 +1,131 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + configServiceRef, + createBackendPlugin, + httpRouterServiceRef, + loggerServiceRef, + loggerToWinstonLogger, +} from '@backstage/backend-plugin-api'; +import { + EventBroker, + EventPublisher, + EventSubscriber, + eventsExtensionPoint, + EventsExtensionPoint, + HttpPostIngressOptions, +} from '@backstage/plugin-events-node'; +import { InMemoryEventBroker } from './InMemoryEventBroker'; +import Router from 'express-promise-router'; +import { HttpPostIngressEventPublisher } from './http'; + +class EventsExtensionPointImpl implements EventsExtensionPoint { + #eventBroker: EventBroker | undefined; + #httpPostIngresses: HttpPostIngressOptions[] = []; + #publishers: EventPublisher[] = []; + #subscribers: EventSubscriber[] = []; + + setEventBroker(eventBroker: EventBroker): void { + this.#eventBroker = eventBroker; + } + + addPublishers( + ...publishers: Array> + ): void { + this.#publishers.push(...publishers.flat()); + } + + addSubscribers( + ...subscribers: Array> + ): void { + this.#subscribers.push(...subscribers.flat()); + } + + addHttpPostIngress(options: HttpPostIngressOptions) { + this.#httpPostIngresses.push(options); + } + + get eventBroker() { + return this.#eventBroker; + } + + get publishers() { + return this.#publishers; + } + + get subscribers() { + return this.#subscribers; + } + + get httpPostIngresses() { + return this.#httpPostIngresses; + } +} + +/** + * Events plugin + * + * @alpha + */ +export const eventsPlugin = createBackendPlugin({ + id: 'events', + register(env) { + const extensionPoint = new EventsExtensionPointImpl(); + env.registerExtensionPoint(eventsExtensionPoint, extensionPoint); + + env.registerInit({ + deps: { + config: configServiceRef, + httpRouter: httpRouterServiceRef, + logger: loggerServiceRef, + }, + async init({ config, httpRouter, logger }) { + const winstonLogger = loggerToWinstonLogger(logger); + const eventsRouter = Router(); + const router = Router(); + eventsRouter.use('/http', router); + + const ingresses = Object.fromEntries( + extensionPoint.httpPostIngresses.map(ingress => [ + ingress.topic, + ingress as Omit, + ]), + ); + + const http = HttpPostIngressEventPublisher.fromConfig({ + config, + logger: winstonLogger, + router, + ingresses, + }); + + if (!extensionPoint.eventBroker) { + extensionPoint.setEventBroker(new InMemoryEventBroker(winstonLogger)); + } + + extensionPoint.eventBroker!.subscribe(extensionPoint.subscribers); + [extensionPoint.publishers, http] + .flat() + .forEach(publisher => + publisher.setEventBroker(extensionPoint.eventBroker!), + ); + + httpRouter.use(eventsRouter); + }, + }); + }, +}); diff --git a/plugins/events-backend/src/service/InMemoryEventBroker.test.ts b/plugins/events-backend/src/service/InMemoryEventBroker.test.ts new file mode 100644 index 0000000000..68a6f63a72 --- /dev/null +++ b/plugins/events-backend/src/service/InMemoryEventBroker.test.ts @@ -0,0 +1,66 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { getVoidLogger } from '@backstage/backend-common'; +import { TestEventSubscriber } from '@backstage/plugin-events-backend-test-utils'; +import { InMemoryEventBroker } from './InMemoryEventBroker'; + +const logger = getVoidLogger(); + +describe('InMemoryEventBroker', () => { + it('passes events to interested subscribers', () => { + const subscriber1 = new TestEventSubscriber('test1', ['topicA', 'topicB']); + const subscriber2 = new TestEventSubscriber('test2', ['topicB', 'topicC']); + const eventBroker = new InMemoryEventBroker(logger); + + eventBroker.subscribe(subscriber1); + eventBroker.subscribe(subscriber2); + eventBroker.publish({ topic: 'topicA', eventPayload: { test: 'topicA' } }); + eventBroker.publish({ topic: 'topicB', eventPayload: { test: 'topicB' } }); + eventBroker.publish({ topic: 'topicC', eventPayload: { test: 'topicC' } }); + eventBroker.publish({ topic: 'topicD', eventPayload: { test: 'topicD' } }); + + expect(Object.keys(subscriber1.receivedEvents)).toEqual([ + 'topicA', + 'topicB', + ]); + expect(subscriber1.receivedEvents.topicA.length).toEqual(1); + expect(subscriber1.receivedEvents.topicA[0]).toEqual({ + topic: 'topicA', + eventPayload: { test: 'topicA' }, + }); + expect(subscriber1.receivedEvents.topicB.length).toEqual(1); + expect(subscriber1.receivedEvents.topicB[0]).toEqual({ + topic: 'topicB', + eventPayload: { test: 'topicB' }, + }); + + expect(Object.keys(subscriber2.receivedEvents)).toEqual([ + 'topicB', + 'topicC', + ]); + expect(subscriber2.receivedEvents.topicB.length).toEqual(1); + expect(subscriber2.receivedEvents.topicB[0]).toEqual({ + topic: 'topicB', + eventPayload: { test: 'topicB' }, + }); + expect(subscriber2.receivedEvents.topicC.length).toEqual(1); + expect(subscriber2.receivedEvents.topicC[0]).toEqual({ + topic: 'topicC', + eventPayload: { test: 'topicC' }, + }); + }); +}); diff --git a/plugins/events-backend/src/service/InMemoryEventBroker.ts b/plugins/events-backend/src/service/InMemoryEventBroker.ts new file mode 100644 index 0000000000..90c7d912fe --- /dev/null +++ b/plugins/events-backend/src/service/InMemoryEventBroker.ts @@ -0,0 +1,58 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + EventBroker, + EventParams, + EventSubscriber, +} from '@backstage/plugin-events-node'; +import { Logger } from 'winston'; + +/** + * In-memory event broker which will pass the event to all registered subscribers + * interested in it. + * Events will not be persisted in any form. + */ +// TODO(pjungermann): add prom metrics? (see plugins/catalog-backend/src/util/metrics.ts, etc.) +export class InMemoryEventBroker implements EventBroker { + constructor(private readonly logger: Logger) {} + + private readonly subscribers: { + [topic: string]: EventSubscriber[]; + } = {}; + + async publish(params: EventParams): Promise { + this.logger.debug( + `Event received: topic=${params.topic}, metadata=${JSON.stringify( + params.metadata, + )}, payload=${JSON.stringify(params.eventPayload)}`, + ); + + const subscribed = this.subscribers[params.topic] ?? []; + subscribed.forEach(subscriber => subscriber.onEvent(params)); + } + + subscribe( + ...subscribers: Array> + ): void { + subscribers.flat().forEach(subscriber => { + subscriber.supportsEventTopics().forEach(topic => { + this.subscribers[topic] = this.subscribers[topic] ?? []; + this.subscribers[topic].push(subscriber); + }); + }); + } +} diff --git a/plugins/events-backend/src/service/http/HttpPostIngressEventPublisher.test.ts b/plugins/events-backend/src/service/http/HttpPostIngressEventPublisher.test.ts new file mode 100644 index 0000000000..3d93e347b3 --- /dev/null +++ b/plugins/events-backend/src/service/http/HttpPostIngressEventPublisher.test.ts @@ -0,0 +1,225 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { errorHandler, getVoidLogger } from '@backstage/backend-common'; +import { ConfigReader } from '@backstage/config'; +import { TestEventBroker } from '@backstage/plugin-events-backend-test-utils'; +import express from 'express'; +import Router from 'express-promise-router'; +import request from 'supertest'; +import { HttpPostIngressEventPublisher } from './HttpPostIngressEventPublisher'; + +describe('HttpPostIngressEventPublisher', () => { + const logger = getVoidLogger(); + + it('should set up routes correctly', async () => { + const config = new ConfigReader({ + events: { + http: { + topics: ['testA'], + }, + }, + }); + + const router = Router(); + router.use(express.json()); + router.use(errorHandler()); + const app = express().use(router); + + const publisher = HttpPostIngressEventPublisher.fromConfig({ + config, + logger, + router, + ingresses: { + testB: {}, + }, + }); + + const eventBroker = new TestEventBroker(); + await publisher.setEventBroker(eventBroker); + + const notFoundResponse = await request(app) + .post('/unknown') + .timeout(100) + .send({ test: 'data' }); + expect(notFoundResponse.status).toBe(404); + + const response1 = await request(app) + .post('/testA') + .set('X-Custom-Header', 'test-value') + .timeout(100) + .send({ testA: 'data' }); + expect(response1.status).toBe(202); + + const response2 = await request(app) + .post('/testB') + .set('X-Custom-Header', 'test-value') + .timeout(100) + .send({ testB: 'data' }); + expect(response2.status).toBe(202); + + expect(eventBroker.published.length).toEqual(2); + expect(eventBroker.published[0].topic).toEqual('testA'); + expect(eventBroker.published[0].eventPayload).toEqual({ testA: 'data' }); + expect(eventBroker.published[0].metadata).toEqual( + expect.objectContaining({ + 'content-type': 'application/json', + 'x-custom-header': 'test-value', + }), + ); + expect(eventBroker.published[1].topic).toEqual('testB'); + expect(eventBroker.published[1].eventPayload).toEqual({ testB: 'data' }); + expect(eventBroker.published[1].metadata).toEqual( + expect.objectContaining({ + 'content-type': 'application/json', + 'x-custom-header': 'test-value', + }), + ); + }); + + it('with validator', async () => { + const config = new ConfigReader({ + events: { + http: { + topics: ['testA'], + }, + }, + }); + + const router = Router(); + router.use(express.json()); + router.use(errorHandler()); + const app = express().use(router); + + const publisher = HttpPostIngressEventPublisher.fromConfig({ + config, + logger, + router, + ingresses: { + testB: { + validator: async (req, context) => { + if (req.headers['x-test-signature'] === 'testB-signature') { + return; + } + + context.reject({ + status: 400, + payload: { + message: 'wrong signature', + }, + }); + }, + }, + testC: { + validator: async (req, context) => { + if (req.headers['x-test-signature'] === 'testC-signature') { + return; + } + + context.reject({ + status: 404, + // payload: {}, + }); + }, + }, + testD: { + validator: async (req, context) => { + if (req.headers['x-test-signature'] === 'testD-signature') { + return; + } + + context.reject({ + // status: 403, + // payload: {}, + }); + }, + }, + }, + }); + + const eventBroker = new TestEventBroker(); + await publisher.setEventBroker(eventBroker); + + const response1 = await request(app) + .post('/testA') + .timeout(100) + .send({ test: 'data' }); + expect(response1.status).toBe(202); + + const response2 = await request(app) + .post('/testB') + .timeout(100) + .send({ test: 'data' }); + expect(response2.status).toBe(400); + expect(response2.body).toEqual({ message: 'wrong signature' }); + + const response3 = await request(app) + .post('/testB') + .set('X-Test-Signature', 'wrong') + .timeout(100) + .send({ test: 'data' }); + expect(response3.status).toBe(400); + expect(response3.body).toEqual({ message: 'wrong signature' }); + + const response4 = await request(app) + .post('/testB') + .set('X-Test-Signature', 'testB-signature') + .timeout(100) + .send({ test: 'data' }); + expect(response4.status).toBe(202); + + const response5 = await request(app) + .post('/testC') + .timeout(100) + .send({ test: 'data' }); + expect(response5.status).toBe(404); + expect(response5.body).toEqual({}); + + const response6 = await request(app) + .post('/testD') + .timeout(100) + .send({ test: 'data' }); + expect(response6.status).toBe(403); + expect(response6.body).toEqual({}); + + expect(eventBroker.published.length).toEqual(2); + expect(eventBroker.published[0].topic).toEqual('testA'); + expect(eventBroker.published[0].eventPayload).toEqual({ test: 'data' }); + expect(eventBroker.published[1].topic).toEqual('testB'); + expect(eventBroker.published[1].eventPayload).toEqual({ test: 'data' }); + expect(eventBroker.published[1].metadata).toEqual( + expect.objectContaining({ + 'x-test-signature': 'testB-signature', + }), + ); + }); + + it('without configuration', async () => { + const config = new ConfigReader({}); + + const router = Router(); + router.use(express.json()); + router.use(errorHandler()); + + expect(() => + HttpPostIngressEventPublisher.fromConfig({ + config, + logger, + router, + }), + ).not.toThrow(); + }); +}); diff --git a/plugins/events-backend/src/service/http/HttpPostIngressEventPublisher.ts b/plugins/events-backend/src/service/http/HttpPostIngressEventPublisher.ts new file mode 100644 index 0000000000..64b7140b54 --- /dev/null +++ b/plugins/events-backend/src/service/http/HttpPostIngressEventPublisher.ts @@ -0,0 +1,118 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { errorHandler } from '@backstage/backend-common'; +import { Config } from '@backstage/config'; +import { + EventBroker, + EventPublisher, + HttpPostIngressOptions, + RequestValidator, +} from '@backstage/plugin-events-node'; +import express from 'express'; +import Router from 'express-promise-router'; +import { Logger } from 'winston'; +import { RequestValidationContextImpl } from './validation'; + +/** + * Publishes events received from their origin (e.g., webhook events from an SCM system) + * via HTTP POST endpoint and passes the request body as event payload to the registered subscribers. + * + * @public + */ +// TODO(pjungermann): add prom metrics? (see plugins/catalog-backend/src/util/metrics.ts, etc.) +export class HttpPostIngressEventPublisher implements EventPublisher { + private eventBroker?: EventBroker; + + static fromConfig(env: { + config: Config; + ingresses?: { [topic: string]: Omit }; + logger: Logger; + router: express.Router; + }): HttpPostIngressEventPublisher { + const topics = + env.config.getOptionalStringArray('events.http.topics') ?? []; + + const ingresses = env.ingresses ?? {}; + topics.forEach(topic => { + // don't overwrite topic settings + // (e.g., added at the config as well as argument) + if (!ingresses[topic]) { + ingresses[topic] = {}; + } + }); + + return new HttpPostIngressEventPublisher(env.logger, env.router, ingresses); + } + + private constructor( + private logger: Logger, + router: express.Router, + ingresses: { [topic: string]: Omit }, + ) { + router.use(this.createRouter(ingresses)); + } + + async setEventBroker(eventBroker: EventBroker): Promise { + this.eventBroker = eventBroker; + } + + private createRouter(ingresses: { + [topic: string]: Omit; + }): express.Router { + const router = Router(); + router.use(express.json()); + + Object.keys(ingresses).forEach(topic => + this.addRouteForTopic(router, topic, ingresses[topic].validator), + ); + + router.use(errorHandler()); + return router; + } + + private addRouteForTopic( + router: express.Router, + topic: string, + validator?: RequestValidator, + ): void { + const path = `/${topic}`; + + router.post(path, async (request, response) => { + const context = new RequestValidationContextImpl(); + await validator?.(request, context); + if (context.wasRejected()) { + response + .status(context.rejectionDetails!.status) + .json(context.rejectionDetails!.payload); + return; + } + + const eventPayload = request.body; + await this.eventBroker!.publish({ + topic, + eventPayload, + metadata: request.headers, + }); + + response.status(202).json({ status: 'accepted' }); + }); + + // TODO(pjungermann): We don't really know the externally defined path prefix here, + // however it is more useful for users to have it. Is there a better way? + this.logger.info(`Registered /api/events/http${path} to receive events`); + } +} diff --git a/plugins/events-backend/src/service/http/index.ts b/plugins/events-backend/src/service/http/index.ts new file mode 100644 index 0000000000..fe71e49dfa --- /dev/null +++ b/plugins/events-backend/src/service/http/index.ts @@ -0,0 +1,18 @@ +/* + * 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 { HttpPostIngressEventPublisher } from './HttpPostIngressEventPublisher'; +export * from './validation'; diff --git a/plugins/events-backend/src/service/http/validation/RequestValidationContextImpl.test.ts b/plugins/events-backend/src/service/http/validation/RequestValidationContextImpl.test.ts new file mode 100644 index 0000000000..b2f1485f65 --- /dev/null +++ b/plugins/events-backend/src/service/http/validation/RequestValidationContextImpl.test.ts @@ -0,0 +1,64 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { RequestValidationContextImpl } from './RequestValidationContextImpl'; + +describe('RequestValidationContextImpl', () => { + it('not rejected', () => { + const context = new RequestValidationContextImpl(); + + expect(context.wasRejected()).toBe(false); + expect(context.rejectionDetails).toBeUndefined(); + }); + + it('reject without details', () => { + const context = new RequestValidationContextImpl(); + + context.reject(); + + expect(context.wasRejected()).toBe(true); + expect(context.rejectionDetails).not.toBeUndefined(); + expect(context.rejectionDetails!.status).toBe(403); + expect(context.rejectionDetails!.payload).toEqual({}); + }); + + it('reject with partial details', () => { + const context = new RequestValidationContextImpl(); + + context.reject({ status: 404 }); + + expect(context.wasRejected()).toBe(true); + expect(context.rejectionDetails).not.toBeUndefined(); + expect(context.rejectionDetails!.status).toBe(404); + expect(context.rejectionDetails!.payload).toEqual({}); + }); + + it('reject with details', () => { + const context = new RequestValidationContextImpl(); + + context.reject({ + status: 403, + payload: { message: 'invalid signature' }, + }); + + expect(context.wasRejected()).toBe(true); + expect(context.rejectionDetails).not.toBeUndefined(); + expect(context.rejectionDetails!.status).toBe(403); + expect(context.rejectionDetails!.payload).toEqual({ + message: 'invalid signature', + }); + }); +}); diff --git a/plugins/events-backend/src/service/http/validation/RequestValidationContextImpl.ts b/plugins/events-backend/src/service/http/validation/RequestValidationContextImpl.ts new file mode 100644 index 0000000000..3dc607a683 --- /dev/null +++ b/plugins/events-backend/src/service/http/validation/RequestValidationContextImpl.ts @@ -0,0 +1,39 @@ +/* + * 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 { + RequestRejectionDetails, + RequestValidationContext, +} from '@backstage/plugin-events-node'; + +export class RequestValidationContextImpl implements RequestValidationContext { + #rejectionDetails: RequestRejectionDetails | undefined; + + reject(details?: Partial): void { + this.#rejectionDetails = { + status: details?.status ?? 403, + payload: details?.payload ?? {}, + }; + } + + wasRejected(): boolean { + return this.#rejectionDetails !== undefined; + } + + get rejectionDetails() { + return this.#rejectionDetails; + } +} diff --git a/plugins/events-backend/src/service/http/validation/index.ts b/plugins/events-backend/src/service/http/validation/index.ts new file mode 100644 index 0000000000..7513014906 --- /dev/null +++ b/plugins/events-backend/src/service/http/validation/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { RequestValidationContextImpl } from './RequestValidationContextImpl'; diff --git a/plugins/events-backend/src/setupTests.ts b/plugins/events-backend/src/setupTests.ts new file mode 100644 index 0000000000..d3232290a7 --- /dev/null +++ b/plugins/events-backend/src/setupTests.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export {}; diff --git a/plugins/events-node/.eslintrc.js b/plugins/events-node/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/events-node/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/events-node/README.md b/plugins/events-node/README.md new file mode 100644 index 0000000000..44738222bc --- /dev/null +++ b/plugins/events-node/README.md @@ -0,0 +1,3 @@ +# plugin-events-node + +Houses types and utilities for building events-related modules. diff --git a/plugins/events-node/api-report.md b/plugins/events-node/api-report.md new file mode 100644 index 0000000000..1054211cbc --- /dev/null +++ b/plugins/events-node/api-report.md @@ -0,0 +1,106 @@ +## API Report File for "@backstage/plugin-events-node" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { ExtensionPoint } from '@backstage/backend-plugin-api'; +import { Request as Request_2 } from 'express'; + +// @public +export interface EventBroker { + publish(params: EventParams): Promise; + subscribe( + ...subscribers: Array> + ): void; +} + +// @public (undocumented) +export interface EventParams { + eventPayload: unknown; + metadata?: Record; + topic: string; +} + +// @public +export interface EventPublisher { + // (undocumented) + setEventBroker(eventBroker: EventBroker): Promise; +} + +// @public +export abstract class EventRouter implements EventPublisher, EventSubscriber { + // (undocumented) + protected abstract determineDestinationTopic( + params: EventParams, + ): string | undefined; + // (undocumented) + onEvent(params: EventParams): Promise; + // (undocumented) + setEventBroker(eventBroker: EventBroker): Promise; + // (undocumented) + abstract supportsEventTopics(): string[]; +} + +// @alpha (undocumented) +export interface EventsExtensionPoint { + // (undocumented) + addHttpPostIngress(options: HttpPostIngressOptions): void; + // (undocumented) + addPublishers( + ...publishers: Array> + ): void; + // (undocumented) + addSubscribers( + ...subscribers: Array> + ): void; + // (undocumented) + setEventBroker(eventBroker: EventBroker): void; +} + +// @alpha (undocumented) +export const eventsExtensionPoint: ExtensionPoint; + +// @public +export interface EventSubscriber { + onEvent(params: EventParams): Promise; + supportsEventTopics(): string[]; +} + +// @public (undocumented) +export interface HttpPostIngressOptions { + // (undocumented) + topic: string; + // (undocumented) + validator?: RequestValidator; +} + +// @public +export interface RequestRejectionDetails { + // (undocumented) + payload: unknown; + // (undocumented) + status: number; +} + +// @public +export interface RequestValidationContext { + reject(details?: Partial): void; +} + +// @public +export type RequestValidator = ( + request: Request_2, + context: RequestValidationContext, +) => Promise; + +// @public +export abstract class SubTopicEventRouter extends EventRouter { + protected constructor(topic: string); + // (undocumented) + protected determineDestinationTopic(params: EventParams): string | undefined; + // (undocumented) + protected abstract determineSubTopic(params: EventParams): string | undefined; + // (undocumented) + supportsEventTopics(): string[]; +} +``` diff --git a/plugins/events-node/package.json b/plugins/events-node/package.json new file mode 100644 index 0000000000..317af49c5c --- /dev/null +++ b/plugins/events-node/package.json @@ -0,0 +1,38 @@ +{ + "name": "@backstage/plugin-events-node", + "description": "The plugin-events-node module for @backstage/plugin-events-backend", + "version": "0.0.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "alphaTypes": "dist/index.alpha.d.ts", + "main": "dist/index.cjs.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "node-library" + }, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build --experimental-type-build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "dependencies": { + "@backstage/backend-plugin-api": "workspace:^", + "@types/express": "^4.17.6", + "express": "^4.17.1" + }, + "devDependencies": { + "@backstage/cli": "workspace:^" + }, + "files": [ + "alpha", + "dist" + ] +} diff --git a/plugins/events-node/src/api/EventBroker.ts b/plugins/events-node/src/api/EventBroker.ts new file mode 100644 index 0000000000..736c2a2bf0 --- /dev/null +++ b/plugins/events-node/src/api/EventBroker.ts @@ -0,0 +1,43 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { EventParams } from './EventParams'; +import { EventSubscriber } from './EventSubscriber'; + +/** + * Allows a decoupled and asynchronous communication between components. + * Components can publish events for a given topic and + * others can subscribe for future events for topics they are interested in. + * + * @public + */ +export interface EventBroker { + /** + * Publishes an event for the topic. + * + * @param params - parameters for the to be published event. + */ + publish(params: EventParams): Promise; + + /** + * Adds new subscribers for {@link EventSubscriber#supportsEventTopics | interested topics}. + * + * @param subscribers - interested in events of specified topics. + */ + subscribe( + ...subscribers: Array> + ): void; +} diff --git a/plugins/events-node/src/api/EventParams.ts b/plugins/events-node/src/api/EventParams.ts new file mode 100644 index 0000000000..6912827281 --- /dev/null +++ b/plugins/events-node/src/api/EventParams.ts @@ -0,0 +1,33 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @public + */ +export interface EventParams { + /** + * Topic for which this event should be published. + */ + topic: string; + /** + * Event payload. + */ + eventPayload: unknown; + /** + * Metadata (e.g., HTTP headers and similar for events received from external). + */ + metadata?: Record; +} diff --git a/plugins/events-node/src/api/EventPublisher.ts b/plugins/events-node/src/api/EventPublisher.ts new file mode 100644 index 0000000000..285f427804 --- /dev/null +++ b/plugins/events-node/src/api/EventPublisher.ts @@ -0,0 +1,29 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { EventBroker } from './EventBroker'; + +/** + * Publishes events to be consumed by subscribers for their topic. + * The events can come from different (external) sources + * like emitted themselves, received via HTTP endpoint (i.e. webhook) + * or from event brokers, queues, etc. + * + * @public + */ +export interface EventPublisher { + setEventBroker(eventBroker: EventBroker): Promise; +} diff --git a/plugins/events-node/src/api/EventRouter.test.ts b/plugins/events-node/src/api/EventRouter.test.ts new file mode 100644 index 0000000000..551c5ea67d --- /dev/null +++ b/plugins/events-node/src/api/EventRouter.test.ts @@ -0,0 +1,81 @@ +/* + * 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 { EventBroker } from './EventBroker'; +import { EventParams } from './EventParams'; +import { EventRouter } from './EventRouter'; + +class TestEventRouter extends EventRouter { + protected determineDestinationTopic(params: EventParams): string | undefined { + const payload = params.eventPayload as { value?: number }; + if (payload.value === undefined) { + return undefined; + } + + return payload.value % 2 === 0 ? 'even' : 'odd'; + } + + supportsEventTopics(): string[] { + return ['my-topic']; + } +} + +describe('EventRouter', () => { + const eventRouter = new TestEventRouter(); + const topic = 'my-topic'; + const metadata = { random: 'metadata' }; + + it('no destination topic', async () => { + const published: EventParams[] = []; + const eventBroker = { + publish: (params: EventParams) => { + published.push(params); + }, + } as EventBroker; + await eventRouter.setEventBroker(eventBroker); + + await eventRouter.onEvent({ + topic, + eventPayload: { discarded: 'event' }, + metadata, + }); + + expect(published).toEqual([]); + }); + + it('with destination topic', async () => { + const published: EventParams[] = []; + const eventBroker = { + publish: (params: EventParams) => { + published.push(params); + }, + } as EventBroker; + await eventRouter.setEventBroker(eventBroker); + + const payloadEven = { value: 2 }; + const payloadOdd = { value: 3 }; + await eventRouter.onEvent({ topic, eventPayload: payloadEven, metadata }); + await eventRouter.onEvent({ topic, eventPayload: payloadOdd, metadata }); + + expect(published.length).toBe(2); + expect(published[0].topic).toEqual('even'); + expect(published[0].eventPayload).toEqual(payloadEven); + expect(published[0].metadata).toEqual(metadata); + expect(published[1].topic).toEqual('odd'); + expect(published[1].eventPayload).toEqual(payloadOdd); + expect(published[1].metadata).toEqual(metadata); + }); +}); diff --git a/plugins/events-node/src/api/EventRouter.ts b/plugins/events-node/src/api/EventRouter.ts new file mode 100644 index 0000000000..b435ef15f4 --- /dev/null +++ b/plugins/events-node/src/api/EventRouter.ts @@ -0,0 +1,55 @@ +/* + * 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 { EventBroker } from './EventBroker'; +import { EventParams } from './EventParams'; +import { EventPublisher } from './EventPublisher'; +import { EventSubscriber } from './EventSubscriber'; + +/** + * Subscribes to a topic and - depending on a set of conditions - + * republishes the event to another topic. + * + * @see {@link https://www.enterpriseintegrationpatterns.com/MessageRouter.html | Message Router pattern}. + * @public + */ +export abstract class EventRouter implements EventPublisher, EventSubscriber { + private eventBroker?: EventBroker; + + protected abstract determineDestinationTopic( + params: EventParams, + ): string | undefined; + + async onEvent(params: EventParams): Promise { + const topic = this.determineDestinationTopic(params); + + if (!topic) { + return; + } + + // republish to different topic + this.eventBroker?.publish({ + ...params, + topic, + }); + } + + async setEventBroker(eventBroker: EventBroker): Promise { + this.eventBroker = eventBroker; + } + + abstract supportsEventTopics(): string[]; +} diff --git a/plugins/events-node/src/api/EventSubscriber.ts b/plugins/events-node/src/api/EventSubscriber.ts new file mode 100644 index 0000000000..439f49b890 --- /dev/null +++ b/plugins/events-node/src/api/EventSubscriber.ts @@ -0,0 +1,38 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { EventParams } from './EventParams'; + +/** + * Handles received events. + * This may include triggering refreshes of catalog entities + * or other actions to react on events. + * + * @public + */ +export interface EventSubscriber { + /** + * Supported event topics like "github", "bitbucketCloud", etc. + */ + supportsEventTopics(): string[]; + + /** + * React on a received event. + * + * @param params - parameters for the to be received event. + */ + onEvent(params: EventParams): Promise; +} diff --git a/plugins/events-node/src/api/SubTopicEventRouter.test.ts b/plugins/events-node/src/api/SubTopicEventRouter.test.ts new file mode 100644 index 0000000000..d5c79895a5 --- /dev/null +++ b/plugins/events-node/src/api/SubTopicEventRouter.test.ts @@ -0,0 +1,67 @@ +/* + * 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 { EventBroker } from './EventBroker'; +import { EventParams } from './EventParams'; +import { SubTopicEventRouter } from './SubTopicEventRouter'; + +class TestSubTopicEventRouter extends SubTopicEventRouter { + constructor() { + super('my-topic'); + } + + protected determineSubTopic(params: EventParams): string | undefined { + return params.metadata?.['x-my-event'] as string | undefined; + } +} + +describe('SubTopicEventRouter', () => { + const eventRouter = new TestSubTopicEventRouter(); + const topic = 'my-topic'; + const eventPayload = { test: 'payload' }; + const metadata = { 'x-my-event': 'test.type' }; + + it('no x-my-event', async () => { + const published: EventParams[] = []; + const eventBroker = { + publish: (params: EventParams) => { + published.push(params); + }, + } as EventBroker; + await eventRouter.setEventBroker(eventBroker); + + await eventRouter.onEvent({ topic, eventPayload }); + + expect(published).toEqual([]); + }); + + it('with x-my-event', async () => { + const published: EventParams[] = []; + const eventBroker = { + publish: (params: EventParams) => { + published.push(params); + }, + } as EventBroker; + await eventRouter.setEventBroker(eventBroker); + + await eventRouter.onEvent({ topic, eventPayload, metadata }); + + expect(published.length).toBe(1); + expect(published[0].topic).toEqual('my-topic.test.type'); + expect(published[0].eventPayload).toEqual(eventPayload); + expect(published[0].metadata).toEqual(metadata); + }); +}); diff --git a/plugins/events-node/src/api/SubTopicEventRouter.ts b/plugins/events-node/src/api/SubTopicEventRouter.ts new file mode 100644 index 0000000000..04abe14009 --- /dev/null +++ b/plugins/events-node/src/api/SubTopicEventRouter.ts @@ -0,0 +1,44 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { EventParams } from './EventParams'; +import { EventRouter } from './EventRouter'; + +/** + * Subscribes to the provided (generic) topic + * and publishes the events under the more concrete sub-topic + * depending on the implemented logic for determining it. + * Implementing classes might use information from `metadata` + * and/or properties within the payload. + * + * @public + */ +export abstract class SubTopicEventRouter extends EventRouter { + protected constructor(private readonly topic: string) { + super(); + } + + protected abstract determineSubTopic(params: EventParams): string | undefined; + + protected determineDestinationTopic(params: EventParams): string | undefined { + const subTopic = this.determineSubTopic(params); + return subTopic ? `${params.topic}.${subTopic}` : undefined; + } + + supportsEventTopics(): string[] { + return [this.topic]; + } +} diff --git a/plugins/events-node/src/api/http/HttpPostIngressOptions.ts b/plugins/events-node/src/api/http/HttpPostIngressOptions.ts new file mode 100644 index 0000000000..d9f005d84d --- /dev/null +++ b/plugins/events-node/src/api/http/HttpPostIngressOptions.ts @@ -0,0 +1,25 @@ +/* + * 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 { RequestValidator } from './validation'; + +/** + * @public + */ +export interface HttpPostIngressOptions { + topic: string; + validator?: RequestValidator; +} diff --git a/plugins/events-node/src/api/http/index.ts b/plugins/events-node/src/api/http/index.ts new file mode 100644 index 0000000000..9206819a4a --- /dev/null +++ b/plugins/events-node/src/api/http/index.ts @@ -0,0 +1,18 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export type { HttpPostIngressOptions } from './HttpPostIngressOptions'; +export * from './validation'; diff --git a/plugins/events-node/src/api/http/validation/RequestRejectionDetails.ts b/plugins/events-node/src/api/http/validation/RequestRejectionDetails.ts new file mode 100644 index 0000000000..1eca094367 --- /dev/null +++ b/plugins/events-node/src/api/http/validation/RequestRejectionDetails.ts @@ -0,0 +1,26 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Details for how to respond to the rejection + * of the received HTTP request transmitting an event payload. + * + * @public + */ +export interface RequestRejectionDetails { + status: number; + payload: unknown; +} diff --git a/plugins/events-node/src/api/http/validation/RequestValidationContext.ts b/plugins/events-node/src/api/http/validation/RequestValidationContext.ts new file mode 100644 index 0000000000..eedb6f1f96 --- /dev/null +++ b/plugins/events-node/src/api/http/validation/RequestValidationContext.ts @@ -0,0 +1,32 @@ +/* + * 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 { RequestRejectionDetails } from './RequestRejectionDetails'; + +/** + * Passed context for the validation + * at which rejections can be expressed. + * + * @public + */ +export interface RequestValidationContext { + /** + * Rejects the validated request + * + * @param details - Optional details about the rejection which will be provided to the sender. + */ + reject(details?: Partial): void; +} diff --git a/plugins/events-node/src/api/http/validation/RequestValidator.ts b/plugins/events-node/src/api/http/validation/RequestValidator.ts new file mode 100644 index 0000000000..b419b855cf --- /dev/null +++ b/plugins/events-node/src/api/http/validation/RequestValidator.ts @@ -0,0 +1,34 @@ +/* + * 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 { Request } from 'express'; +import { RequestValidationContext } from './RequestValidationContext'; + +/** + * Validator used to check the received HTTP request + * transmitting an event payload. + * + * E.g., it can be used for signature verification like + * for GitHub webhook events + * (https://docs.github.com/en/developers/webhooks-and-events/webhooks/creating-webhooks#secret) + * or other kinds of checks. + * + * @public + */ +export type RequestValidator = ( + request: Request, + context: RequestValidationContext, +) => Promise; diff --git a/plugins/events-node/src/api/http/validation/index.ts b/plugins/events-node/src/api/http/validation/index.ts new file mode 100644 index 0000000000..95f2d474eb --- /dev/null +++ b/plugins/events-node/src/api/http/validation/index.ts @@ -0,0 +1,19 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export type { RequestRejectionDetails } from './RequestRejectionDetails'; +export type { RequestValidationContext } from './RequestValidationContext'; +export type { RequestValidator } from './RequestValidator'; diff --git a/plugins/events-node/src/api/index.ts b/plugins/events-node/src/api/index.ts new file mode 100644 index 0000000000..91711c0e38 --- /dev/null +++ b/plugins/events-node/src/api/index.ts @@ -0,0 +1,23 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export type { EventBroker } from './EventBroker'; +export type { EventParams } from './EventParams'; +export type { EventPublisher } from './EventPublisher'; +export { EventRouter } from './EventRouter'; +export type { EventSubscriber } from './EventSubscriber'; +export * from './http'; +export { SubTopicEventRouter } from './SubTopicEventRouter'; diff --git a/plugins/events-node/src/extensions.ts b/plugins/events-node/src/extensions.ts new file mode 100644 index 0000000000..945d86b49c --- /dev/null +++ b/plugins/events-node/src/extensions.ts @@ -0,0 +1,47 @@ +/* + * 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 { createExtensionPoint } from '@backstage/backend-plugin-api'; +import { + EventBroker, + EventPublisher, + EventSubscriber, + HttpPostIngressOptions, +} from './api'; + +/** + * @alpha + */ +export interface EventsExtensionPoint { + setEventBroker(eventBroker: EventBroker): void; + + addPublishers( + ...publishers: Array> + ): void; + + addSubscribers( + ...subscribers: Array> + ): void; + + addHttpPostIngress(options: HttpPostIngressOptions): void; +} + +/** + * @alpha + */ +export const eventsExtensionPoint = createExtensionPoint({ + id: 'events', +}); diff --git a/plugins/events-node/src/index.ts b/plugins/events-node/src/index.ts new file mode 100644 index 0000000000..422eeb169e --- /dev/null +++ b/plugins/events-node/src/index.ts @@ -0,0 +1,25 @@ +/* + * 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. + */ + +/** + * The events-node module for `@backstage/plugin-events-backend`. + * + * @packageDocumentation + */ + +export * from './api'; +export type { EventsExtensionPoint } from './extensions'; +export { eventsExtensionPoint } from './extensions'; diff --git a/plugins/events-node/src/setupTests.ts b/plugins/events-node/src/setupTests.ts new file mode 100644 index 0000000000..d3232290a7 --- /dev/null +++ b/plugins/events-node/src/setupTests.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export {}; diff --git a/plugins/example-todo-list-backend/CHANGELOG.md b/plugins/example-todo-list-backend/CHANGELOG.md index df0c013892..90893229c8 100644 --- a/plugins/example-todo-list-backend/CHANGELOG.md +++ b/plugins/example-todo-list-backend/CHANGELOG.md @@ -1,5 +1,15 @@ # @internal/plugin-todo-list-backend +## 1.0.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + ## 1.0.7-next.0 ### Patch Changes diff --git a/plugins/example-todo-list-backend/package.json b/plugins/example-todo-list-backend/package.json index 9d6419a76d..152404f292 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.7-next.0", + "version": "1.0.7-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -38,7 +38,7 @@ "@backstage/cli": "workspace:^", "@types/supertest": "^2.0.8", "@types/uuid": "^8.0.0", - "msw": "^0.47.0", + "msw": "^0.48.0", "supertest": "^6.1.6" }, "files": [ diff --git a/plugins/example-todo-list-common/package.json b/plugins/example-todo-list-common/package.json index 23a16e10c7..87e759177c 100644 --- a/plugins/example-todo-list-common/package.json +++ b/plugins/example-todo-list-common/package.json @@ -32,7 +32,7 @@ "@backstage/test-utils": "workspace:^", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/example-todo-list/CHANGELOG.md b/plugins/example-todo-list/CHANGELOG.md index f08094181d..3a692cede5 100644 --- a/plugins/example-todo-list/CHANGELOG.md +++ b/plugins/example-todo-list/CHANGELOG.md @@ -1,5 +1,14 @@ # @internal/plugin-todo-list +## 1.0.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + ## 1.0.7-next.0 ### Patch Changes diff --git a/plugins/example-todo-list/package.json b/plugins/example-todo-list/package.json index 0b12ae6208..df25b76395 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.7-next.0", + "version": "1.0.7-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -43,7 +43,7 @@ "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/explore-react/package.json b/plugins/explore-react/package.json index 27ee4c23df..b029d2bf9b 100644 --- a/plugins/explore-react/package.json +++ b/plugins/explore-react/package.json @@ -43,7 +43,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/explore/CHANGELOG.md b/plugins/explore/CHANGELOG.md index bc31cd1ec6..56a41c0e6a 100644 --- a/plugins/explore/CHANGELOG.md +++ b/plugins/explore/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-explore +## 0.3.42-next.1 + +### Patch Changes + +- 5c25ce6d9e: Added a section to explore plugin README that describes the customization of explore tools content. +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + - @backstage/plugin-explore-react@0.0.23-next.0 + ## 0.3.42-next.0 ### Patch Changes diff --git a/plugins/explore/package.json b/plugins/explore/package.json index 7ff382b9ce..61a58c6d45 100644 --- a/plugins/explore/package.json +++ b/plugins/explore/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-explore", "description": "A Backstage plugin for building an exploration page of your software ecosystem", - "version": "0.3.42-next.0", + "version": "0.3.42-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -61,7 +61,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/firehydrant/CHANGELOG.md b/plugins/firehydrant/CHANGELOG.md index cd01270cbe..f9c72f56e7 100644 --- a/plugins/firehydrant/CHANGELOG.md +++ b/plugins/firehydrant/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-firehydrant +## 0.1.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.1.28-next.0 ### Patch Changes diff --git a/plugins/firehydrant/package.json b/plugins/firehydrant/package.json index 2c455fbd82..e1ffe6c3d8 100644 --- a/plugins/firehydrant/package.json +++ b/plugins/firehydrant/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-firehydrant", "description": "A Backstage plugin that integrates towards FireHydrant", - "version": "0.1.28-next.0", + "version": "0.1.28-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -46,7 +46,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/fossa/CHANGELOG.md b/plugins/fossa/CHANGELOG.md index bd43f4d7b8..b425da715a 100644 --- a/plugins/fossa/CHANGELOG.md +++ b/plugins/fossa/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-fossa +## 0.2.43-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.2.43-next.0 ### Patch Changes diff --git a/plugins/fossa/package.json b/plugins/fossa/package.json index 32d9da5146..17f1b3c2a5 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.43-next.0", + "version": "0.2.43-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -59,7 +59,7 @@ "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist", diff --git a/plugins/gcalendar/CHANGELOG.md b/plugins/gcalendar/CHANGELOG.md index 3e4cc2473c..cb9a289a56 100644 --- a/plugins/gcalendar/CHANGELOG.md +++ b/plugins/gcalendar/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-gcalendar +## 0.3.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + ## 0.3.7-next.0 ### Patch Changes diff --git a/plugins/gcalendar/package.json b/plugins/gcalendar/package.json index c6f748c6a2..15cfdc0dba 100644 --- a/plugins/gcalendar/package.json +++ b/plugins/gcalendar/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-gcalendar", - "version": "0.3.7-next.0", + "version": "0.3.7-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -54,7 +54,7 @@ "@types/node": "^16.11.26", "@types/sanitize-html": "^2.6.2", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/gcp-projects/CHANGELOG.md b/plugins/gcp-projects/CHANGELOG.md index 3e4f8df529..3046eccda2 100644 --- a/plugins/gcp-projects/CHANGELOG.md +++ b/plugins/gcp-projects/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-gcp-projects +## 0.3.30-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + ## 0.3.30-next.0 ### Patch Changes diff --git a/plugins/gcp-projects/package.json b/plugins/gcp-projects/package.json index 6b1ea7a0d4..74e7bc332c 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.30-next.0", + "version": "0.3.30-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -55,7 +55,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/git-release-manager/CHANGELOG.md b/plugins/git-release-manager/CHANGELOG.md index 00b079b7cd..1ffb9f6b3a 100644 --- a/plugins/git-release-manager/CHANGELOG.md +++ b/plugins/git-release-manager/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-git-release-manager +## 0.3.24-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/theme@0.2.16 + ## 0.3.24-next.0 ### Patch Changes diff --git a/plugins/git-release-manager/package.json b/plugins/git-release-manager/package.json index 9b3533d994..3253629b04 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.24-next.0", + "version": "0.3.24-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -53,7 +53,7 @@ "@types/node": "^16.11.26", "@types/recharts": "^1.8.15", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/github-actions/CHANGELOG.md b/plugins/github-actions/CHANGELOG.md index b3570d20cf..9bbe18ff4d 100644 --- a/plugins/github-actions/CHANGELOG.md +++ b/plugins/github-actions/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-github-actions +## 0.5.11-next.1 + +### Patch Changes + +- ed438a3ba5: Add error panel when the plugin fails. +- 0d6837ca4e: Fix wrong GitHub callback URL documentation +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.5.11-next.0 ### Patch Changes diff --git a/plugins/github-actions/package.json b/plugins/github-actions/package.json index 8247c48fa5..f8081bae08 100644 --- a/plugins/github-actions/package.json +++ b/plugins/github-actions/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-github-actions", "description": "A Backstage plugin that integrates towards GitHub Actions", - "version": "0.5.11-next.0", + "version": "0.5.11-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -62,7 +62,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/github-deployments/CHANGELOG.md b/plugins/github-deployments/CHANGELOG.md index 0a9a4215df..e29edb4604 100644 --- a/plugins/github-deployments/CHANGELOG.md +++ b/plugins/github-deployments/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-github-deployments +## 0.1.42-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/integration-react@1.1.6-next.1 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.1.42-next.0 ### Patch Changes diff --git a/plugins/github-deployments/package.json b/plugins/github-deployments/package.json index a25fab05db..534804cf50 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.42-next.0", + "version": "0.1.42-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -51,7 +51,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/github-issues/CHANGELOG.md b/plugins/github-issues/CHANGELOG.md index a812495a5f..a1d5aeb0c6 100644 --- a/plugins/github-issues/CHANGELOG.md +++ b/plugins/github-issues/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-github-issues +## 0.2.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.2.0-next.0 ### Minor Changes diff --git a/plugins/github-issues/package.json b/plugins/github-issues/package.json index 3853e845a6..122e0e7709 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.0-next.0", + "version": "0.2.0-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -51,7 +51,7 @@ "@types/node": "*", "@types/react": "^16.13.1 || ^17.0.0", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/github-pull-requests-board/CHANGELOG.md b/plugins/github-pull-requests-board/CHANGELOG.md index a91ceae5f0..150a4c2ffb 100644 --- a/plugins/github-pull-requests-board/CHANGELOG.md +++ b/plugins/github-pull-requests-board/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-github-pull-requests-board +## 0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.1.5-next.0 ### Patch Changes diff --git a/plugins/github-pull-requests-board/package.json b/plugins/github-pull-requests-board/package.json index c6f58ebf0f..e551b12fa2 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.5-next.0", + "version": "0.1.5-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -58,7 +58,7 @@ "@types/node": "^16.11.26", "@types/react": "^16.13.1 || ^17.0.0", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "peerDependencies": { "react": "^16.13.1 || ^17.0.0", diff --git a/plugins/gitops-profiles/CHANGELOG.md b/plugins/gitops-profiles/CHANGELOG.md index a578fe2077..ec3771c87f 100644 --- a/plugins/gitops-profiles/CHANGELOG.md +++ b/plugins/gitops-profiles/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-gitops-profiles +## 0.3.29-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + ## 0.3.29-next.0 ### Patch Changes diff --git a/plugins/gitops-profiles/package.json b/plugins/gitops-profiles/package.json index 000f1c4b6c..f5b6f5cc40 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.29-next.0", + "version": "0.3.29-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -55,7 +55,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/gocd/CHANGELOG.md b/plugins/gocd/CHANGELOG.md index 4409bc5861..6fb6bee3c1 100644 --- a/plugins/gocd/CHANGELOG.md +++ b/plugins/gocd/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-gocd +## 0.1.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.1.17-next.0 ### Patch Changes diff --git a/plugins/gocd/package.json b/plugins/gocd/package.json index e8ba4b9374..f8128f0e93 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.17-next.0", + "version": "0.1.17-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -58,7 +58,7 @@ "@types/luxon": "^3.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist", diff --git a/plugins/graphiql/CHANGELOG.md b/plugins/graphiql/CHANGELOG.md index 912c4e972b..3dbf192aff 100644 --- a/plugins/graphiql/CHANGELOG.md +++ b/plugins/graphiql/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-graphiql +## 0.2.43-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + ## 0.2.43-next.0 ### Patch Changes diff --git a/plugins/graphiql/package.json b/plugins/graphiql/package.json index 6f10a179a7..8bcc6ea95c 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.43-next.0", + "version": "0.2.43-next.1", "publishConfig": { "access": "public", "main": "dist/index.esm.js", @@ -58,7 +58,7 @@ "@types/codemirror": "^5.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/graphql-backend/CHANGELOG.md b/plugins/graphql-backend/CHANGELOG.md index 2fa54c680f..ed7bc2dbcf 100644 --- a/plugins/graphql-backend/CHANGELOG.md +++ b/plugins/graphql-backend/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-graphql-backend +## 0.1.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/plugin-catalog-graphql@0.3.15-next.0 + ## 0.1.28-next.0 ### Patch Changes diff --git a/plugins/graphql-backend/package.json b/plugins/graphql-backend/package.json index 70c8fb0c6f..c6c2d3559e 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.28-next.0", + "version": "0.1.28-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -52,7 +52,7 @@ "devDependencies": { "@backstage/cli": "workspace:^", "@types/supertest": "^2.0.8", - "msw": "^0.47.0", + "msw": "^0.48.0", "supertest": "^6.1.3" }, "files": [ diff --git a/plugins/home/CHANGELOG.md b/plugins/home/CHANGELOG.md index b9c43b0af8..4e9dfbe22d 100644 --- a/plugins/home/CHANGELOG.md +++ b/plugins/home/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-home +## 0.4.27-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + - @backstage/plugin-stack-overflow@0.1.7-next.1 + ## 0.4.27-next.0 ### Patch Changes diff --git a/plugins/home/package.json b/plugins/home/package.json index 8c267f4d25..6048316f6b 100644 --- a/plugins/home/package.json +++ b/plugins/home/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-home", "description": "A Backstage plugin that helps you build a home page", - "version": "0.4.27-next.0", + "version": "0.4.27-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -61,7 +61,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/ilert/CHANGELOG.md b/plugins/ilert/CHANGELOG.md index d1810178cc..796b375801 100644 --- a/plugins/ilert/CHANGELOG.md +++ b/plugins/ilert/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-ilert +## 0.2.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.2.0-next.0 ### Minor Changes diff --git a/plugins/ilert/package.json b/plugins/ilert/package.json index 5399a19bd7..0f5c8faa62 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.0-next.0", + "version": "0.2.0-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -51,7 +51,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist", diff --git a/plugins/jenkins-backend/CHANGELOG.md b/plugins/jenkins-backend/CHANGELOG.md index 54573cdaec..593c9d5b97 100644 --- a/plugins/jenkins-backend/CHANGELOG.md +++ b/plugins/jenkins-backend/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-jenkins-backend +## 0.1.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/plugin-jenkins-common@0.1.10-next.0 + - @backstage/plugin-permission-common@0.7.1-next.0 + ## 0.1.28-next.0 ### Patch Changes diff --git a/plugins/jenkins-backend/package.json b/plugins/jenkins-backend/package.json index 3a7a930f95..f9ce0826a0 100644 --- a/plugins/jenkins-backend/package.json +++ b/plugins/jenkins-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-jenkins-backend", "description": "A Backstage backend plugin that integrates towards Jenkins", - "version": "0.1.28-next.0", + "version": "0.1.28-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -44,7 +44,7 @@ "@backstage/cli": "workspace:^", "@types/jenkins": "^0.23.1", "@types/supertest": "^2.0.8", - "msw": "^0.47.0", + "msw": "^0.48.0", "supertest": "^6.1.6" }, "files": [ diff --git a/plugins/jenkins/CHANGELOG.md b/plugins/jenkins/CHANGELOG.md index 2a15d2917a..5c39dcadb2 100644 --- a/plugins/jenkins/CHANGELOG.md +++ b/plugins/jenkins/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-jenkins +## 0.7.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + - @backstage/plugin-jenkins-common@0.1.10-next.0 + ## 0.7.10-next.0 ### Patch Changes diff --git a/plugins/jenkins/package.json b/plugins/jenkins/package.json index a77f3d2439..3068f794be 100644 --- a/plugins/jenkins/package.json +++ b/plugins/jenkins/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-jenkins", "description": "A Backstage plugin that integrates towards Jenkins", - "version": "0.7.10-next.0", + "version": "0.7.10-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -62,7 +62,7 @@ "@types/node": "^16.11.26", "@types/testing-library__jest-dom": "^5.9.1", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/kafka-backend/CHANGELOG.md b/plugins/kafka-backend/CHANGELOG.md index 5999228785..bd93e4eccb 100644 --- a/plugins/kafka-backend/CHANGELOG.md +++ b/plugins/kafka-backend/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-kafka-backend +## 0.2.31-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + ## 0.2.31-next.0 ### Patch Changes diff --git a/plugins/kafka-backend/package.json b/plugins/kafka-backend/package.json index 096170dc7e..ec377ee5a9 100644 --- a/plugins/kafka-backend/package.json +++ b/plugins/kafka-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kafka-backend", "description": "A Backstage backend plugin that integrates towards Kafka", - "version": "0.2.31-next.0", + "version": "0.2.31-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 ec8563d64b..2cb4cb5a64 100644 --- a/plugins/kafka/CHANGELOG.md +++ b/plugins/kafka/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-kafka +## 0.3.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.3.11-next.0 ### Patch Changes diff --git a/plugins/kafka/package.json b/plugins/kafka/package.json index 0bcb7dfa24..b4c2276301 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.11-next.0", + "version": "0.3.11-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -51,7 +51,7 @@ "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", "jest-when": "^3.1.0", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist", diff --git a/plugins/kubernetes-backend/CHANGELOG.md b/plugins/kubernetes-backend/CHANGELOG.md index 804112324d..6420598fa5 100644 --- a/plugins/kubernetes-backend/CHANGELOG.md +++ b/plugins/kubernetes-backend/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-kubernetes-backend +## 0.8.0-next.1 + +### Patch Changes + +- cfb30b700c: Pin `@kubernetes/client-node` version to `0.17.0`. +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-kubernetes-common@0.4.4-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + ## 0.8.0-next.0 ### Minor Changes diff --git a/plugins/kubernetes-backend/package.json b/plugins/kubernetes-backend/package.json index ea6a1146a8..60112c41d1 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.8.0-next.0", + "version": "0.8.0-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/kubernetes-common/CHANGELOG.md b/plugins/kubernetes-common/CHANGELOG.md index b85e3c00ee..3cacfd6037 100644 --- a/plugins/kubernetes-common/CHANGELOG.md +++ b/plugins/kubernetes-common/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-kubernetes-common +## 0.4.4-next.1 + +### Patch Changes + +- cfb30b700c: Pin `@kubernetes/client-node` version to `0.17.0`. +- Updated dependencies + - @backstage/catalog-model@1.1.3-next.0 + ## 0.4.4-next.0 ### Patch Changes diff --git a/plugins/kubernetes-common/package.json b/plugins/kubernetes-common/package.json index 401341a0e8..627d642dde 100644 --- a/plugins/kubernetes-common/package.json +++ b/plugins/kubernetes-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kubernetes-common", "description": "Common functionalities for kubernetes, to be shared between kubernetes and kubernetes-backend plugin", - "version": "0.4.4-next.0", + "version": "0.4.4-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/kubernetes/CHANGELOG.md b/plugins/kubernetes/CHANGELOG.md index 2272804b22..f07b0d942c 100644 --- a/plugins/kubernetes/CHANGELOG.md +++ b/plugins/kubernetes/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-kubernetes +## 0.7.4-next.1 + +### Patch Changes + +- cfb30b700c: Pin `@kubernetes/client-node` version to `0.17.0`. +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/plugin-kubernetes-common@0.4.4-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.7.4-next.0 ### Patch Changes diff --git a/plugins/kubernetes/package.json b/plugins/kubernetes/package.json index 0bed1a213b..e1e2c783fe 100644 --- a/plugins/kubernetes/package.json +++ b/plugins/kubernetes/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kubernetes", "description": "A Backstage plugin that integrates towards Kubernetes", - "version": "0.7.4-next.0", + "version": "0.7.4-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -66,7 +66,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/lighthouse/CHANGELOG.md b/plugins/lighthouse/CHANGELOG.md index 8a5a1bee97..0600fff13e 100644 --- a/plugins/lighthouse/CHANGELOG.md +++ b/plugins/lighthouse/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-lighthouse +## 0.3.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.3.11-next.0 ### Patch Changes diff --git a/plugins/lighthouse/package.json b/plugins/lighthouse/package.json index 8c87e8eec3..0e6f684360 100644 --- a/plugins/lighthouse/package.json +++ b/plugins/lighthouse/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-lighthouse", "description": "A Backstage plugin that integrates towards Lighthouse", - "version": "0.3.11-next.0", + "version": "0.3.11-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -60,7 +60,7 @@ "@types/node": "^16.11.26", "@types/react": "^16.13.1 || ^17.0.0", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/newrelic-dashboard/CHANGELOG.md b/plugins/newrelic-dashboard/CHANGELOG.md index 81efe251d3..0db2b8cb32 100644 --- a/plugins/newrelic-dashboard/CHANGELOG.md +++ b/plugins/newrelic-dashboard/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-newrelic-dashboard +## 0.2.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.2.4-next.0 ### Patch Changes diff --git a/plugins/newrelic-dashboard/package.json b/plugins/newrelic-dashboard/package.json index a8100bdd38..4daad1ff0b 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.4-next.0", + "version": "0.2.4-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 526010f2f8..35e97b5780 100644 --- a/plugins/newrelic/CHANGELOG.md +++ b/plugins/newrelic/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-newrelic +## 0.3.29-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + ## 0.3.29-next.0 ### Patch Changes diff --git a/plugins/newrelic/package.json b/plugins/newrelic/package.json index 0eedad1ced..45576eb07a 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.29-next.0", + "version": "0.3.29-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -54,7 +54,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/org-react/CHANGELOG.md b/plugins/org-react/CHANGELOG.md new file mode 100644 index 0000000000..e009146419 --- /dev/null +++ b/plugins/org-react/CHANGELOG.md @@ -0,0 +1,17 @@ +# @backstage/plugin-org-react + +## 0.1.0-next.0 + +### Minor Changes + +- e96274f1fe: Implemented the org-react plugin, with it's first component being: a `GroupListPicker` component that will give the user the ability to choose a group + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 diff --git a/plugins/org-react/package.json b/plugins/org-react/package.json index b7b87f9aca..bc2b7f426d 100644 --- a/plugins/org-react/package.json +++ b/plugins/org-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-org-react", - "version": "0.0.0", + "version": "0.1.0-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -54,7 +54,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "*", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/org/CHANGELOG.md b/plugins/org/CHANGELOG.md index 682da2da91..0b461c09d9 100644 --- a/plugins/org/CHANGELOG.md +++ b/plugins/org/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-org +## 0.6.0-next.1 + +### Minor Changes + +- 0b11500151: Updates the User and Group Profile cards to add the links from the UserEntity or the GroupEntity + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.5.11-next.0 ### Patch Changes diff --git a/plugins/org/package.json b/plugins/org/package.json index 507660f1a3..a8ea9946ec 100644 --- a/plugins/org/package.json +++ b/plugins/org/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-org", "description": "A Backstage plugin that helps you create entity pages for your organization", - "version": "0.5.11-next.0", + "version": "0.6.0-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -57,7 +57,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/org/src/components/Cards/OwnershipCard/ComponentsGrid.tsx b/plugins/org/src/components/Cards/OwnershipCard/ComponentsGrid.tsx index 6f7680849c..f996342454 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/ComponentsGrid.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/ComponentsGrid.tsx @@ -56,15 +56,17 @@ const useStyles = makeStyles((theme: BackstageTheme) => const EntityCountTile = ({ counter, type, - name, + kind, url, }: { counter: number; - type: string; - name: string; + type?: string; + kind: string; url: string; }) => { - const classes = useStyles({ type }); + const classes = useStyles({ type: type ?? kind }); + + const rawTitle = type ?? kind; return ( @@ -78,8 +80,9 @@ const EntityCountTile = ({ {counter} - {pluralize(name, counter)} + {pluralize(rawTitle.toLocaleUpperCase('en-US'), counter)} + {type && {kind}} ); @@ -113,11 +116,11 @@ export const ComponentsGrid = ({ return ( {componentsWithCounters?.map(c => ( - + diff --git a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx index 28fa3f4988..84f27fa183 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx @@ -217,10 +217,16 @@ describe('OwnershipCard', () => { expect( queryByText(getByText('SYSTEM').parentElement!, '1'), ).toBeInTheDocument(); + expect( + queryByText(getByText('SYSTEM').parentElement!, 'System'), + ).not.toBeInTheDocument(); expect(getByText('OPENAPI')).toBeInTheDocument(); expect( queryByText(getByText('OPENAPI').parentElement!, '1'), ).toBeInTheDocument(); + expect( + queryByText(getByText('OPENAPI').parentElement!, 'API'), + ).toBeInTheDocument(); expect(() => getByText('LIBRARY')).toThrow(); }); @@ -246,7 +252,7 @@ describe('OwnershipCard', () => { expect(getByText('OPENAPI').closest('a')).toHaveAttribute( 'href', - '/create/?filters%5Bkind%5D=API&filters%5Btype%5D=openapi&filters%5Bowners%5D=my-team&filters%5Buser%5D=all', + '/create/?filters%5Bkind%5D=api&filters%5Btype%5D=openapi&filters%5Bowners%5D=my-team&filters%5Buser%5D=all', ); }); @@ -292,7 +298,7 @@ describe('OwnershipCard', () => { expect(getByText('OPENAPI').closest('a')).toHaveAttribute( 'href', - '/create/?filters%5Bkind%5D=API&filters%5Btype%5D=openapi&filters%5Bowners%5D=user%3Athe-user&filters%5Bowners%5D=my-team&filters%5Bowners%5D=custom%2Fsome-team&filters%5Buser%5D=all', + '/create/?filters%5Bkind%5D=api&filters%5Btype%5D=openapi&filters%5Bowners%5D=user%3Athe-user&filters%5Bowners%5D=my-team&filters%5Bowners%5D=custom%2Fsome-team&filters%5Buser%5D=all', ); }); diff --git a/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.ts b/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.ts index 7c0bb76e2e..c928d9b55f 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.ts +++ b/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.ts @@ -36,7 +36,7 @@ const limiter = limiterFactory(10); type EntityTypeProps = { kind: string; - type: string; + type?: string; count: number; }; @@ -49,7 +49,7 @@ const getQueryParams = ( humanizeEntityRef(parseEntityRef(owner), { defaultKind: 'group' }), ); const filters = { - kind, + kind: kind.toLocaleLowerCase('en-US'), type, owners, user: 'all', @@ -135,7 +135,7 @@ export function useGetEntities( | { counter: number; type: string; - name: string; + kind: string; queryParams: string; }[] | undefined; @@ -173,16 +173,14 @@ export function useGetEntities( const counts = ownedEntitiesList.items.reduce( (acc: EntityTypeProps[], ownedEntity) => { const match = acc.find( - x => - x.kind === ownedEntity.kind && - x.type === (ownedEntity.spec?.type ?? ownedEntity.kind), + x => x.kind === ownedEntity.kind && x.type === ownedEntity.spec?.type, ); if (match) { match.count += 1; } else { acc.push({ kind: ownedEntity.kind, - type: ownedEntity.spec?.type?.toString() ?? ownedEntity.kind, + type: ownedEntity.spec?.type?.toString(), count: 1, }); } @@ -197,12 +195,12 @@ export function useGetEntities( return topN.map(topOwnedEntity => ({ counter: topOwnedEntity.count, type: topOwnedEntity.type, - name: topOwnedEntity.type.toLocaleUpperCase('en-US'), + kind: topOwnedEntity.kind, queryParams: getQueryParams(owners, topOwnedEntity), })) as Array<{ counter: number; type: string; - name: string; + kind: string; queryParams: string; }>; }, [catalogApi, entity, relationsType]); diff --git a/plugins/pagerduty/CHANGELOG.md b/plugins/pagerduty/CHANGELOG.md index ec4a152a4d..56c004d3d8 100644 --- a/plugins/pagerduty/CHANGELOG.md +++ b/plugins/pagerduty/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-pagerduty +## 0.5.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.5.4-next.0 ### Patch Changes diff --git a/plugins/pagerduty/package.json b/plugins/pagerduty/package.json index 64ab795489..4ceb3d2193 100644 --- a/plugins/pagerduty/package.json +++ b/plugins/pagerduty/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-pagerduty", "description": "A Backstage plugin that integrates towards PagerDuty", - "version": "0.5.4-next.0", + "version": "0.5.4-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -61,7 +61,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/periskop-backend/CHANGELOG.md b/plugins/periskop-backend/CHANGELOG.md index 63ca36cc60..cabf964815 100644 --- a/plugins/periskop-backend/CHANGELOG.md +++ b/plugins/periskop-backend/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-periskop-backend +## 0.1.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/config@1.0.4-next.0 + ## 0.1.9-next.0 ### Patch Changes diff --git a/plugins/periskop-backend/package.json b/plugins/periskop-backend/package.json index 3a91af5252..276c0aa137 100644 --- a/plugins/periskop-backend/package.json +++ b/plugins/periskop-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-periskop-backend", - "version": "0.1.9-next.0", + "version": "0.1.9-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -35,7 +35,7 @@ "devDependencies": { "@backstage/cli": "workspace:^", "@types/supertest": "^2.0.8", - "msw": "^0.47.0", + "msw": "^0.48.0", "supertest": "^6.1.6" }, "files": [ diff --git a/plugins/periskop/CHANGELOG.md b/plugins/periskop/CHANGELOG.md index afec1859f2..fa639ab4b0 100644 --- a/plugins/periskop/CHANGELOG.md +++ b/plugins/periskop/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-periskop +## 0.1.9-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.1.9-next.0 ### Patch Changes diff --git a/plugins/periskop/package.json b/plugins/periskop/package.json index 53971e9930..3bc1136acb 100644 --- a/plugins/periskop/package.json +++ b/plugins/periskop/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-periskop", - "version": "0.1.9-next.0", + "version": "0.1.9-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -50,7 +50,7 @@ "@types/luxon": "^3.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist", diff --git a/plugins/permission-backend/CHANGELOG.md b/plugins/permission-backend/CHANGELOG.md index d57c79ca08..31bd75e948 100644 --- a/plugins/permission-backend/CHANGELOG.md +++ b/plugins/permission-backend/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-permission-backend +## 0.5.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/plugin-permission-node@0.7.1-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/plugin-permission-common@0.7.1-next.0 + ## 0.5.13-next.0 ### Patch Changes diff --git a/plugins/permission-backend/package.json b/plugins/permission-backend/package.json index 16351d26b9..5566520b6a 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.13-next.0", + "version": "0.5.13-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -42,7 +42,7 @@ "@backstage/cli": "workspace:^", "@types/lodash": "^4.14.151", "@types/supertest": "^2.0.8", - "msw": "^0.47.0", + "msw": "^0.48.0", "supertest": "^6.1.6" }, "files": [ diff --git a/plugins/permission-common/package.json b/plugins/permission-common/package.json index 394cbe896f..9afa8576fe 100644 --- a/plugins/permission-common/package.json +++ b/plugins/permission-common/package.json @@ -50,6 +50,6 @@ }, "devDependencies": { "@backstage/cli": "workspace:^", - "msw": "^0.47.0" + "msw": "^0.48.0" } } diff --git a/plugins/permission-node/CHANGELOG.md b/plugins/permission-node/CHANGELOG.md index 2d31993117..2c2759ff95 100644 --- a/plugins/permission-node/CHANGELOG.md +++ b/plugins/permission-node/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-permission-node +## 0.7.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/plugin-permission-common@0.7.1-next.0 + ## 0.7.1-next.0 ### Patch Changes diff --git a/plugins/permission-node/package.json b/plugins/permission-node/package.json index 33baf825ac..4543292cc1 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.1-next.0", + "version": "0.7.1-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -48,7 +48,7 @@ "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "@types/supertest": "^2.0.8", - "msw": "^0.47.0", + "msw": "^0.48.0", "supertest": "^6.1.3" }, "files": [ diff --git a/plugins/playlist-backend/CHANGELOG.md b/plugins/playlist-backend/CHANGELOG.md index 9798c12013..a892d6a8dc 100644 --- a/plugins/playlist-backend/CHANGELOG.md +++ b/plugins/playlist-backend/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-playlist-backend +## 0.2.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-test-utils@0.1.30-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/plugin-permission-node@0.7.1-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/plugin-permission-common@0.7.1-next.0 + - @backstage/plugin-playlist-common@0.1.2-next.0 + ## 0.2.1-next.1 ### Patch Changes diff --git a/plugins/playlist-backend/package.json b/plugins/playlist-backend/package.json index 8548a3e4b8..72c58e1c32 100644 --- a/plugins/playlist-backend/package.json +++ b/plugins/playlist-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-playlist-backend", - "version": "0.2.1-next.1", + "version": "0.2.1-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -45,7 +45,7 @@ "devDependencies": { "@backstage/cli": "workspace:^", "@types/supertest": "^2.0.8", - "msw": "^0.47.0", + "msw": "^0.48.0", "supertest": "^6.1.3" }, "files": [ diff --git a/plugins/playlist/CHANGELOG.md b/plugins/playlist/CHANGELOG.md index d7135e79a0..f49f0c6301 100644 --- a/plugins/playlist/CHANGELOG.md +++ b/plugins/playlist/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-playlist +## 0.1.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-common@1.0.8-next.0 + - @backstage/plugin-catalog-react@1.2.1-next.1 + - @backstage/plugin-permission-common@0.7.1-next.0 + - @backstage/plugin-permission-react@0.4.7-next.0 + - @backstage/plugin-playlist-common@0.1.2-next.0 + - @backstage/plugin-search-react@1.2.1-next.1 + ## 0.1.2-next.1 ### Patch Changes diff --git a/plugins/playlist/package.json b/plugins/playlist/package.json index e8fc47a2a9..f50b666c6b 100644 --- a/plugins/playlist/package.json +++ b/plugins/playlist/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-playlist", - "version": "0.1.2-next.1", + "version": "0.1.2-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -62,7 +62,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "*", "cross-fetch": "^3.1.5", - "msw": "^0.47.0", + "msw": "^0.48.0", "swr": "^1.1.2" }, "files": [ diff --git a/plugins/proxy-backend/CHANGELOG.md b/plugins/proxy-backend/CHANGELOG.md index 91c3419ccd..2688a5b6c2 100644 --- a/plugins/proxy-backend/CHANGELOG.md +++ b/plugins/proxy-backend/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-proxy-backend +## 0.2.32-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/config@1.0.4-next.0 + ## 0.2.32-next.0 ### Patch Changes diff --git a/plugins/proxy-backend/package.json b/plugins/proxy-backend/package.json index 2deee67f17..dd9678a28a 100644 --- a/plugins/proxy-backend/package.json +++ b/plugins/proxy-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-proxy-backend", "description": "A Backstage backend plugin that helps you set up proxy endpoints in the backend", - "version": "0.2.32-next.0", + "version": "0.2.32-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -51,7 +51,7 @@ "@types/supertest": "^2.0.8", "@types/uuid": "^8.0.0", "@types/yup": "^0.29.13", - "msw": "^0.47.0", + "msw": "^0.48.0", "supertest": "^6.1.3" }, "files": [ diff --git a/plugins/rollbar-backend/CHANGELOG.md b/plugins/rollbar-backend/CHANGELOG.md index 962b167902..bcf422ffcf 100644 --- a/plugins/rollbar-backend/CHANGELOG.md +++ b/plugins/rollbar-backend/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-rollbar-backend +## 0.1.35-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/config@1.0.4-next.0 + ## 0.1.35-next.0 ### Patch Changes diff --git a/plugins/rollbar-backend/package.json b/plugins/rollbar-backend/package.json index 0fb2c0a4e0..2e7a97fe8b 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.35-next.0", + "version": "0.1.35-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -52,7 +52,7 @@ "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "@types/supertest": "^2.0.8", - "msw": "^0.47.0", + "msw": "^0.48.0", "supertest": "^6.1.3" }, "files": [ diff --git a/plugins/rollbar/CHANGELOG.md b/plugins/rollbar/CHANGELOG.md index 340e06d265..dc2a34ac3b 100644 --- a/plugins/rollbar/CHANGELOG.md +++ b/plugins/rollbar/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-rollbar +## 0.4.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.4.11-next.0 ### Patch Changes diff --git a/plugins/rollbar/package.json b/plugins/rollbar/package.json index 1c4b585f5f..0664b0c41b 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.11-next.0", + "version": "0.4.11-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -62,7 +62,7 @@ "@types/node": "^16.11.26", "@types/react": "^16.13.1 || ^17.0.0", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist", diff --git a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md index 37d00c6885..35f52ccfaf 100644 --- a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-scaffolder-backend-module-cookiecutter +## 0.2.13-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-scaffolder-backend@1.8.0-next.2 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/types@1.0.1-next.0 + ## 0.2.13-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-cookiecutter/package.json b/plugins/scaffolder-backend-module-cookiecutter/package.json index 939e2801da..6c5ddc160c 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.13-next.1", + "version": "0.2.13-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -40,7 +40,7 @@ "@types/fs-extra": "^9.0.1", "@types/mock-fs": "^4.13.0", "mock-fs": "^5.1.0", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/scaffolder-backend-module-rails/CHANGELOG.md b/plugins/scaffolder-backend-module-rails/CHANGELOG.md index 65f0b6cc49..7917e73068 100644 --- a/plugins/scaffolder-backend-module-rails/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-rails/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-scaffolder-backend-module-rails +## 0.4.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-scaffolder-backend@1.8.0-next.2 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/types@1.0.1-next.0 + ## 0.4.6-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-rails/package.json b/plugins/scaffolder-backend-module-rails/package.json index 8f39024301..d7561788d8 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.6-next.1", + "version": "0.4.6-next.2", "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 56cc580bbd..2019b9a0a4 100644 --- a/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-scaffolder-backend-module-yeoman +## 0.2.11-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.8.0-next.2 + - @backstage/config@1.0.4-next.0 + - @backstage/types@1.0.1-next.0 + ## 0.2.11-next.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-yeoman/package.json b/plugins/scaffolder-backend-module-yeoman/package.json index cf7a13a7a4..be16e9b508 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.11-next.1", + "version": "0.2.11-next.2", "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 0a86b5e9bb..1a0135f5f6 100644 --- a/plugins/scaffolder-backend/CHANGELOG.md +++ b/plugins/scaffolder-backend/CHANGELOG.md @@ -1,5 +1,30 @@ # @backstage/plugin-scaffolder-backend +## 1.8.0-next.2 + +### Minor Changes + +- 5025d2e8b6: Adds the ability to pass (an optional) array of strings that will be applied to the newly scaffolded repository as topic labels. + +### Patch Changes + +- 969a8444ea: Updated dependency `esbuild` to `^0.15.0`. +- 9ff4ff3745: Implement "Branch protection rules" support for "publish:github" action +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-plugin-api@0.1.4-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/plugin-catalog-backend@1.5.1-next.1 + - @backstage/plugin-catalog-node@1.2.1-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/types@1.0.1-next.0 + - @backstage/plugin-scaffolder-common@1.2.2-next.0 + ## 1.8.0-next.1 ### Minor Changes diff --git a/plugins/scaffolder-backend/api-report.md b/plugins/scaffolder-backend/api-report.md index 846fa59b08..50395ed4c9 100644 --- a/plugins/scaffolder-backend/api-report.md +++ b/plugins/scaffolder-backend/api-report.md @@ -198,6 +198,13 @@ export function createGithubRepoCreateAction(options: { allowMergeCommit?: boolean | undefined; allowAutoMerge?: boolean | undefined; requireCodeOwnerReviews?: boolean | undefined; + bypassPullRequestAllowances?: + | { + users?: string[] | undefined; + teams?: string[] | undefined; + apps?: string[] | undefined; + } + | undefined; requiredStatusCheckContexts?: string[] | undefined; requireBranchesToBeUpToDate?: boolean | undefined; repoVisibility?: 'internal' | 'private' | 'public' | undefined; @@ -236,6 +243,13 @@ export function createGithubRepoPushAction(options: { gitAuthorName?: string | undefined; gitAuthorEmail?: string | undefined; requireCodeOwnerReviews?: boolean | undefined; + bypassPullRequestAllowances?: + | { + users?: string[]; + teams?: string[]; + apps?: string[]; + } + | undefined; requiredStatusCheckContexts?: string[] | undefined; requireBranchesToBeUpToDate?: boolean | undefined; sourcePath?: string | undefined; @@ -366,6 +380,13 @@ export function createPublishGithubAction(options: { allowMergeCommit?: boolean | undefined; allowAutoMerge?: boolean | undefined; sourcePath?: string | undefined; + bypassPullRequestAllowances?: + | { + users?: string[]; + teams?: string[]; + apps?: string[]; + } + | undefined; requireCodeOwnerReviews?: boolean | undefined; requiredStatusCheckContexts?: string[] | undefined; requireBranchesToBeUpToDate?: boolean | undefined; @@ -422,6 +443,7 @@ export function createPublishGitlabAction(options: { gitAuthorName?: string | undefined; gitAuthorEmail?: string | undefined; setUserAsOwner?: boolean | undefined; + topics?: string[] | undefined; }>; // @public diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index 816704705e..0eaa9aca2d 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.8.0-next.1", + "version": "1.8.0-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -93,7 +93,7 @@ "esbuild": "^0.15.0", "jest-when": "^3.1.0", "mock-fs": "^5.1.0", - "msw": "^0.47.0", + "msw": "^0.48.0", "supertest": "^6.1.3", "yaml": "^2.0.0" }, diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoCreate.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoCreate.ts index 9348526b20..760f42eade 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoCreate.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoCreate.ts @@ -52,6 +52,11 @@ export function createGithubRepoCreateAction(options: { allowMergeCommit?: boolean; allowAutoMerge?: boolean; requireCodeOwnerReviews?: boolean; + bypassPullRequestAllowances?: { + users?: string[]; + teams?: string[]; + apps?: string[]; + }; requiredStatusCheckContexts?: string[]; requireBranchesToBeUpToDate?: boolean; repoVisibility?: 'private' | 'internal' | 'public'; @@ -85,6 +90,7 @@ export function createGithubRepoCreateAction(options: { homepage: inputProps.homepage, access: inputProps.access, requireCodeOwnerReviews: inputProps.requireCodeOwnerReviews, + bypassPullRequestAllowances: inputProps.bypassPullRequestAllowances, requiredStatusCheckContexts: inputProps.requiredStatusCheckContexts, requireBranchesToBeUpToDate: inputProps.requireBranchesToBeUpToDate, repoVisibility: inputProps.repoVisibility, diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoPush.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoPush.ts index b02a475698..1694e37710 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoPush.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoPush.ts @@ -49,6 +49,13 @@ export function createGithubRepoPushAction(options: { gitAuthorName?: string; gitAuthorEmail?: string; requireCodeOwnerReviews?: boolean; + bypassPullRequestAllowances?: + | { + users?: string[]; + teams?: string[]; + apps?: string[]; + } + | undefined; requiredStatusCheckContexts?: string[]; requireBranchesToBeUpToDate?: boolean; sourcePath?: string; @@ -65,6 +72,7 @@ export function createGithubRepoPushAction(options: { repoUrl: inputProps.repoUrl, requireCodeOwnerReviews: inputProps.requireCodeOwnerReviews, requiredStatusCheckContexts: inputProps.requiredStatusCheckContexts, + bypassPullRequestAllowances: inputProps.bypassPullRequestAllowances, requireBranchesToBeUpToDate: inputProps.requireBranchesToBeUpToDate, defaultBranch: inputProps.defaultBranch, protectDefaultBranch: inputProps.protectDefaultBranch, @@ -94,6 +102,7 @@ export function createGithubRepoPushAction(options: { gitAuthorName, gitAuthorEmail, requireCodeOwnerReviews = false, + bypassPullRequestAllowances, requiredStatusCheckContexts = [], requireBranchesToBeUpToDate = true, token: providedToken, @@ -131,6 +140,7 @@ export function createGithubRepoPushAction(options: { client, repo, requireCodeOwnerReviews, + bypassPullRequestAllowances, requiredStatusCheckContexts, requireBranchesToBeUpToDate, config, diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/helpers.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/helpers.ts index 2264da1dac..2891ea51cf 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/helpers.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/helpers.ts @@ -247,6 +247,13 @@ export async function initRepoPushAndProtect( client: Octokit, repo: string, requireCodeOwnerReviews: boolean, + bypassPullRequestAllowances: + | { + users?: string[]; + teams?: string[]; + apps?: string[]; + } + | undefined, requiredStatusCheckContexts: string[], requireBranchesToBeUpToDate: boolean, config: Config, @@ -289,6 +296,7 @@ export async function initRepoPushAndProtect( repoName: repo, logger, defaultBranch, + bypassPullRequestAllowances, requireCodeOwnerReviews, requiredStatusCheckContexts, requireBranchesToBeUpToDate, diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/inputProperties.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/inputProperties.ts index b00d5fa132..e832c3dbfa 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/inputProperties.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/inputProperties.ts @@ -147,6 +147,35 @@ const protectEnforceAdmins = { type: 'boolean', description: `Enforce admins to adhere to default branch protection. The default value is 'true'`, }; + +const bypassPullRequestAllowances = { + title: 'Bypass pull request requirements', + description: + 'Allow specific users, teams, or apps to bypass pull request requirements.', + type: 'object', + additionalProperties: false, + properties: { + apps: { + type: 'array', + items: { + type: 'string', + }, + }, + users: { + type: 'array', + items: { + type: 'string', + }, + }, + teams: { + type: 'array', + items: { + type: 'string', + }, + }, + }, +}; + const gitCommitMessage = { title: 'Git Commit Message', type: 'string', @@ -174,6 +203,7 @@ export { gitCommitMessage }; export { homepage }; export { protectDefaultBranch }; export { protectEnforceAdmins }; +export { bypassPullRequestAllowances }; export { repoUrl }; export { repoVisibility }; export { requireCodeOwnerReviews }; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/helpers.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/helpers.ts index be77d27a9a..5afe51cc35 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/helpers.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/helpers.ts @@ -185,6 +185,11 @@ type BranchProtectionOptions = { logger: Logger; requireCodeOwnerReviews: boolean; requiredStatusCheckContexts?: string[]; + bypassPullRequestAllowances?: { + users?: string[]; + teams?: string[]; + apps?: string[]; + }; requireBranchesToBeUpToDate?: boolean; defaultBranch?: string; enforceAdmins?: boolean; @@ -196,6 +201,7 @@ export const enableBranchProtectionOnDefaultRepoBranch = async ({ owner, logger, requireCodeOwnerReviews, + bypassPullRequestAllowances, requiredStatusCheckContexts = [], requireBranchesToBeUpToDate = true, defaultBranch = 'master', @@ -226,6 +232,7 @@ export const enableBranchProtectionOnDefaultRepoBranch = async ({ required_pull_request_reviews: { required_approving_review_count: 1, require_code_owner_reviews: requireCodeOwnerReviews, + bypass_pull_request_allowances: bypassPullRequestAllowances, }, }); } catch (e) { diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.ts index c1f8e8b5b6..be4cbb1dad 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.ts @@ -29,6 +29,7 @@ import { import * as inputProps from '../github/inputProperties'; import * as outputProps from '../github/outputProperties'; import { parseRepoUrl } from './util'; + /** * Creates a new action that initializes a git repository of the content in the workspace * and publishes it to GitHub. @@ -59,6 +60,13 @@ export function createPublishGithubAction(options: { allowMergeCommit?: boolean; allowAutoMerge?: boolean; sourcePath?: string; + bypassPullRequestAllowances?: + | { + users?: string[]; + teams?: string[]; + apps?: string[]; + } + | undefined; requireCodeOwnerReviews?: boolean; requiredStatusCheckContexts?: string[]; requireBranchesToBeUpToDate?: boolean; @@ -93,6 +101,7 @@ export function createPublishGithubAction(options: { description: inputProps.description, homepage: inputProps.homepage, access: inputProps.access, + bypassPullRequestAllowances: inputProps.bypassPullRequestAllowances, requireCodeOwnerReviews: inputProps.requireCodeOwnerReviews, requiredStatusCheckContexts: inputProps.requiredStatusCheckContexts, requireBranchesToBeUpToDate: inputProps.requireBranchesToBeUpToDate, @@ -129,6 +138,7 @@ export function createPublishGithubAction(options: { homepage, access, requireCodeOwnerReviews = false, + bypassPullRequestAllowances, requiredStatusCheckContexts = [], requireBranchesToBeUpToDate = true, repoVisibility = 'private', @@ -195,6 +205,7 @@ export function createPublishGithubAction(options: { client, repo, requireCodeOwnerReviews, + bypassPullRequestAllowances, requiredStatusCheckContexts, requireBranchesToBeUpToDate, config, 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 9fc95b1b5e..53669efd0b 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlab.ts @@ -44,6 +44,7 @@ export function createPublishGitlabAction(options: { gitAuthorName?: string; gitAuthorEmail?: string; setUserAsOwner?: boolean; + topics?: string[]; }>({ id: 'publish:gitlab', description: @@ -99,6 +100,14 @@ export function createPublishGitlabAction(options: { description: 'Set the token user as owner of the newly created repository. Requires a token authorized to do the edit in the integration configuration for the matching host', }, + topics: { + title: 'Topic labels', + description: 'Topic labels to apply on the repository.', + type: 'array', + items: { + type: 'string', + }, + }, }, }, output: { @@ -128,6 +137,7 @@ export function createPublishGitlabAction(options: { gitAuthorName, gitAuthorEmail, setUserAsOwner = false, + topics = [], } = ctx.input; const { owner, repo, host } = parseRepoUrl(repoUrl, integrations); @@ -173,6 +183,7 @@ export function createPublishGitlabAction(options: { namespace_id: targetNamespace, name: repo, visibility: repoVisibility, + ...(topics.length ? { topics } : {}), }); // When setUserAsOwner is true the input token is expected to come from an unprivileged user GitLab diff --git a/plugins/scaffolder/CHANGELOG.md b/plugins/scaffolder/CHANGELOG.md index 709809f5f7..42c911e511 100644 --- a/plugins/scaffolder/CHANGELOG.md +++ b/plugins/scaffolder/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-scaffolder +## 1.8.0-next.1 + +### Patch Changes + +- 580285787d: The `create` and `click` analytics events are now also captured on the "next" version of the component creation page. +- 3b3fc3cc3c: Fix `formData` not being present in the `next` version +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/integration-react@1.1.6-next.1 + - @backstage/theme@0.2.16 + - @backstage/types@1.0.1-next.0 + - @backstage/plugin-catalog-common@1.0.8-next.0 + - @backstage/plugin-catalog-react@1.2.1-next.1 + - @backstage/plugin-permission-react@0.4.7-next.0 + - @backstage/plugin-scaffolder-common@1.2.2-next.0 + ## 1.8.0-next.0 ### Minor Changes diff --git a/plugins/scaffolder/api-report.md b/plugins/scaffolder/api-report.md index 158c75e5bd..27eb863a16 100644 --- a/plugins/scaffolder/api-report.md +++ b/plugins/scaffolder/api-report.md @@ -42,7 +42,7 @@ export function createNextScaffolderFieldExtension< TInputProps extends UIOptionsType = {}, >( options: NextFieldExtensionOptions, -): Extension>; +): Extension>; // @public export function createScaffolderFieldExtension< diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index cfa69c128a..214351e2b7 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.8.0-next.0", + "version": "1.8.0-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -55,11 +55,11 @@ "@material-ui/lab": "4.0.0-alpha.57", "@react-hookz/web": "^15.0.0", "@rjsf/core": "^3.2.1", - "@rjsf/core-v5": "npm:@rjsf/core@^5.0.0-beta.10", + "@rjsf/core-v5": "npm:@rjsf/core@^5.0.0-beta.12", "@rjsf/material-ui": "^3.2.1", - "@rjsf/material-ui-v5": "npm:@rjsf/material-ui@^5.0.0-beta.10", - "@rjsf/utils": "^5.0.0-beta.10", - "@rjsf/validator-ajv8": "^5.0.0-beta.10", + "@rjsf/material-ui-v5": "npm:@rjsf/material-ui@^5.0.0-beta.12", + "@rjsf/utils": "^5.0.0-beta.12", + "@rjsf/validator-ajv8": "^5.0.0-beta.12", "@types/json-schema": "^7.0.9", "@uiw/react-codemirror": "^4.9.3", "classnames": "^2.2.6", @@ -96,7 +96,7 @@ "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", "event-source-polyfill": "1.0.25", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist", diff --git a/plugins/scaffolder/src/components/fields/EntityNamePicker/validation.ts b/plugins/scaffolder/src/components/fields/EntityNamePicker/validation.ts index 7a40a460ba..d116bef228 100644 --- a/plugins/scaffolder/src/components/fields/EntityNamePicker/validation.ts +++ b/plugins/scaffolder/src/components/fields/EntityNamePicker/validation.ts @@ -23,7 +23,7 @@ export const entityNamePickerValidation = ( ) => { if (!KubernetesValidatorFunctions.isValidObjectName(value)) { validation.addError( - 'must start and end with an alphanumeric character, and contain only alphanumeric characters, hyphens, underscores, and periods. Maximum length is 63 characters.', + 'Must start and end with an alphanumeric character, and contain only alphanumeric characters, hyphens, underscores, and periods. Maximum length is 63 characters.', ); } }; diff --git a/plugins/scaffolder/src/extensions/index.tsx b/plugins/scaffolder/src/extensions/index.tsx index 08075b5b9d..08ab3e603c 100644 --- a/plugins/scaffolder/src/extensions/index.tsx +++ b/plugins/scaffolder/src/extensions/index.tsx @@ -72,7 +72,7 @@ export function createNextScaffolderFieldExtension< TInputProps extends UIOptionsType = {}, >( options: NextFieldExtensionOptions, -): Extension> { +): Extension> { return { expose() { const FieldExtensionDataHolder: any = () => null; diff --git a/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/Stepper.tsx b/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/Stepper.tsx index bed2515aaf..75f92916df 100644 --- a/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/Stepper.tsx +++ b/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/Stepper.tsx @@ -143,6 +143,7 @@ export const Stepper = (props: StepperProps) => { validator={validator} extraErrors={errors as unknown as ErrorSchema} formData={formState} + formContext={{ formData: formState }} schema={steps[activeStep].schema} uiSchema={steps[activeStep].uiSchema} onSubmit={handleNext} diff --git a/plugins/search-backend-module-elasticsearch/CHANGELOG.md b/plugins/search-backend-module-elasticsearch/CHANGELOG.md index 30a3367bf4..d2dbb132d1 100644 --- a/plugins/search-backend-module-elasticsearch/CHANGELOG.md +++ b/plugins/search-backend-module-elasticsearch/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-search-backend-module-elasticsearch +## 1.0.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-backend-node@1.0.4-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/plugin-search-common@1.1.1-next.0 + ## 1.0.4-next.0 ### Patch Changes diff --git a/plugins/search-backend-module-elasticsearch/package.json b/plugins/search-backend-module-elasticsearch/package.json index a45c3c43e5..63735691a3 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.0.4-next.0", + "version": "1.0.4-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 dcd0bbdc78..cc2c25de46 100644 --- a/plugins/search-backend-module-pg/CHANGELOG.md +++ b/plugins/search-backend-module-pg/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-search-backend-module-pg +## 0.4.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-search-backend-node@1.0.4-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/plugin-search-common@1.1.1-next.0 + ## 0.4.2-next.0 ### Patch Changes diff --git a/plugins/search-backend-module-pg/package.json b/plugins/search-backend-module-pg/package.json index 5e91bfabeb..d89c2cdcda 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.4.2-next.0", + "version": "0.4.2-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 bfcd09dcad..4a8bb84934 100644 --- a/plugins/search-backend-node/CHANGELOG.md +++ b/plugins/search-backend-node/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-search-backend-node +## 1.0.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/plugin-permission-common@0.7.1-next.0 + - @backstage/plugin-search-common@1.1.1-next.0 + ## 1.0.4-next.0 ### Patch Changes diff --git a/plugins/search-backend-node/package.json b/plugins/search-backend-node/package.json index a0c4964ccf..5d8e08d661 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.0.4-next.0", + "version": "1.0.4-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 c2cc89ac5b..c52b2fe13e 100644 --- a/plugins/search-backend/CHANGELOG.md +++ b/plugins/search-backend/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-search-backend +## 1.1.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/plugin-permission-node@0.7.1-next.1 + - @backstage/plugin-search-backend-node@1.0.4-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/types@1.0.1-next.0 + - @backstage/plugin-permission-common@0.7.1-next.0 + - @backstage/plugin-search-common@1.1.1-next.0 + ## 1.1.1-next.0 ### Patch Changes diff --git a/plugins/search-backend/package.json b/plugins/search-backend/package.json index d221cf1ea5..4ea9db283c 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.1.1-next.0", + "version": "1.1.1-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 d5f100d97c..043d87828f 100644 --- a/plugins/search-react/CHANGELOG.md +++ b/plugins/search-react/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-search-react +## 1.2.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/types@1.0.1-next.0 + - @backstage/version-bridge@1.0.1 + - @backstage/plugin-search-common@1.1.1-next.0 + ## 1.2.1-next.0 ### Patch Changes diff --git a/plugins/search-react/package.json b/plugins/search-react/package.json index 7097d8fa4e..3d8fa634d4 100644 --- a/plugins/search-react/package.json +++ b/plugins/search-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-react", - "version": "1.2.1-next.0", + "version": "1.2.1-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/search/CHANGELOG.md b/plugins/search/CHANGELOG.md index 5e71299d1e..a673a8c2b1 100644 --- a/plugins/search/CHANGELOG.md +++ b/plugins/search/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-search +## 1.0.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/types@1.0.1-next.0 + - @backstage/version-bridge@1.0.1 + - @backstage/plugin-catalog-react@1.2.1-next.1 + - @backstage/plugin-search-common@1.1.1-next.0 + - @backstage/plugin-search-react@1.2.1-next.1 + ## 1.0.4-next.0 ### Patch Changes diff --git a/plugins/search/package.json b/plugins/search/package.json index 7d0f6d4f52..3631dbf073 100644 --- a/plugins/search/package.json +++ b/plugins/search/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search", "description": "The Backstage plugin that provides your backstage app with search", - "version": "1.0.4-next.0", + "version": "1.0.4-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -66,7 +66,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/sentry/CHANGELOG.md b/plugins/sentry/CHANGELOG.md index 661950e6ca..da4ab7914d 100644 --- a/plugins/sentry/CHANGELOG.md +++ b/plugins/sentry/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-sentry +## 0.4.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.4.4-next.0 ### Patch Changes diff --git a/plugins/sentry/package.json b/plugins/sentry/package.json index 190e9b048b..9e2fc84e95 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.4.4-next.0", + "version": "0.4.4-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -62,7 +62,7 @@ "@types/node": "^16.11.26", "@types/react": "^16.13.1 || ^17.0.0", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist", diff --git a/plugins/shortcuts/CHANGELOG.md b/plugins/shortcuts/CHANGELOG.md index e918aa8608..26da68d31e 100644 --- a/plugins/shortcuts/CHANGELOG.md +++ b/plugins/shortcuts/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-shortcuts +## 0.3.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/types@1.0.1-next.0 + ## 0.3.3-next.0 ### Patch Changes diff --git a/plugins/shortcuts/package.json b/plugins/shortcuts/package.json index 2bd0204af7..bd24319681 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.3-next.0", + "version": "0.3.3-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -50,7 +50,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/sonarqube-backend/CHANGELOG.md b/plugins/sonarqube-backend/CHANGELOG.md index e752ee9a2b..30a02a3f2f 100644 --- a/plugins/sonarqube-backend/CHANGELOG.md +++ b/plugins/sonarqube-backend/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-sonarqube-backend +## 0.1.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + ## 0.1.3-next.0 ### Patch Changes diff --git a/plugins/sonarqube-backend/package.json b/plugins/sonarqube-backend/package.json index 59f02b2950..269b6cc761 100644 --- a/plugins/sonarqube-backend/package.json +++ b/plugins/sonarqube-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-sonarqube-backend", - "version": "0.1.3-next.0", + "version": "0.1.3-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -36,7 +36,7 @@ "@backstage/cli": "workspace:^", "@backstage/test-utils": "workspace:^", "@types/supertest": "^2.0.12", - "msw": "^0.47.0", + "msw": "^0.48.0", "supertest": "^6.2.4" }, "files": [ diff --git a/plugins/sonarqube/CHANGELOG.md b/plugins/sonarqube/CHANGELOG.md index dd5aa80817..0839fd4009 100644 --- a/plugins/sonarqube/CHANGELOG.md +++ b/plugins/sonarqube/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-sonarqube +## 0.4.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.4.3-next.0 ### Patch Changes diff --git a/plugins/sonarqube/api-report.md b/plugins/sonarqube/api-report.md index e0a51479a4..2edf80618e 100644 --- a/plugins/sonarqube/api-report.md +++ b/plugins/sonarqube/api-report.md @@ -21,9 +21,17 @@ export const EntitySonarQubeCard: (props: { duplicationRatings?: DuplicationRating[] | undefined; }) => JSX.Element; +// @public (undocumented) +export const EntitySonarQubeContentPage: ( + props: SonarQubeContentPageProps, +) => JSX.Element; + // @public (undocumented) export const isSonarQubeAvailable: (entity: Entity) => boolean; +// @public (undocumented) +export const SONARQUBE_PROJECT_KEY_ANNOTATION = 'sonarqube.org/project-key'; + // @public (undocumented) export const SonarQubeCard: (props: { variant?: InfoCardVariants; @@ -31,7 +39,11 @@ export const SonarQubeCard: (props: { }) => JSX.Element; // @public (undocumented) -const sonarQubePlugin: BackstagePlugin<{}, {}, {}>; -export { sonarQubePlugin as plugin }; -export { sonarQubePlugin }; +export type SonarQubeContentPageProps = { + title?: string; + supportTitle?: string; +}; + +// @public (undocumented) +export const sonarQubePlugin: BackstagePlugin<{}, {}, {}>; ``` diff --git a/plugins/sonarqube/package.json b/plugins/sonarqube/package.json index b46cb5c0b1..2d217ee57c 100644 --- a/plugins/sonarqube/package.json +++ b/plugins/sonarqube/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-sonarqube", "description": "", - "version": "0.4.3-next.0", + "version": "0.4.3-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -59,7 +59,7 @@ "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist", diff --git a/plugins/sonarqube/src/components/SonarQubeContentPage/SonarQubeContentPage.test.tsx b/plugins/sonarqube/src/components/SonarQubeContentPage/SonarQubeContentPage.test.tsx new file mode 100644 index 0000000000..8e847d7c31 --- /dev/null +++ b/plugins/sonarqube/src/components/SonarQubeContentPage/SonarQubeContentPage.test.tsx @@ -0,0 +1,91 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { EntityProvider } from '@backstage/plugin-catalog-react'; +import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; +import { lightTheme } from '@backstage/theme'; +import { ThemeProvider } from '@material-ui/core'; +import React from 'react'; +import { + isSonarQubeAvailable, + SONARQUBE_PROJECT_KEY_ANNOTATION, +} from '../useProjectKey'; +import { SonarQubeApi, sonarQubeApiRef } from '../../api'; + +const Providers = ({ + annotation, + children, +}: { annotation: string } & React.PropsWithChildren): JSX.Element => ( + + + {children} + + +); + +describe('', () => { + beforeAll(() => { + jest.mock('@backstage/plugin-sonarqube', () => ({ + __esModule: true, + isSonarQubeAvailable, + EntitySonarQubeCard: () => { + return
; + }, + })); + }); + + it('renders EntitySonarQubeCard', async () => { + const { SonarQubeContentPage } = require('./SonarQubeContentPage'); + + const rendered = await renderInTestApp( + + + , + ); + expect(rendered.getByText('SonarQube Dashboard')).toBeInTheDocument(); + expect(rendered.getByText('No information to display')).toBeInTheDocument(); + expect( + rendered.getByText("There is no SonarQube project with key 'bar'."), + ).toBeInTheDocument(); + }, 15000); + + it('renders MissingAnnotationEmptyState if sonar annotation is missing', async () => { + const { SonarQubeContentPage } = require('./SonarQubeContentPage'); + + const rendered = await renderInTestApp( + + + , + ); + expect(rendered.getByText('Missing Annotation')).toBeInTheDocument(); + expect( + rendered.getAllByText(SONARQUBE_PROJECT_KEY_ANNOTATION, { exact: false }) + .length, + ).toBe(2); + }, 15000); +}); diff --git a/plugins/sonarqube/src/components/SonarQubeContentPage/SonarQubeContentPage.tsx b/plugins/sonarqube/src/components/SonarQubeContentPage/SonarQubeContentPage.tsx new file mode 100644 index 0000000000..33a145b746 --- /dev/null +++ b/plugins/sonarqube/src/components/SonarQubeContentPage/SonarQubeContentPage.tsx @@ -0,0 +1,53 @@ +/* + * 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 { + Content, + ContentHeader, + SupportButton, +} from '@backstage/core-components'; +import { MissingAnnotationEmptyState } from '@backstage/core-components'; +import { useEntity } from '@backstage/plugin-catalog-react'; +import React from 'react'; +import { + isSonarQubeAvailable, + SONARQUBE_PROJECT_KEY_ANNOTATION, +} from '../useProjectKey'; +import { SonarQubeCard } from '../SonarQubeCard'; + +/** @public */ +export type SonarQubeContentPageProps = { + title?: string; + supportTitle?: string; +}; + +export const SonarQubeContentPage = (props: SonarQubeContentPageProps) => { + const { entity } = useEntity(); + const { title, supportTitle } = props; + + return isSonarQubeAvailable(entity) ? ( + + + {supportTitle && {supportTitle}} + + + + ) : ( + + ); +}; diff --git a/plugins/sonarqube/src/components/SonarQubeContentPage/index.ts b/plugins/sonarqube/src/components/SonarQubeContentPage/index.ts new file mode 100644 index 0000000000..59327e9a88 --- /dev/null +++ b/plugins/sonarqube/src/components/SonarQubeContentPage/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { SonarQubeContentPage } from './SonarQubeContentPage'; +export type { SonarQubeContentPageProps } from './SonarQubeContentPage'; diff --git a/plugins/sonarqube/src/components/index.ts b/plugins/sonarqube/src/components/index.ts index 7e58100efa..8e1d93f85b 100644 --- a/plugins/sonarqube/src/components/index.ts +++ b/plugins/sonarqube/src/components/index.ts @@ -14,5 +14,10 @@ * limitations under the License. */ -export * from './SonarQubeCard'; -export { isSonarQubeAvailable } from './useProjectKey'; +export { SonarQubeCard } from './SonarQubeCard'; +export type { DuplicationRating } from './SonarQubeCard'; +export type { SonarQubeContentPageProps } from './SonarQubeContentPage'; +export { + isSonarQubeAvailable, + SONARQUBE_PROJECT_KEY_ANNOTATION, +} from './useProjectKey'; diff --git a/plugins/sonarqube/src/components/useProjectKey.test.ts b/plugins/sonarqube/src/components/useProjectKey.test.ts index 921e9455c0..8686ac82de 100644 --- a/plugins/sonarqube/src/components/useProjectKey.test.ts +++ b/plugins/sonarqube/src/components/useProjectKey.test.ts @@ -39,10 +39,12 @@ describe('isSonarQubeAvailable', () => { const entity = createDummyEntity('dummy'); expect(isSonarQubeAvailable(entity)).toBe(true); }); + it('returns false if sonarqube annotation empty', () => { const entity = createDummyEntity(''); expect(isSonarQubeAvailable(entity)).toBe(false); }); + it('returns false if sonarqube annotation not defined', () => { const entity = { apiVersion: '', @@ -59,6 +61,7 @@ describe('isSonarQubeAvailable', () => { describe('useProjectInfo', () => { const DUMMY_INSTANCE = 'dummyInstance'; const DUMMY_KEY = 'dummyKey'; + it('parse annotation with key and instance', () => { const entity = createDummyEntity( DUMMY_INSTANCE + SONARQUBE_PROJECT_INSTANCE_SEPARATOR + DUMMY_KEY, @@ -68,6 +71,33 @@ describe('useProjectInfo', () => { projectKey: DUMMY_KEY, }); }); + + it('parse annotation with instance, tenant/project-key', () => { + const DUMMY_KEY_WITH_TENANT = 'dummy-tenant/dummyKey'; + const entity = createDummyEntity( + DUMMY_INSTANCE + + SONARQUBE_PROJECT_INSTANCE_SEPARATOR + + DUMMY_KEY_WITH_TENANT, + ); + expect(useProjectInfo(entity)).toEqual({ + projectInstance: DUMMY_INSTANCE, + projectKey: DUMMY_KEY_WITH_TENANT, + }); + }); + + it('parse annotation with instance, tenant:project-key', () => { + const DUMMY_KEY_WITH_TENANT = 'dummy-tenant:dummyKey'; + const entity = createDummyEntity( + DUMMY_INSTANCE + + SONARQUBE_PROJECT_INSTANCE_SEPARATOR + + DUMMY_KEY_WITH_TENANT, + ); + expect(useProjectInfo(entity)).toEqual({ + projectInstance: DUMMY_INSTANCE, + projectKey: DUMMY_KEY_WITH_TENANT, + }); + }); + // compatibility with previous mono-instance sonarqube config it('parse annotation with only key', () => { const entity = createDummyEntity(DUMMY_KEY); @@ -76,6 +106,7 @@ describe('useProjectInfo', () => { projectKey: DUMMY_KEY, }); }); + it('handle empty annotation', () => { const entity = createDummyEntity(''); expect(useProjectInfo(entity)).toEqual({ @@ -83,6 +114,7 @@ describe('useProjectInfo', () => { projectKey: undefined, }); }); + it('handle non-existent annotation', () => { const entity = { apiVersion: '', diff --git a/plugins/sonarqube/src/components/useProjectKey.ts b/plugins/sonarqube/src/components/useProjectKey.ts index 59a572a6c4..20f7f03bb3 100644 --- a/plugins/sonarqube/src/components/useProjectKey.ts +++ b/plugins/sonarqube/src/components/useProjectKey.ts @@ -16,6 +16,7 @@ import { Entity } from '@backstage/catalog-model'; +/** @public */ export const SONARQUBE_PROJECT_KEY_ANNOTATION = 'sonarqube.org/project-key'; export const SONARQUBE_PROJECT_INSTANCE_SEPARATOR = '/'; @@ -42,11 +43,16 @@ export const useProjectInfo = ( const annotation = entity?.metadata.annotations?.[SONARQUBE_PROJECT_KEY_ANNOTATION]; if (annotation) { - if (annotation.indexOf(SONARQUBE_PROJECT_INSTANCE_SEPARATOR) > -1) { - [projectInstance, projectKey] = annotation.split( - SONARQUBE_PROJECT_INSTANCE_SEPARATOR, - 2, - ); + const instanceSeparatorIndex = annotation.indexOf( + SONARQUBE_PROJECT_INSTANCE_SEPARATOR, + ); + if (instanceSeparatorIndex > -1) { + // Examples: + // instanceA/projectA -> projectInstance = "instanceA" & projectKey = "projectA" + // instanceA/tenantA:projectA -> projectInstance = "instanceA" & projectKey = "tenantA:projectA" + // instanceA/tenantA/projectA -> projectInstance = "instanceA" & projectKey = "tenantA/projectA" + projectInstance = annotation.substring(0, instanceSeparatorIndex); + projectKey = annotation.substring(instanceSeparatorIndex + 1); } else { projectKey = annotation; } diff --git a/plugins/sonarqube/src/index.ts b/plugins/sonarqube/src/index.ts index 1e6f83aa49..30f6351d4d 100644 --- a/plugins/sonarqube/src/index.ts +++ b/plugins/sonarqube/src/index.ts @@ -22,8 +22,4 @@ */ export * from './components'; -export { - sonarQubePlugin, - sonarQubePlugin as plugin, - EntitySonarQubeCard, -} from './plugin'; +export * from './plugin'; diff --git a/plugins/sonarqube/src/plugin.ts b/plugins/sonarqube/src/plugin.ts index 0ea62de492..5eb5ea82f3 100644 --- a/plugins/sonarqube/src/plugin.ts +++ b/plugins/sonarqube/src/plugin.ts @@ -52,3 +52,16 @@ export const EntitySonarQubeCard = sonarQubePlugin.provide( }, }), ); + +/** @public */ +export const EntitySonarQubeContentPage = sonarQubePlugin.provide( + createComponentExtension({ + name: 'EntitySonarQubeContentPage', + component: { + lazy: () => + import('./components/SonarQubeContentPage').then( + m => m.SonarQubeContentPage, + ), + }, + }), +); diff --git a/plugins/splunk-on-call/CHANGELOG.md b/plugins/splunk-on-call/CHANGELOG.md index 02a736b782..c4bc4eca7e 100644 --- a/plugins/splunk-on-call/CHANGELOG.md +++ b/plugins/splunk-on-call/CHANGELOG.md @@ -1,5 +1,24 @@ # @backstage/plugin-splunk-on-call +## 0.4.0-next.1 + +### Minor Changes + +- 34b772ef31: Use the routing key if it's available instead of team name when triggering incidents. + + BREAKING CHANGE: + Before, the team name was used even if the routing key (with or without team) was used. + Now, the routing key defined for the component will be used instead of the team name. + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.3.35-next.0 ### Patch Changes diff --git a/plugins/splunk-on-call/package.json b/plugins/splunk-on-call/package.json index 0434c7b07b..dfb4aef654 100644 --- a/plugins/splunk-on-call/package.json +++ b/plugins/splunk-on-call/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-splunk-on-call", "description": "A Backstage plugin that integrates towards Splunk On-Call", - "version": "0.3.35-next.0", + "version": "0.4.0-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -60,7 +60,7 @@ "@types/luxon": "^3.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "configSchema": "config.d.ts", "files": [ diff --git a/plugins/stack-overflow-backend/CHANGELOG.md b/plugins/stack-overflow-backend/CHANGELOG.md index 50b989079a..e1e06fc69e 100644 --- a/plugins/stack-overflow-backend/CHANGELOG.md +++ b/plugins/stack-overflow-backend/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-stack-overflow-backend +## 0.1.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.21.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/plugin-search-common@1.1.1-next.0 + ## 0.1.7-next.0 ### Patch Changes diff --git a/plugins/stack-overflow-backend/package.json b/plugins/stack-overflow-backend/package.json index 4714c29551..34203bb2f7 100644 --- a/plugins/stack-overflow-backend/package.json +++ b/plugins/stack-overflow-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-stack-overflow-backend", - "version": "0.1.7-next.0", + "version": "0.1.7-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 a725475f69..0d68732761 100644 --- a/plugins/stack-overflow/CHANGELOG.md +++ b/plugins/stack-overflow/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-stack-overflow +## 0.1.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-home@0.4.27-next.1 + - @backstage/plugin-search-common@1.1.1-next.0 + ## 0.1.7-next.0 ### Patch Changes diff --git a/plugins/stack-overflow/api-report.md b/plugins/stack-overflow/api-report.md index 81cfe1395b..9af9231094 100644 --- a/plugins/stack-overflow/api-report.md +++ b/plugins/stack-overflow/api-report.md @@ -44,5 +44,6 @@ export type StackOverflowQuestionsRequestParams = { export const StackOverflowSearchResultListItem: (props: { result: any; icon?: ReactNode; + rank?: number | undefined; }) => JSX.Element; ``` diff --git a/plugins/stack-overflow/package.json b/plugins/stack-overflow/package.json index 2b0910bbae..d9748e41dd 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.7-next.0", + "version": "0.1.7-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -48,7 +48,7 @@ "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist", diff --git a/plugins/stack-overflow/src/search/StackOverflowSearchResultListItem/StackOverflowSearchResultListItem.test.tsx b/plugins/stack-overflow/src/search/StackOverflowSearchResultListItem/StackOverflowSearchResultListItem.test.tsx index 61e901591e..9e27149efb 100644 --- a/plugins/stack-overflow/src/search/StackOverflowSearchResultListItem/StackOverflowSearchResultListItem.test.tsx +++ b/plugins/stack-overflow/src/search/StackOverflowSearchResultListItem/StackOverflowSearchResultListItem.test.tsx @@ -15,9 +15,15 @@ */ import React from 'react'; -import { renderInTestApp } from '@backstage/test-utils'; +import { + MockAnalyticsApi, + renderInTestApp, + TestApiProvider, +} from '@backstage/test-utils'; +import userEvent from '@testing-library/user-event'; import { screen } from '@testing-library/react'; import { StackOverflowSearchResultListItem } from './StackOverflowSearchResultListItem'; +import { analyticsApiRef } from '@backstage/core-plugin-api'; describe('', () => { it('should render without exploding', async () => { @@ -40,4 +46,36 @@ describe('', () => { screen.getByText(/Customizing Spotify backstage UI/i).closest('a'), ).toHaveAttribute('href', 'https://stackoverflow.com/questions/7'); }); + + it('should capture analytics for rank', async () => { + const analyticsSpy = new MockAnalyticsApi(); + + await renderInTestApp( + + + , + , + ); + + await userEvent.click( + screen.getByText(/Customizing Spotify backstage UI/i), + ); + + expect(analyticsSpy.getEvents()[0]).toMatchObject({ + action: 'discover', + attributes: { to: 'https://stackoverflow.com/questions/7' }, + context: { extension: 'App', pluginId: 'root', routeRef: 'unknown' }, + subject: 'Customizing Spotify backstage UI', + value: 1, + }); + }); }); diff --git a/plugins/stack-overflow/src/search/StackOverflowSearchResultListItem/StackOverflowSearchResultListItem.tsx b/plugins/stack-overflow/src/search/StackOverflowSearchResultListItem/StackOverflowSearchResultListItem.tsx index c793939593..581fe34dfb 100644 --- a/plugins/stack-overflow/src/search/StackOverflowSearchResultListItem/StackOverflowSearchResultListItem.tsx +++ b/plugins/stack-overflow/src/search/StackOverflowSearchResultListItem/StackOverflowSearchResultListItem.tsx @@ -25,19 +25,29 @@ import { Box, Chip, } from '@material-ui/core'; +import { useAnalytics } from '@backstage/core-plugin-api'; type StackOverflowSearchResultListItemProps = { result: any; // TODO(emmaindal): type to StackOverflowDocument. icon?: React.ReactNode; + rank?: number; }; export const StackOverflowSearchResultListItem = ( props: StackOverflowSearchResultListItemProps, ) => { const { location, title, text, answers, tags } = props.result; + const analytics = useAnalytics(); + + const handleClick = () => { + analytics.captureEvent('discover', title, { + attributes: { to: location }, + value: props.rank, + }); + }; return ( - + {props.icon && {props.icon}} diff --git a/plugins/tech-insights-backend-module-jsonfc/CHANGELOG.md b/plugins/tech-insights-backend-module-jsonfc/CHANGELOG.md index 84a682dc8e..73e429cc3a 100644 --- a/plugins/tech-insights-backend-module-jsonfc/CHANGELOG.md +++ b/plugins/tech-insights-backend-module-jsonfc/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-tech-insights-backend-module-jsonfc +## 0.1.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-tech-insights-node@0.3.6-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/plugin-tech-insights-common@0.2.8-next.0 + ## 0.1.22-next.0 ### Patch Changes diff --git a/plugins/tech-insights-backend-module-jsonfc/package.json b/plugins/tech-insights-backend-module-jsonfc/package.json index 9a811bc65a..51e2e56f84 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.22-next.0", + "version": "0.1.22-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 b39c640ddb..d48694aa11 100644 --- a/plugins/tech-insights-backend/CHANGELOG.md +++ b/plugins/tech-insights-backend/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-tech-insights-backend +## 0.5.4-next.1 + +### Patch Changes + +- f12e9e5b8c: Add Documentation on 404 Errors +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/plugin-tech-insights-node@0.3.6-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/types@1.0.1-next.0 + - @backstage/plugin-tech-insights-common@0.2.8-next.0 + ## 0.5.4-next.0 ### Patch Changes diff --git a/plugins/tech-insights-backend/README.md b/plugins/tech-insights-backend/README.md index 26dac78db5..95fa3ccda9 100644 --- a/plugins/tech-insights-backend/README.md +++ b/plugins/tech-insights-backend/README.md @@ -213,6 +213,8 @@ and modify the `techInsights.ts` file to contain a reference to the FactChecker }); ``` +NOTE: You need a Fact Checker Factory to get access to the backend routes that will allow the facts to be checked. If you don't have a Fact Checker Factory you will see 404s and potentially other errors. + To be able to run checks, you need to additionally add individual checks into your FactChecker implementation. For examples how to add these, you can check the documentation of the individual implementation of the FactChecker #### Modifying check persistence diff --git a/plugins/tech-insights-backend/package.json b/plugins/tech-insights-backend/package.json index 6d42c1aecc..9d87dc38a2 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.4-next.0", + "version": "0.5.4-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 8173dbc132..4fa01df31c 100644 --- a/plugins/tech-insights-node/CHANGELOG.md +++ b/plugins/tech-insights-node/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-tech-insights-node +## 0.3.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/types@1.0.1-next.0 + - @backstage/plugin-tech-insights-common@0.2.8-next.0 + ## 0.3.6-next.0 ### Patch Changes diff --git a/plugins/tech-insights-node/package.json b/plugins/tech-insights-node/package.json index 7300089744..7628e3816e 100644 --- a/plugins/tech-insights-node/package.json +++ b/plugins/tech-insights-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-tech-insights-node", - "version": "0.3.6-next.0", + "version": "0.3.6-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 f60027e045..924bd3450d 100644 --- a/plugins/tech-insights/CHANGELOG.md +++ b/plugins/tech-insights/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-tech-insights +## 0.3.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/types@1.0.1-next.0 + - @backstage/plugin-catalog-react@1.2.1-next.1 + - @backstage/plugin-tech-insights-common@0.2.8-next.0 + ## 0.3.2-next.0 ### Patch Changes diff --git a/plugins/tech-insights/package.json b/plugins/tech-insights/package.json index cb9def285e..cf687a3763 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.2-next.0", + "version": "0.3.3-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -56,7 +56,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/tech-radar/CHANGELOG.md b/plugins/tech-radar/CHANGELOG.md index df5bee360a..5a028de613 100644 --- a/plugins/tech-radar/CHANGELOG.md +++ b/plugins/tech-radar/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-tech-radar +## 0.5.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/theme@0.2.16 + ## 0.5.18-next.0 ### Patch Changes diff --git a/plugins/tech-radar/package.json b/plugins/tech-radar/package.json index a4dd1f0848..ad4e84803b 100644 --- a/plugins/tech-radar/package.json +++ b/plugins/tech-radar/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-tech-radar", "description": "A Backstage plugin that lets you display a Tech Radar for your organization", - "version": "0.5.18-next.0", + "version": "0.5.18-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -59,7 +59,7 @@ "@types/node": "^16.11.26", "@types/react": "^16.13.1 || ^17.0.0", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/techdocs-addons-test-utils/CHANGELOG.md b/plugins/techdocs-addons-test-utils/CHANGELOG.md index ba3141919a..4e9bedff96 100644 --- a/plugins/techdocs-addons-test-utils/CHANGELOG.md +++ b/plugins/techdocs-addons-test-utils/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-techdocs-addons-test-utils +## 1.0.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-techdocs@1.4.0-next.2 + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-app-api@1.2.0-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/integration-react@1.1.6-next.1 + - @backstage/test-utils@1.2.2-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog@1.6.1-next.1 + - @backstage/plugin-search-react@1.2.1-next.1 + - @backstage/plugin-techdocs-react@1.0.6-next.1 + ## 1.0.6-next.1 ### Patch Changes diff --git a/plugins/techdocs-addons-test-utils/package.json b/plugins/techdocs-addons-test-utils/package.json index a7b6abd782..df41006048 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.6-next.1", + "version": "1.0.6-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -63,7 +63,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/techdocs-backend/CHANGELOG.md b/plugins/techdocs-backend/CHANGELOG.md index b038fa202f..dce071d223 100644 --- a/plugins/techdocs-backend/CHANGELOG.md +++ b/plugins/techdocs-backend/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-techdocs-backend +## 1.4.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-techdocs-node@1.4.2-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/plugin-catalog-common@1.0.8-next.0 + - @backstage/plugin-permission-common@0.7.1-next.0 + - @backstage/plugin-search-common@1.1.1-next.0 + ## 1.4.1-next.0 ### Patch Changes diff --git a/plugins/techdocs-backend/package.json b/plugins/techdocs-backend/package.json index 5e74c47d3c..9c31f79c39 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.4.1-next.0", + "version": "1.4.1-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -59,7 +59,7 @@ "@backstage/cli": "workspace:^", "@backstage/plugin-search-backend-node": "workspace:^", "@types/dockerode": "^3.3.0", - "msw": "^0.47.0", + "msw": "^0.48.0", "supertest": "^6.1.3" }, "files": [ diff --git a/plugins/techdocs-module-addons-contrib/CHANGELOG.md b/plugins/techdocs-module-addons-contrib/CHANGELOG.md index c56e9cbf12..33139a90ed 100644 --- a/plugins/techdocs-module-addons-contrib/CHANGELOG.md +++ b/plugins/techdocs-module-addons-contrib/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-techdocs-module-addons-contrib +## 1.0.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/integration-react@1.1.6-next.1 + - @backstage/theme@0.2.16 + - @backstage/plugin-techdocs-react@1.0.6-next.1 + ## 1.0.6-next.0 ### Patch Changes diff --git a/plugins/techdocs-module-addons-contrib/package.json b/plugins/techdocs-module-addons-contrib/package.json index 782273e8c0..85255010be 100644 --- a/plugins/techdocs-module-addons-contrib/package.json +++ b/plugins/techdocs-module-addons-contrib/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-techdocs-module-addons-contrib", "description": "Plugin module for contributed TechDocs Addons", - "version": "1.0.6-next.0", + "version": "1.0.6-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -61,7 +61,7 @@ "@types/node": "^16.11.26", "@types/react": "^16.13.1 || ^17.0.0", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/techdocs-node/CHANGELOG.md b/plugins/techdocs-node/CHANGELOG.md index cc8770c34b..cddc42e91b 100644 --- a/plugins/techdocs-node/CHANGELOG.md +++ b/plugins/techdocs-node/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-techdocs-node +## 1.4.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/plugin-search-common@1.1.1-next.0 + ## 1.4.2-next.0 ### Patch Changes diff --git a/plugins/techdocs-node/package.json b/plugins/techdocs-node/package.json index eef2da8ccb..b43e5eed82 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.4.2-next.0", + "version": "1.4.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 9418517a6c..5c5b289d77 100644 --- a/plugins/techdocs-react/CHANGELOG.md +++ b/plugins/techdocs-react/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-techdocs-react +## 1.0.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/version-bridge@1.0.1 + ## 1.0.6-next.0 ### Patch Changes diff --git a/plugins/techdocs-react/package.json b/plugins/techdocs-react/package.json index d7ff40bed8..9dead41490 100644 --- a/plugins/techdocs-react/package.json +++ b/plugins/techdocs-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-techdocs-react", "description": "Shared frontend utilities for TechDocs and Addons", - "version": "1.0.6-next.0", + "version": "1.0.6-next.1", "publishConfig": { "access": "public", "alphaTypes": "dist/index.alpha.d.ts", diff --git a/plugins/techdocs-react/src/context.test.tsx b/plugins/techdocs-react/src/context.test.tsx index 6cc5537d9e..4800204f36 100644 --- a/plugins/techdocs-react/src/context.test.tsx +++ b/plugins/techdocs-react/src/context.test.tsx @@ -19,9 +19,13 @@ import { renderHook, act } from '@testing-library/react-hooks'; import { ThemeProvider } from '@material-ui/core'; import { lightTheme } from '@backstage/theme'; -import { TestApiProvider } from '@backstage/test-utils'; +import { MockAnalyticsApi, TestApiProvider } from '@backstage/test-utils'; import { Entity, CompoundEntityRef } from '@backstage/catalog-model'; -import { configApiRef } from '@backstage/core-plugin-api'; +import { + analyticsApiRef, + configApiRef, + useAnalytics, +} from '@backstage/core-plugin-api'; import { techdocsApiRef } from './api'; import { useTechDocsReaderPage, TechDocsReaderPageProvider } from './context'; @@ -60,6 +64,8 @@ const configApiMock = { getOptionalBoolean: jest.fn().mockReturnValue(undefined), }; +const analyticsApiMock = new MockAnalyticsApi(); + const wrapper = ({ entityRef = { kind: mockEntityMetadata.kind, @@ -74,6 +80,7 @@ const wrapper = ({ { + beforeEach(() => { + jest.clearAllMocks(); + }); + it('should set title', async () => { const { result, waitForNextUpdate } = renderHook( () => useTechDocsReaderPage(), @@ -157,4 +168,21 @@ describe('useTechDocsReaderPage', () => { expect(result.current.entityRef).toStrictEqual(caseSensitiveEntityRef); }); + + it('entityRef provided as analytics context', async () => { + const { waitForNextUpdate } = renderHook( + () => useAnalytics().captureEvent('action', 'subject'), + { wrapper }, + ); + + await waitForNextUpdate(); + + expect(analyticsApiMock.getEvents()[0]).toMatchObject({ + action: 'action', + subject: 'subject', + context: { + entityRef: 'component:default/test', + }, + }); + }); }); diff --git a/plugins/techdocs-react/src/context.tsx b/plugins/techdocs-react/src/context.tsx index 66faf858fa..2a5b151824 100644 --- a/plugins/techdocs-react/src/context.tsx +++ b/plugins/techdocs-react/src/context.tsx @@ -33,7 +33,11 @@ import { createVersionedValueMap, } from '@backstage/version-bridge'; -import { configApiRef, useApi } from '@backstage/core-plugin-api'; +import { + AnalyticsContext, + configApiRef, + useApi, +} from '@backstage/core-plugin-api'; import { techdocsApiRef } from './api'; import { TechDocsEntityMetadata, TechDocsMetadata } from './types'; @@ -141,9 +145,13 @@ export const TechDocsReaderPageProvider = memo( const versionedValue = createVersionedValueMap({ 1: value }); return ( - - {children instanceof Function ? children(value) : children} - + + + {children instanceof Function ? children(value) : children} + + ); }, (prevProps, nextProps) => { diff --git a/plugins/techdocs/CHANGELOG.md b/plugins/techdocs/CHANGELOG.md index d146a4d576..3ed95372a4 100644 --- a/plugins/techdocs/CHANGELOG.md +++ b/plugins/techdocs/CHANGELOG.md @@ -1,5 +1,24 @@ # @backstage/plugin-techdocs +## 1.4.0-next.2 + +### Patch Changes + +- e92aa15f01: Bumped `canvas` dependency to the latest version, which has better Node.js v18 support. +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + - @backstage/integration-react@1.1.6-next.1 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + - @backstage/plugin-search-common@1.1.1-next.0 + - @backstage/plugin-search-react@1.2.1-next.1 + - @backstage/plugin-techdocs-react@1.0.6-next.1 + ## 1.4.0-next.1 ### Patch Changes diff --git a/plugins/techdocs/package.json b/plugins/techdocs/package.json index 9eb6f6af3a..a72b13ab6e 100644 --- a/plugins/techdocs/package.json +++ b/plugins/techdocs/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-techdocs", "description": "The Backstage plugin that renders technical documentation for your components", - "version": "1.4.0-next.1", + "version": "1.4.0-next.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -78,7 +78,7 @@ "@types/node": "^16.11.26", "canvas": "^2.10.2", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist", diff --git a/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/dom.tsx b/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/dom.tsx index e886454594..9babff0c54 100644 --- a/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/dom.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/dom.tsx @@ -21,7 +21,7 @@ import { useTheme, useMediaQuery } from '@material-ui/core'; import { BackstageTheme } from '@backstage/theme'; import { CompoundEntityRef } from '@backstage/catalog-model'; -import { useApi } from '@backstage/core-plugin-api'; +import { useAnalytics, useApi } from '@backstage/core-plugin-api'; import { scmIntegrationsApiRef } from '@backstage/integration-react'; import { @@ -63,6 +63,7 @@ export const useTechDocsReaderDom = ( const isMobileMedia = useMediaQuery(MOBILE_MEDIA_QUERY); const sanitizerTransformer = useSanitizerTransformer(); const stylesTransformer = useStylesTransformer(); + const analytics = useAnalytics(); const techdocsStorageApi = useApi(techdocsStorageApiRef); const scmIntegrationsApi = useApi(scmIntegrationsApiRef); @@ -177,6 +178,12 @@ export const useTechDocsReaderDom = ( const parsedUrl = new URL(url); const fullPath = `${parsedUrl.pathname}${parsedUrl.search}${parsedUrl.hash}`; + // capture link clicks within documentation + const linkText = + (event.target as HTMLAnchorElement | undefined)?.innerText || url; + const to = url.replace(window.location.origin, ''); + analytics.captureEvent('click', linkText, { attributes: { to } }); + // hash exists when anchor is clicked on secondary sidebar if (parsedUrl.hash) { if (modifierActive) { @@ -219,7 +226,7 @@ export const useTechDocsReaderDom = ( onLoaded: () => {}, }), ]), - [theme, navigate], + [theme, navigate, analytics], ); useEffect(() => { diff --git a/plugins/techdocs/src/reader/components/TechDocsReaderPageHeader/TechDocsReaderPageHeader.tsx b/plugins/techdocs/src/reader/components/TechDocsReaderPageHeader/TechDocsReaderPageHeader.tsx index e76cb1d173..b7b297591d 100644 --- a/plugins/techdocs/src/reader/components/TechDocsReaderPageHeader/TechDocsReaderPageHeader.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsReaderPageHeader/TechDocsReaderPageHeader.tsx @@ -81,7 +81,7 @@ export const TechDocsReaderPageHeader = ( setSubtitle(() => { let { site_description } = metadata; if (!site_description || site_description === 'None') { - site_description = 'Home'; + site_description = ''; } return site_description; }); @@ -155,7 +155,7 @@ export const TechDocsReaderPageHeader = ( type="Documentation" typeLink={docsRootLink} title={title || skeleton} - subtitle={subtitle || skeleton} + subtitle={subtitle === '' ? undefined : subtitle || skeleton} > {tabTitle} diff --git a/plugins/todo-backend/CHANGELOG.md b/plugins/todo-backend/CHANGELOG.md index f4827591df..47b3b3d42b 100644 --- a/plugins/todo-backend/CHANGELOG.md +++ b/plugins/todo-backend/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-todo-backend +## 0.1.35-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/catalog-client@1.1.2-next.0 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/integration@1.4.0-next.0 + ## 0.1.35-next.0 ### Patch Changes diff --git a/plugins/todo-backend/package.json b/plugins/todo-backend/package.json index ae227478b6..10762a501b 100644 --- a/plugins/todo-backend/package.json +++ b/plugins/todo-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-todo-backend", "description": "A Backstage backend plugin that lets you browse TODO comments in your source code", - "version": "0.1.35-next.0", + "version": "0.1.35-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -45,7 +45,7 @@ "devDependencies": { "@backstage/cli": "workspace:^", "@types/supertest": "^2.0.8", - "msw": "^0.47.0", + "msw": "^0.48.0", "supertest": "^6.1.3" }, "files": [ diff --git a/plugins/todo/CHANGELOG.md b/plugins/todo/CHANGELOG.md index c97576555d..8729bc8ee7 100644 --- a/plugins/todo/CHANGELOG.md +++ b/plugins/todo/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-todo +## 0.2.13-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.2.13-next.0 ### Patch Changes diff --git a/plugins/todo/package.json b/plugins/todo/package.json index c5cd8df216..4e8fd21657 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.13-next.0", + "version": "0.2.13-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -54,7 +54,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/user-settings-backend/CHANGELOG.md b/plugins/user-settings-backend/CHANGELOG.md index 54a75f3888..fef6843ff0 100644 --- a/plugins/user-settings-backend/CHANGELOG.md +++ b/plugins/user-settings-backend/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-user-settings-backend +## 0.1.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/plugin-auth-node@0.2.7-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/types@1.0.1-next.0 + ## 0.1.2-next.0 ### Patch Changes diff --git a/plugins/user-settings-backend/package.json b/plugins/user-settings-backend/package.json index 5015b60456..b648159b9c 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.1.2-next.0", + "version": "0.1.2-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 d73d533cba..f81cbbe831 100644 --- a/plugins/user-settings/CHANGELOG.md +++ b/plugins/user-settings/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-user-settings +## 0.5.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-app-api@1.2.0-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/types@1.0.1-next.0 + ## 0.5.1-next.0 ### Patch Changes diff --git a/plugins/user-settings/package.json b/plugins/user-settings/package.json index 744cf40eec..b70002c177 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.5.1-next.0", + "version": "0.5.1-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -58,7 +58,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/vault-backend/CHANGELOG.md b/plugins/vault-backend/CHANGELOG.md index 6f3270dba1..02986aff92 100644 --- a/plugins/vault-backend/CHANGELOG.md +++ b/plugins/vault-backend/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-vault-backend +## 0.2.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.16.0-next.1 + - @backstage/backend-tasks@0.3.7-next.1 + - @backstage/backend-test-utils@0.1.30-next.1 + - @backstage/config@1.0.4-next.0 + - @backstage/errors@1.1.3-next.0 + ## 0.2.4-next.0 ### Patch Changes diff --git a/plugins/vault-backend/package.json b/plugins/vault-backend/package.json index 2cc170337a..7eeb568cf9 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.2.4-next.0", + "version": "0.2.4-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -53,7 +53,7 @@ "@backstage/cli": "workspace:^", "@types/compression": "^1.7.2", "@types/supertest": "^2.0.8", - "msw": "^0.47.0", + "msw": "^0.48.0", "supertest": "^6.1.6" }, "files": [ diff --git a/plugins/vault/CHANGELOG.md b/plugins/vault/CHANGELOG.md index ce0f6c41cf..ec9b7bf25f 100644 --- a/plugins/vault/CHANGELOG.md +++ b/plugins/vault/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-vault +## 0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/catalog-model@1.1.3-next.0 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + - @backstage/plugin-catalog-react@1.2.1-next.1 + ## 0.1.5-next.0 ### Patch Changes diff --git a/plugins/vault/package.json b/plugins/vault/package.json index dc5e7b0c13..04607f21a7 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.5-next.0", + "version": "0.1.5-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -57,7 +57,7 @@ "@testing-library/user-event": "^14.0.0", "@types/node": "*", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/plugins/xcmetrics/CHANGELOG.md b/plugins/xcmetrics/CHANGELOG.md index 8c68404127..cc7938df81 100644 --- a/plugins/xcmetrics/CHANGELOG.md +++ b/plugins/xcmetrics/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-xcmetrics +## 0.2.31-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.0-next.1 + - @backstage/core-plugin-api@1.1.0-next.0 + - @backstage/errors@1.1.3-next.0 + - @backstage/theme@0.2.16 + ## 0.2.31-next.0 ### Patch Changes diff --git a/plugins/xcmetrics/package.json b/plugins/xcmetrics/package.json index 6946095a01..529917ee61 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.31-next.0", + "version": "0.2.31-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -49,7 +49,7 @@ "@types/luxon": "^3.0.0", "@types/node": "^16.11.26", "cross-fetch": "^3.1.5", - "msw": "^0.47.0" + "msw": "^0.48.0" }, "files": [ "dist" diff --git a/scripts/isolated-release.js b/scripts/isolated-release.js deleted file mode 100755 index 4df900450e..0000000000 --- a/scripts/isolated-release.js +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env node -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -const path = require('path'); -const childProcess = require('child_process'); -const { getPackages } = require('@manypkg/get-packages'); - -// Prepare a release of the provided packages, e.g. @backstage/core -async function main(args) { - if (args.includes('--help') || args.length === 0) { - const arg0 = path.relative(process.cwd(), process.argv[1]); - console.log(`Usage: ${process.argv0} ${arg0} ...`); - process.exit(1); - } - - const { packages } = await getPackages(__dirname); - const ignoreArgs = packages - .filter(p => !args.includes(p.packageJson.name)) - .flatMap(p => ['--ignore', p.packageJson.name]); - - const { status } = childProcess.spawnSync( - 'yarn', - ['changeset', 'version', ...ignoreArgs], - { - stdio: 'inherit', - }, - ); - if (status !== 0) { - return; - } - - childProcess.spawnSync( - 'yarn', - ['prettier', '--write', '{packages,plugins}/*/{package.json,CHANGELOG.md}'], - { - stdio: 'inherit', - }, - ); -} - -main(process.argv.slice(2)).catch(error => { - console.error(error.stack); - process.exit(1); -}); diff --git a/scripts/patch-release-for-pr.js b/scripts/patch-release-for-pr.js new file mode 100755 index 0000000000..fcfef0c6a7 --- /dev/null +++ b/scripts/patch-release-for-pr.js @@ -0,0 +1,156 @@ +#!/usr/bin/env node +/* + * 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 fs = require('fs-extra'); +const path = require('path'); +const semver = require('semver'); +const { Octokit } = require('@octokit/rest'); +const { execFile: execFileCb } = require('child_process'); +const { promisify } = require('util'); + +const execFile = promisify(execFileCb); + +const owner = 'backstage'; +const repo = 'backstage'; +const rootDir = path.resolve(__dirname, '..'); + +const octokit = new Octokit({ + auth: process.env.GITHUB_TOKEN, +}); + +async function run(command, ...args) { + const { stdout, stderr } = await execFile(command, args, { + cwd: rootDir, + }); + + if (stderr) { + console.error(stderr); + } + + return stdout.trim(); +} + +/** + * Finds the current stable release version of the repo, looking at + * the current commit and backwards, finding the first commit were a + * stable version is present. + */ +async function findCurrentReleaseVersion() { + const rootPkgPath = path.resolve(rootDir, 'package.json'); + const pkg = await fs.readJson(rootPkgPath); + + if (!semver.prerelease(pkg.version)) { + return pkg.version; + } + + const { stdout: revListStr } = await execFile('git', [ + 'rev-list', + 'HEAD', + '--', + 'package.json', + ]); + const revList = revListStr.trim().split(/\r?\n/); + + for (const rev of revList) { + const { stdout: pkgJsonStr } = await execFile('git', [ + 'show', + `${rev}:package.json`, + ]); + if (pkgJsonStr) { + const pkgJson = JSON.parse(pkgJsonStr); + if (!semver.prerelease(pkgJson.version)) { + return pkgJson.version; + } + } + } + + throw new Error('No stable release found'); +} + +async function main(prNumberStr) { + const prNumber = parseInt(prNumberStr, 10); + if (!Number.isInteger(prNumber)) { + throw new Error('Must provide a PR number as the first argument'); + } + console.log(`PR number: ${prNumber}`); + + if (await run('git', 'status', '--porcelain')) { + throw new Error('Cannot run with a dirty working tree'); + } + + const release = await findCurrentReleaseVersion(); + console.log(`Patching release ${release}`); + + await run('git', 'fetch'); + + const patchBranch = `patch/v${release}`; + try { + await run('git', 'checkout', `origin/${patchBranch}`); + } catch { + await run('git', 'checkout', '-b', patchBranch, `v${release}`); + await run('git', 'push', 'origin', '-u', patchBranch); + } + + const { data } = await octokit.pulls.get({ + owner, + repo, + pull_number: prNumber, + }); + + const headSha = data.head.sha; + if (!headSha) { + throw new Error('head sha not available'); + } + const baseSha = data.base.sha; + if (!baseSha) { + throw new Error('base sha not available'); + } + const mergeBaseSha = await run('git', 'merge-base', headSha, baseSha); + + // Create new branch, apply changes from all commits on PR branch, commit, push + const branchName = `patch-release-pr-${prNumber}`; + await run('git', 'checkout', '-b', branchName); + + const logLines = await run( + 'git', + 'log', + `${mergeBaseSha}...${headSha}`, + '--reverse', + '--pretty=%H', + ); + for (const logSha of logLines.split(/\r?\n/)) { + await run('git', 'cherry-pick', '-n', logSha); + } + await run('git', 'commit', '--signoff', '-m', `Patch from PR #${prNumber}`); + + console.log('Running "yarn release" ...'); + await run('yarn', 'release'); + + await run('git', 'add', '.'); + await run('git', 'commit', '--signoff', '-m', 'Generate Release'); + + await run('git', 'push', 'origin', '-u', branchName); + + console.log( + `https://github.com/backstage/backstage/compare/${patchBranch}...${branchName}?expand=1&body=This%20release%20fixes%20an%20issue%20where&title=Patch%20release%20of%20%23${prNumber}`, + ); +} + +main(process.argv.slice(2)).catch(error => { + console.error(error.stack || error); + process.exit(1); +}); diff --git a/scripts/prepare-release.js b/scripts/prepare-release.js index 962d54abb0..973f4fad58 100755 --- a/scripts/prepare-release.js +++ b/scripts/prepare-release.js @@ -209,7 +209,11 @@ async function applyPatchVersions(repo, patchVersions) { const deps = packageJson[depType]; for (const depName of Object.keys(deps ?? {})) { const currentRange = deps[depName]; - if (currentRange === '*' || currentRange === '') { + if ( + currentRange === '*' || + currentRange === '' || + currentRange.startsWith('workspace:') + ) { continue; } diff --git a/storybook/yarn.lock b/storybook/yarn.lock index c864d817ab..f6b5be55d0 100644 --- a/storybook/yarn.lock +++ b/storybook/yarn.lock @@ -3107,90 +3107,90 @@ __metadata: languageName: node linkType: hard -"@swc/core-darwin-arm64@npm:1.3.14": - version: 1.3.14 - resolution: "@swc/core-darwin-arm64@npm:1.3.14" +"@swc/core-darwin-arm64@npm:1.3.16": + version: 1.3.16 + resolution: "@swc/core-darwin-arm64@npm:1.3.16" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@swc/core-darwin-x64@npm:1.3.14": - version: 1.3.14 - resolution: "@swc/core-darwin-x64@npm:1.3.14" +"@swc/core-darwin-x64@npm:1.3.16": + version: 1.3.16 + resolution: "@swc/core-darwin-x64@npm:1.3.16" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@swc/core-linux-arm-gnueabihf@npm:1.3.14": - version: 1.3.14 - resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.14" +"@swc/core-linux-arm-gnueabihf@npm:1.3.16": + version: 1.3.16 + resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.16" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@swc/core-linux-arm64-gnu@npm:1.3.14": - version: 1.3.14 - resolution: "@swc/core-linux-arm64-gnu@npm:1.3.14" +"@swc/core-linux-arm64-gnu@npm:1.3.16": + version: 1.3.16 + resolution: "@swc/core-linux-arm64-gnu@npm:1.3.16" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-arm64-musl@npm:1.3.14": - version: 1.3.14 - resolution: "@swc/core-linux-arm64-musl@npm:1.3.14" +"@swc/core-linux-arm64-musl@npm:1.3.16": + version: 1.3.16 + resolution: "@swc/core-linux-arm64-musl@npm:1.3.16" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@swc/core-linux-x64-gnu@npm:1.3.14": - version: 1.3.14 - resolution: "@swc/core-linux-x64-gnu@npm:1.3.14" +"@swc/core-linux-x64-gnu@npm:1.3.16": + version: 1.3.16 + resolution: "@swc/core-linux-x64-gnu@npm:1.3.16" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-x64-musl@npm:1.3.14": - version: 1.3.14 - resolution: "@swc/core-linux-x64-musl@npm:1.3.14" +"@swc/core-linux-x64-musl@npm:1.3.16": + version: 1.3.16 + resolution: "@swc/core-linux-x64-musl@npm:1.3.16" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@swc/core-win32-arm64-msvc@npm:1.3.14": - version: 1.3.14 - resolution: "@swc/core-win32-arm64-msvc@npm:1.3.14" +"@swc/core-win32-arm64-msvc@npm:1.3.16": + version: 1.3.16 + resolution: "@swc/core-win32-arm64-msvc@npm:1.3.16" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@swc/core-win32-ia32-msvc@npm:1.3.14": - version: 1.3.14 - resolution: "@swc/core-win32-ia32-msvc@npm:1.3.14" +"@swc/core-win32-ia32-msvc@npm:1.3.16": + version: 1.3.16 + resolution: "@swc/core-win32-ia32-msvc@npm:1.3.16" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@swc/core-win32-x64-msvc@npm:1.3.14": - version: 1.3.14 - resolution: "@swc/core-win32-x64-msvc@npm:1.3.14" +"@swc/core-win32-x64-msvc@npm:1.3.16": + version: 1.3.16 + resolution: "@swc/core-win32-x64-msvc@npm:1.3.16" conditions: os=win32 & cpu=x64 languageName: node linkType: hard "@swc/core@npm:^1.3.9": - version: 1.3.14 - resolution: "@swc/core@npm:1.3.14" + version: 1.3.16 + resolution: "@swc/core@npm:1.3.16" dependencies: - "@swc/core-darwin-arm64": 1.3.14 - "@swc/core-darwin-x64": 1.3.14 - "@swc/core-linux-arm-gnueabihf": 1.3.14 - "@swc/core-linux-arm64-gnu": 1.3.14 - "@swc/core-linux-arm64-musl": 1.3.14 - "@swc/core-linux-x64-gnu": 1.3.14 - "@swc/core-linux-x64-musl": 1.3.14 - "@swc/core-win32-arm64-msvc": 1.3.14 - "@swc/core-win32-ia32-msvc": 1.3.14 - "@swc/core-win32-x64-msvc": 1.3.14 + "@swc/core-darwin-arm64": 1.3.16 + "@swc/core-darwin-x64": 1.3.16 + "@swc/core-linux-arm-gnueabihf": 1.3.16 + "@swc/core-linux-arm64-gnu": 1.3.16 + "@swc/core-linux-arm64-musl": 1.3.16 + "@swc/core-linux-x64-gnu": 1.3.16 + "@swc/core-linux-x64-musl": 1.3.16 + "@swc/core-win32-arm64-msvc": 1.3.16 + "@swc/core-win32-ia32-msvc": 1.3.16 + "@swc/core-win32-x64-msvc": 1.3.16 dependenciesMeta: "@swc/core-darwin-arm64": optional: true @@ -3214,7 +3214,7 @@ __metadata: optional: true bin: swcx: run_swcx.js - checksum: 79e9857ee3d5af22d9a6e644d7608594fa8ccd9102dbc088addc0f6ee9e1e8e3fc8835545730707395aa47197ab119fa323aedf4184cf51892379b307aedddc0 + checksum: 4361252c928c487a02f526aecd8f3072b923244234c2701916944cf13c252b6d5ce2466caf3e0797d3e92e71a89d4a044f8577e51e8f7fe3af0fe30d94e94b13 languageName: node linkType: hard diff --git a/yarn.lock b/yarn.lock index 6e9fba135e..0841181a34 100644 --- a/yarn.lock +++ b/yarn.lock @@ -303,9 +303,9 @@ __metadata: languageName: node linkType: hard -"@asyncapi/react-component@npm:1.0.0-next.43": - version: 1.0.0-next.43 - resolution: "@asyncapi/react-component@npm:1.0.0-next.43" +"@asyncapi/react-component@npm:1.0.0-next.44": + version: 1.0.0-next.44 + resolution: "@asyncapi/react-component@npm:1.0.0-next.44" dependencies: "@asyncapi/avro-schema-parser": ^0.3.0 "@asyncapi/openapi-schema-parser": ^2.0.0 @@ -319,7 +319,7 @@ __metadata: peerDependencies: react: ">=16.8.0" react-dom: ">=16.8.0" - checksum: d19adc2b6e674633457da28d38636df4cf9891f4038827b52f2737699d064bcf0d3be707e9f3284852d1bb507f3f36df9ec3bb02fd6f901cfda7a1f49ea9c5da + checksum: 1d96db3bc6a4655884969a7639467836376c028df1a00f8930adf4e1b6ecb43e6a2d61df5c68e63d6c105d319fecb3f2ac0e4146274a81a874fbde17f4dbac1c languageName: node linkType: hard @@ -330,6 +330,790 @@ __metadata: languageName: node linkType: hard +"@aws-crypto/ie11-detection@npm:^2.0.0": + version: 2.0.2 + resolution: "@aws-crypto/ie11-detection@npm:2.0.2" + dependencies: + tslib: ^1.11.1 + checksum: 713293deea8eefd3ab43dc05e62228571d27754e7293f8ec2fd8a0c693fbbfc55213e6599387776e3cdbc951965dc62e24e92b9c4a853e4a50d00ae6a9f6b2bd + languageName: node + linkType: hard + +"@aws-crypto/sha256-browser@npm:2.0.0": + version: 2.0.0 + resolution: "@aws-crypto/sha256-browser@npm:2.0.0" + dependencies: + "@aws-crypto/ie11-detection": ^2.0.0 + "@aws-crypto/sha256-js": ^2.0.0 + "@aws-crypto/supports-web-crypto": ^2.0.0 + "@aws-crypto/util": ^2.0.0 + "@aws-sdk/types": ^3.1.0 + "@aws-sdk/util-locate-window": ^3.0.0 + "@aws-sdk/util-utf8-browser": ^3.0.0 + tslib: ^1.11.1 + checksum: 7bc1ff042d0c53a46c0fc3824bd97fb3ed1df7dc030b8a995889471052860b8c8ade469c97866fafd8249a3144d0f48b0f1054f357e2b403606009381c4b8f0e + languageName: node + linkType: hard + +"@aws-crypto/sha256-js@npm:2.0.0": + version: 2.0.0 + resolution: "@aws-crypto/sha256-js@npm:2.0.0" + dependencies: + "@aws-crypto/util": ^2.0.0 + "@aws-sdk/types": ^3.1.0 + tslib: ^1.11.1 + checksum: e4abf9baec6bed19d380f92a999a41ac5bdd8890dfd45971d29054c298854c5b7087e7de633413f2e64618ef8238ccf4c0b75797c73063c74bbba3cb5d8b2581 + languageName: node + linkType: hard + +"@aws-crypto/sha256-js@npm:^2.0.0": + version: 2.0.2 + resolution: "@aws-crypto/sha256-js@npm:2.0.2" + dependencies: + "@aws-crypto/util": ^2.0.2 + "@aws-sdk/types": ^3.110.0 + tslib: ^1.11.1 + checksum: 9125ec65a2b05fce908ac2289ba97b995a299f2d717684804211df8e8bcffd8cd9b8861582240655b88f2255c46fcee34026f75c057ffb22f44b6a76cd43f65a + languageName: node + linkType: hard + +"@aws-crypto/supports-web-crypto@npm:^2.0.0": + version: 2.0.2 + resolution: "@aws-crypto/supports-web-crypto@npm:2.0.2" + dependencies: + tslib: ^1.11.1 + checksum: 03d04d29292dc1b76db9bc6becd05f52fa79adee0ec084f971b0767f7e73250dd0422bea57636015f8c27f38aefcd1d9c58800a4749cf35339296c8d670f3ccb + languageName: node + linkType: hard + +"@aws-crypto/util@npm:^2.0.0, @aws-crypto/util@npm:^2.0.2": + version: 2.0.2 + resolution: "@aws-crypto/util@npm:2.0.2" + dependencies: + "@aws-sdk/types": ^3.110.0 + "@aws-sdk/util-utf8-browser": ^3.0.0 + tslib: ^1.11.1 + checksum: 13cb33a39005b09c062398d361043c2224bc8ba42b1432bad52e15bc4bf9ffad4facdddc394b3cc71b3fb8d86a7ec325fd1afa107b5fde0dab84a7e32d311d7f + languageName: node + linkType: hard + +"@aws-sdk/abort-controller@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/abort-controller@npm:3.183.0" + dependencies: + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: 28f5bc16b5aba414e354df603bc8becd010aa8c9b3c79e527130723a39f21d5a3df98c3bafb3cea733d415a5b042af90098ffa9dfa29d400114c2f6f5292524e + languageName: node + linkType: hard + +"@aws-sdk/client-sqs@npm:^3.0.0": + version: 3.183.0 + resolution: "@aws-sdk/client-sqs@npm:3.183.0" + dependencies: + "@aws-crypto/sha256-browser": 2.0.0 + "@aws-crypto/sha256-js": 2.0.0 + "@aws-sdk/client-sts": 3.183.0 + "@aws-sdk/config-resolver": 3.183.0 + "@aws-sdk/credential-provider-node": 3.183.0 + "@aws-sdk/fetch-http-handler": 3.183.0 + "@aws-sdk/hash-node": 3.183.0 + "@aws-sdk/invalid-dependency": 3.183.0 + "@aws-sdk/md5-js": 3.183.0 + "@aws-sdk/middleware-content-length": 3.183.0 + "@aws-sdk/middleware-host-header": 3.183.0 + "@aws-sdk/middleware-logger": 3.183.0 + "@aws-sdk/middleware-recursion-detection": 3.183.0 + "@aws-sdk/middleware-retry": 3.183.0 + "@aws-sdk/middleware-sdk-sqs": 3.183.0 + "@aws-sdk/middleware-serde": 3.183.0 + "@aws-sdk/middleware-signing": 3.183.0 + "@aws-sdk/middleware-stack": 3.183.0 + "@aws-sdk/middleware-user-agent": 3.183.0 + "@aws-sdk/node-config-provider": 3.183.0 + "@aws-sdk/node-http-handler": 3.183.0 + "@aws-sdk/protocol-http": 3.183.0 + "@aws-sdk/smithy-client": 3.183.0 + "@aws-sdk/types": 3.183.0 + "@aws-sdk/url-parser": 3.183.0 + "@aws-sdk/util-base64-browser": 3.183.0 + "@aws-sdk/util-base64-node": 3.183.0 + "@aws-sdk/util-body-length-browser": 3.183.0 + "@aws-sdk/util-body-length-node": 3.183.0 + "@aws-sdk/util-defaults-mode-browser": 3.183.0 + "@aws-sdk/util-defaults-mode-node": 3.183.0 + "@aws-sdk/util-user-agent-browser": 3.183.0 + "@aws-sdk/util-user-agent-node": 3.183.0 + "@aws-sdk/util-utf8-browser": 3.183.0 + "@aws-sdk/util-utf8-node": 3.183.0 + entities: 2.2.0 + fast-xml-parser: 3.19.0 + tslib: ^2.3.1 + checksum: fe0a7ba53cac4d52c25a4a4f1a1bb16438d5011347fcfec037df1d73379d750cd47b437f7a45aea2d4e29bc92587b51dd7631a06f5d6881e3b67b2d4c0dd2633 + languageName: node + linkType: hard + +"@aws-sdk/client-sso@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/client-sso@npm:3.183.0" + dependencies: + "@aws-crypto/sha256-browser": 2.0.0 + "@aws-crypto/sha256-js": 2.0.0 + "@aws-sdk/config-resolver": 3.183.0 + "@aws-sdk/fetch-http-handler": 3.183.0 + "@aws-sdk/hash-node": 3.183.0 + "@aws-sdk/invalid-dependency": 3.183.0 + "@aws-sdk/middleware-content-length": 3.183.0 + "@aws-sdk/middleware-host-header": 3.183.0 + "@aws-sdk/middleware-logger": 3.183.0 + "@aws-sdk/middleware-recursion-detection": 3.183.0 + "@aws-sdk/middleware-retry": 3.183.0 + "@aws-sdk/middleware-serde": 3.183.0 + "@aws-sdk/middleware-stack": 3.183.0 + "@aws-sdk/middleware-user-agent": 3.183.0 + "@aws-sdk/node-config-provider": 3.183.0 + "@aws-sdk/node-http-handler": 3.183.0 + "@aws-sdk/protocol-http": 3.183.0 + "@aws-sdk/smithy-client": 3.183.0 + "@aws-sdk/types": 3.183.0 + "@aws-sdk/url-parser": 3.183.0 + "@aws-sdk/util-base64-browser": 3.183.0 + "@aws-sdk/util-base64-node": 3.183.0 + "@aws-sdk/util-body-length-browser": 3.183.0 + "@aws-sdk/util-body-length-node": 3.183.0 + "@aws-sdk/util-defaults-mode-browser": 3.183.0 + "@aws-sdk/util-defaults-mode-node": 3.183.0 + "@aws-sdk/util-user-agent-browser": 3.183.0 + "@aws-sdk/util-user-agent-node": 3.183.0 + "@aws-sdk/util-utf8-browser": 3.183.0 + "@aws-sdk/util-utf8-node": 3.183.0 + tslib: ^2.3.1 + checksum: 6909329cf87c1a0c830fa9657e04c7e1ae496d7d79cc0a6813999503ae809f245f0b879af1d5564a5d97c2c69583c8a4df702d29ec7dc75934d98a0cdf017ad3 + languageName: node + linkType: hard + +"@aws-sdk/client-sts@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/client-sts@npm:3.183.0" + dependencies: + "@aws-crypto/sha256-browser": 2.0.0 + "@aws-crypto/sha256-js": 2.0.0 + "@aws-sdk/config-resolver": 3.183.0 + "@aws-sdk/credential-provider-node": 3.183.0 + "@aws-sdk/fetch-http-handler": 3.183.0 + "@aws-sdk/hash-node": 3.183.0 + "@aws-sdk/invalid-dependency": 3.183.0 + "@aws-sdk/middleware-content-length": 3.183.0 + "@aws-sdk/middleware-host-header": 3.183.0 + "@aws-sdk/middleware-logger": 3.183.0 + "@aws-sdk/middleware-recursion-detection": 3.183.0 + "@aws-sdk/middleware-retry": 3.183.0 + "@aws-sdk/middleware-sdk-sts": 3.183.0 + "@aws-sdk/middleware-serde": 3.183.0 + "@aws-sdk/middleware-signing": 3.183.0 + "@aws-sdk/middleware-stack": 3.183.0 + "@aws-sdk/middleware-user-agent": 3.183.0 + "@aws-sdk/node-config-provider": 3.183.0 + "@aws-sdk/node-http-handler": 3.183.0 + "@aws-sdk/protocol-http": 3.183.0 + "@aws-sdk/smithy-client": 3.183.0 + "@aws-sdk/types": 3.183.0 + "@aws-sdk/url-parser": 3.183.0 + "@aws-sdk/util-base64-browser": 3.183.0 + "@aws-sdk/util-base64-node": 3.183.0 + "@aws-sdk/util-body-length-browser": 3.183.0 + "@aws-sdk/util-body-length-node": 3.183.0 + "@aws-sdk/util-defaults-mode-browser": 3.183.0 + "@aws-sdk/util-defaults-mode-node": 3.183.0 + "@aws-sdk/util-user-agent-browser": 3.183.0 + "@aws-sdk/util-user-agent-node": 3.183.0 + "@aws-sdk/util-utf8-browser": 3.183.0 + "@aws-sdk/util-utf8-node": 3.183.0 + entities: 2.2.0 + fast-xml-parser: 3.19.0 + tslib: ^2.3.1 + checksum: d4492e537803d64e5fc0c5db8ac3a3788204aadc14b21e4fb407188feb58b35689c4a6878b4f13123a5f35f7e9fa01d95d427be168aeec9072aea881f2a92fb7 + languageName: node + linkType: hard + +"@aws-sdk/config-resolver@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/config-resolver@npm:3.183.0" + dependencies: + "@aws-sdk/signature-v4": 3.183.0 + "@aws-sdk/types": 3.183.0 + "@aws-sdk/util-config-provider": 3.183.0 + "@aws-sdk/util-middleware": 3.183.0 + tslib: ^2.3.1 + checksum: 1be0ab79d5019f7502a7aee8c740f4e381ab7501ed639569526a4a7e1c70ad6bb36d642a8a2b18afe58c34497c6f2f8244dbf05211a0f6bc9a57e5e379c70b2b + languageName: node + linkType: hard + +"@aws-sdk/credential-provider-env@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/credential-provider-env@npm:3.183.0" + dependencies: + "@aws-sdk/property-provider": 3.183.0 + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: 4281e14c286cc5c57c69ba88c49fe1c1ff61f27923db5e8f852a84cce02b40fdc938f876ad08e72005deae9a28fab7400f747f63ca50f9c4d60e04e6c2705205 + languageName: node + linkType: hard + +"@aws-sdk/credential-provider-imds@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/credential-provider-imds@npm:3.183.0" + dependencies: + "@aws-sdk/node-config-provider": 3.183.0 + "@aws-sdk/property-provider": 3.183.0 + "@aws-sdk/types": 3.183.0 + "@aws-sdk/url-parser": 3.183.0 + tslib: ^2.3.1 + checksum: e9fe1007b22825dc0c033beb2057b9f759d8cafec6e65d08ba4915bccb9b7d737eeccb3d06e9768a084b6726d9ea10778172b1bec695353c60276c1a5c21370e + languageName: node + linkType: hard + +"@aws-sdk/credential-provider-ini@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/credential-provider-ini@npm:3.183.0" + dependencies: + "@aws-sdk/credential-provider-env": 3.183.0 + "@aws-sdk/credential-provider-imds": 3.183.0 + "@aws-sdk/credential-provider-sso": 3.183.0 + "@aws-sdk/credential-provider-web-identity": 3.183.0 + "@aws-sdk/property-provider": 3.183.0 + "@aws-sdk/shared-ini-file-loader": 3.183.0 + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: c7784a3674c863dacc1305a08dd63cb16d1e7374250b0ceafa9feee8344de4228d7c32e84fbaa9d963adab69eb3938cd75b99554756da120cd9beae4693eded9 + languageName: node + linkType: hard + +"@aws-sdk/credential-provider-node@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/credential-provider-node@npm:3.183.0" + dependencies: + "@aws-sdk/credential-provider-env": 3.183.0 + "@aws-sdk/credential-provider-imds": 3.183.0 + "@aws-sdk/credential-provider-ini": 3.183.0 + "@aws-sdk/credential-provider-process": 3.183.0 + "@aws-sdk/credential-provider-sso": 3.183.0 + "@aws-sdk/credential-provider-web-identity": 3.183.0 + "@aws-sdk/property-provider": 3.183.0 + "@aws-sdk/shared-ini-file-loader": 3.183.0 + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: f23e1148054a96d68632284501ba01c4285cce1a2f4562817ec4b7fa315ff56e2f6b97fae0d2ae26fd52fca8c9f000be5d72a3582cff6c32ba10010f02a30977 + languageName: node + linkType: hard + +"@aws-sdk/credential-provider-process@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/credential-provider-process@npm:3.183.0" + dependencies: + "@aws-sdk/property-provider": 3.183.0 + "@aws-sdk/shared-ini-file-loader": 3.183.0 + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: 3109e79ec2b4647f5e7f78c6dc2e10cd8a34a70147e7e90549153b7ff3ff12eda3499b3189d6fc1f3b99f461d5445e8017b44cd50029d30b0fc7437ad88a5f38 + languageName: node + linkType: hard + +"@aws-sdk/credential-provider-sso@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/credential-provider-sso@npm:3.183.0" + dependencies: + "@aws-sdk/client-sso": 3.183.0 + "@aws-sdk/property-provider": 3.183.0 + "@aws-sdk/shared-ini-file-loader": 3.183.0 + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: 8775894ef50499361a4b49d846417c2c1e1ea90383730a32428154628358e7847f6f29dddd3cd04d3a4e15c1343fe10b051a92863055989ac3c4cb241e68f63a + languageName: node + linkType: hard + +"@aws-sdk/credential-provider-web-identity@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/credential-provider-web-identity@npm:3.183.0" + dependencies: + "@aws-sdk/property-provider": 3.183.0 + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: c39576c8f35137284fc69db8d94adcf07fa89d51153ee9710481262e205d485ff089a796e8a253aa14a0434dde91eadb65602fc614167a4f14301201ee840c08 + languageName: node + linkType: hard + +"@aws-sdk/fetch-http-handler@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/fetch-http-handler@npm:3.183.0" + dependencies: + "@aws-sdk/protocol-http": 3.183.0 + "@aws-sdk/querystring-builder": 3.183.0 + "@aws-sdk/types": 3.183.0 + "@aws-sdk/util-base64-browser": 3.183.0 + tslib: ^2.3.1 + checksum: 87c51d1dad8c469e32b99f6ed3729e753097cd4a9f8f417ec8681cf01e18b9a5dc6571f3cd1220293216bd4527b8499bb2ea1f821a240fde6d9560817c120066 + languageName: node + linkType: hard + +"@aws-sdk/hash-node@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/hash-node@npm:3.183.0" + dependencies: + "@aws-sdk/types": 3.183.0 + "@aws-sdk/util-buffer-from": 3.183.0 + tslib: ^2.3.1 + checksum: fbed8757df633620807594535e3bb7d387576e0c2f89ad16dc7c98405a9d1d9743bea50148186de2f19cac67144b30f7f89e6c15317ddd7b8c0c8f61ca9556ef + languageName: node + linkType: hard + +"@aws-sdk/invalid-dependency@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/invalid-dependency@npm:3.183.0" + dependencies: + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: d928ca26d4390ad4f5e2c8198d16e14b675face6ad8c4a4eef699b54ce3f6cba584456659287b0e57e9f9019bc456b51dfa474671e11bf555fe04ed16174c10c + languageName: node + linkType: hard + +"@aws-sdk/is-array-buffer@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/is-array-buffer@npm:3.183.0" + dependencies: + tslib: ^2.3.1 + checksum: 717e508989821434a2ace4f690fc599f67b3f28ee9de5f06fce65a296fe11a68a5b97f30d66bfbf490d4a83259e4ffa1f0321231e4a54ce2440a9c6fdbacde24 + languageName: node + linkType: hard + +"@aws-sdk/md5-js@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/md5-js@npm:3.183.0" + dependencies: + "@aws-sdk/types": 3.183.0 + "@aws-sdk/util-utf8-browser": 3.183.0 + "@aws-sdk/util-utf8-node": 3.183.0 + tslib: ^2.3.1 + checksum: 5bd92465940ace6b3ca13342bd60eab42ffd5d74dfa65655c28e10bbf4aa0c32b2f9b4deb2050f3d092b8586e558bf248559af9c3cffb37810961169ad0797af + languageName: node + linkType: hard + +"@aws-sdk/middleware-content-length@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/middleware-content-length@npm:3.183.0" + dependencies: + "@aws-sdk/protocol-http": 3.183.0 + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: bf3ec6872a925dbafd91e57334b6264e8446ca59eba598ee4bc7b37113c466300ac6b77ab314c4aa2859221f1f4e98beabbd365346e0815d591f276e642d1849 + languageName: node + linkType: hard + +"@aws-sdk/middleware-host-header@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/middleware-host-header@npm:3.183.0" + dependencies: + "@aws-sdk/protocol-http": 3.183.0 + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: b4c4886976cffec614ff368daa995a69c765e737c8d366daa0033d781cf8e7483565bb3627ecd752698edc23dcf578de6657c9e8cb41c0fcd92631d17b7749b8 + languageName: node + linkType: hard + +"@aws-sdk/middleware-logger@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/middleware-logger@npm:3.183.0" + dependencies: + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: 10ffb6af0f81b0144fef91af2bbeaeb680df2beff838f2a6ebcc260971fd6252a166e3bf3501c1fc00f6f8f203117ff6e2b4baebb7a6d8cd8504b7e1f392bd6d + languageName: node + linkType: hard + +"@aws-sdk/middleware-recursion-detection@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/middleware-recursion-detection@npm:3.183.0" + dependencies: + "@aws-sdk/protocol-http": 3.183.0 + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: 461117e0dc8c38750942035a07163817bc8e89f377211f5fb52d4314acae4e7e6cb49be04193c508112833535b33814c1609196cb65e38cff1122043398ad89e + languageName: node + linkType: hard + +"@aws-sdk/middleware-retry@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/middleware-retry@npm:3.183.0" + dependencies: + "@aws-sdk/protocol-http": 3.183.0 + "@aws-sdk/service-error-classification": 3.183.0 + "@aws-sdk/types": 3.183.0 + "@aws-sdk/util-middleware": 3.183.0 + tslib: ^2.3.1 + uuid: ^8.3.2 + checksum: 76fa3f9fe5f1c67bbfa792611289edf0afa2d0271073039931ac9ea46b3f432d74692d2db55443f40b7e97014898454f6d4bd8d2f2f5714a4281428b7464efac + languageName: node + linkType: hard + +"@aws-sdk/middleware-sdk-sqs@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/middleware-sdk-sqs@npm:3.183.0" + dependencies: + "@aws-sdk/types": 3.183.0 + "@aws-sdk/util-hex-encoding": 3.183.0 + tslib: ^2.3.1 + checksum: 0bb914b2e7a5391f5b22a5262a5c299fa7e3eb22076d00c4cfffb449e97404b4830a77bb742e8f3110d66f15ae9aad81ea740238799cc35bb8d328eaf13f3fe2 + languageName: node + linkType: hard + +"@aws-sdk/middleware-sdk-sts@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/middleware-sdk-sts@npm:3.183.0" + dependencies: + "@aws-sdk/middleware-signing": 3.183.0 + "@aws-sdk/property-provider": 3.183.0 + "@aws-sdk/protocol-http": 3.183.0 + "@aws-sdk/signature-v4": 3.183.0 + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: 1969d6128d24cc7d8ff199c2900d805281928668f4dc3ffd128065ccfe515f9f7467a265af276592009bd285847cb9298f8ba4b1dfbe33971c3e7de80986b422 + languageName: node + linkType: hard + +"@aws-sdk/middleware-serde@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/middleware-serde@npm:3.183.0" + dependencies: + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: 7495bb2adceab2c686588697fd9dd50a859706a8d33d98d9907ffc8f9ef78af141f2654cdac8d7b28b1f0544dcf2e52f25d109f5da1348102234ab5b4e79b256 + languageName: node + linkType: hard + +"@aws-sdk/middleware-signing@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/middleware-signing@npm:3.183.0" + dependencies: + "@aws-sdk/property-provider": 3.183.0 + "@aws-sdk/protocol-http": 3.183.0 + "@aws-sdk/signature-v4": 3.183.0 + "@aws-sdk/types": 3.183.0 + "@aws-sdk/util-middleware": 3.183.0 + tslib: ^2.3.1 + checksum: 8025499acfefc072511adbc5084a1ed3cfe9cd9e514c58045425c87538af72ad3adfc134f7d0a059ff52832da392b4679b62d4ad28e477b866a20e78370f0758 + languageName: node + linkType: hard + +"@aws-sdk/middleware-stack@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/middleware-stack@npm:3.183.0" + dependencies: + tslib: ^2.3.1 + checksum: 03136847b96b0e4baba9b64f53a6c6b5738b1fa2c645edb3f47c1f85082791549b423ea791af33e9da3507cd56fbcbd052f1ba773a9f45ea42a3647277e85264 + languageName: node + linkType: hard + +"@aws-sdk/middleware-user-agent@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/middleware-user-agent@npm:3.183.0" + dependencies: + "@aws-sdk/protocol-http": 3.183.0 + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: 8d1001d6d30f0f56aa440c541f6dcee9aad9190837e7a9653aef35448ff13e644cb7a441373192134ac86b5741fa64a120add07202cb97674018bd44612acdf7 + languageName: node + linkType: hard + +"@aws-sdk/node-config-provider@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/node-config-provider@npm:3.183.0" + dependencies: + "@aws-sdk/property-provider": 3.183.0 + "@aws-sdk/shared-ini-file-loader": 3.183.0 + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: 673fb105de8d11ddd1c3e636c7ed01ef4fbe412a7d96543d9db69149dfad64d33adf5b96b106763c058190841ea497f220e1b75ca438dbda7b34729f00b9e823 + languageName: node + linkType: hard + +"@aws-sdk/node-http-handler@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/node-http-handler@npm:3.183.0" + dependencies: + "@aws-sdk/abort-controller": 3.183.0 + "@aws-sdk/protocol-http": 3.183.0 + "@aws-sdk/querystring-builder": 3.183.0 + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: a24ee8cc4e3b63fdec0ebb671caa1e634af488befa7c93a28bb733bb532934c221f6c47707db20264af91ca84336a50b98427b425329b89aeac2a6d2be9537ff + languageName: node + linkType: hard + +"@aws-sdk/property-provider@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/property-provider@npm:3.183.0" + dependencies: + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: 6e8616e5f7efa9f46bdf62118dfc586e61dcdf0bc99f82305759020ce3d25fc1d2db71c62cfd4417a757a138b1a539cf305b584e6e7ade9bce9975fbe66fd326 + languageName: node + linkType: hard + +"@aws-sdk/protocol-http@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/protocol-http@npm:3.183.0" + dependencies: + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: 13b255bcb37b70853d93374f972d743c80f33ac16188c41b512536c2dbec4d7beb55226bfac6d809981d63bbc87f6bf345334238f187da2faa9feaef5001e0a7 + languageName: node + linkType: hard + +"@aws-sdk/querystring-builder@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/querystring-builder@npm:3.183.0" + dependencies: + "@aws-sdk/types": 3.183.0 + "@aws-sdk/util-uri-escape": 3.183.0 + tslib: ^2.3.1 + checksum: a3de19863ccee4e8c9d5bbd719688ee1ffea02c3d90aad5e9c3eb04bed942ff8e5be0bfbc21ed03a968481abe2a2b1093e93b986b4111c468a9f3d3466b61f83 + languageName: node + linkType: hard + +"@aws-sdk/querystring-parser@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/querystring-parser@npm:3.183.0" + dependencies: + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: f05a03c46317c97f1b775f7c5be19365cf464396edc6b23c93efd5289ff1a8658883f7c9dde2cc7b74bb42b57f257bc212abae5d62100d23cdec5409fbffe468 + languageName: node + linkType: hard + +"@aws-sdk/service-error-classification@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/service-error-classification@npm:3.183.0" + checksum: 8c015163aee9ec4d789daa8605e5b9424dfda81d3f609a2c34d800cb36ee78f4a3af02d1738c7e75f9a62cd1ef8ec4307f77457eecba3de4c6565a981484bca4 + languageName: node + linkType: hard + +"@aws-sdk/shared-ini-file-loader@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/shared-ini-file-loader@npm:3.183.0" + dependencies: + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: 317fd0d8012559754f82b88fb386d2a01c19be1d3a0b6da3a6436f71701ed8cd8fbe3f5aa869fd7bbfb8dfb148cd9de02aa68e93001200c76ba9e0691e135773 + languageName: node + linkType: hard + +"@aws-sdk/signature-v4@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/signature-v4@npm:3.183.0" + dependencies: + "@aws-sdk/is-array-buffer": 3.183.0 + "@aws-sdk/types": 3.183.0 + "@aws-sdk/util-hex-encoding": 3.183.0 + "@aws-sdk/util-middleware": 3.183.0 + "@aws-sdk/util-uri-escape": 3.183.0 + tslib: ^2.3.1 + checksum: 6639a4925b194171907fc1cf61101470836f5a8fa363f3fcd7b70bbaa4c756f43e13ad93b575885218a68192c375295d359a7e91db370816bd8f39f9c158ba36 + languageName: node + linkType: hard + +"@aws-sdk/smithy-client@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/smithy-client@npm:3.183.0" + dependencies: + "@aws-sdk/middleware-stack": 3.183.0 + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: 70866adfd91fb35721bcd8667d9a4638e306de6ddc22be37a5b3ea19dfc2a1404a7325992f7f56d635a3bfd3b0ffa159d32f17df35c47ada4724ad8d5bb8d1ce + languageName: node + linkType: hard + +"@aws-sdk/types@npm:3.183.0, @aws-sdk/types@npm:^3.1.0, @aws-sdk/types@npm:^3.110.0": + version: 3.183.0 + resolution: "@aws-sdk/types@npm:3.183.0" + checksum: ab6e888ef8f6d5f5c047dbe0899ac94ad4aa83b9ae1b1fd7a3b88eacec61ab912f215fda65c71f783418d569d1088641806f6b98c9a28ddae04cc70d0eeccea7 + languageName: node + linkType: hard + +"@aws-sdk/url-parser@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/url-parser@npm:3.183.0" + dependencies: + "@aws-sdk/querystring-parser": 3.183.0 + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: 54c99d47e927368db12b6aa1fe4331a27461502355e0c18e99d8e05d9a114529d0b15965ff885cae8e19e49692ad44bf3c323ffdc535d7129deac900f286d1d5 + languageName: node + linkType: hard + +"@aws-sdk/util-base64-browser@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/util-base64-browser@npm:3.183.0" + dependencies: + tslib: ^2.3.1 + checksum: 2c3a4dc7e285b146285ac23de155de5e885d96aa46b29f9c830b6f12541032c6a42be7fd412ec019ddb83e6f155f561d04065b99159515d26d28c0968965dcf2 + languageName: node + linkType: hard + +"@aws-sdk/util-base64-node@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/util-base64-node@npm:3.183.0" + dependencies: + "@aws-sdk/util-buffer-from": 3.183.0 + tslib: ^2.3.1 + checksum: d8d0330aa768f816411a7b2343c500728501775d2f8d7c121d52d8484cbdd938102f3049e69e28574c838416ead0cb742494140609287b8d462bfb041218600d + languageName: node + linkType: hard + +"@aws-sdk/util-body-length-browser@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/util-body-length-browser@npm:3.183.0" + dependencies: + tslib: ^2.3.1 + checksum: 294074e20e4eb46ea992fc9d50fac0b97875d1d09efa706d5298e34f4200226c90bb33bbe96c41c7e91a43fbe44e6cfc0654d09fcdb823fe579545ada65701d9 + languageName: node + linkType: hard + +"@aws-sdk/util-body-length-node@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/util-body-length-node@npm:3.183.0" + dependencies: + tslib: ^2.3.1 + checksum: 60697959c63731d6b4b334bed91d08c4e38e09c0ad95000509641370249c76c5df1ffa0a7cab7418d250a526f49e660f0c67cea28547e442ac47feb7623413b8 + languageName: node + linkType: hard + +"@aws-sdk/util-buffer-from@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/util-buffer-from@npm:3.183.0" + dependencies: + "@aws-sdk/is-array-buffer": 3.183.0 + tslib: ^2.3.1 + checksum: 5f16145cf68b0756f0930990cfba57ac343c83c6e9dc48bc8d4f488cd66548a9e186e702fa94ba33b69d852c2d019eedf4116ac676cf0dfb701081e39e0776dd + languageName: node + linkType: hard + +"@aws-sdk/util-config-provider@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/util-config-provider@npm:3.183.0" + dependencies: + tslib: ^2.3.1 + checksum: 8af6bf5ba31ec0a2fcf994f0a13bde5ff948bcdba02d153cdeea2105ea5eaf934368456bc92f35bfa42a7475cd4d2d2b9a644dfb8b4c2670ae2f103c045dc8b4 + languageName: node + linkType: hard + +"@aws-sdk/util-defaults-mode-browser@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/util-defaults-mode-browser@npm:3.183.0" + dependencies: + "@aws-sdk/property-provider": 3.183.0 + "@aws-sdk/types": 3.183.0 + bowser: ^2.11.0 + tslib: ^2.3.1 + checksum: 8ff54acf1684dd9d82ca13a522c5d2d7ee305511a2748f6e8ef7dc43e668798269e51455ac81b905a5b000a704fd5536f178c84425b8c431500e6a8dc1418135 + languageName: node + linkType: hard + +"@aws-sdk/util-defaults-mode-node@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/util-defaults-mode-node@npm:3.183.0" + dependencies: + "@aws-sdk/config-resolver": 3.183.0 + "@aws-sdk/credential-provider-imds": 3.183.0 + "@aws-sdk/node-config-provider": 3.183.0 + "@aws-sdk/property-provider": 3.183.0 + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + checksum: 40665d251844c4add23e358d9171add7180e0f1fcd4bd99601f4bdd03daa2259fed2567fa200152e14c4d7b1acc1126997f5b4e74c569ee1032f9fee16e6b582 + languageName: node + linkType: hard + +"@aws-sdk/util-hex-encoding@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/util-hex-encoding@npm:3.183.0" + dependencies: + tslib: ^2.3.1 + checksum: 1bf9577d96d01c13a3118e5d767c1e16b1f4f1c574168d78e128e0342edac30c87776340e9e14deb1e9adf539a6b2f953338adabc097fb143e870889698a6308 + languageName: node + linkType: hard + +"@aws-sdk/util-locate-window@npm:^3.0.0": + version: 3.183.0 + resolution: "@aws-sdk/util-locate-window@npm:3.183.0" + dependencies: + tslib: ^2.3.1 + checksum: c29899b440c148aa44a5d9322e06e4cf21644e47bee10555cf8db104d9d76b3985fa4da6e8ca92c137b0b739f7504a7d106e9da49e1d189b84f51f45c21b2204 + languageName: node + linkType: hard + +"@aws-sdk/util-middleware@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/util-middleware@npm:3.183.0" + dependencies: + tslib: ^2.3.1 + checksum: e1a433aebae5e74b365ecb4a57e3c583e7b89697f24b0c9edde93b8ba358e92256550329efb7c6924c0a5037e1bad2b7a1c8ed1b6d02e1aaaa35bca502923752 + languageName: node + linkType: hard + +"@aws-sdk/util-uri-escape@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/util-uri-escape@npm:3.183.0" + dependencies: + tslib: ^2.3.1 + checksum: 9d5f30821cdad15ed6912f7406f83b5b5a45358b208a9374ea944313d9853da8f4ec9881aefa5d6fe78caeaefbb0d103c8485a32f7c25e8b2cae193ea2233bb8 + languageName: node + linkType: hard + +"@aws-sdk/util-user-agent-browser@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/util-user-agent-browser@npm:3.183.0" + dependencies: + "@aws-sdk/types": 3.183.0 + bowser: ^2.11.0 + tslib: ^2.3.1 + checksum: 21349881a4069a09fb0f8c0f5a6d69e6659255008861817c5d9dada61bf032f0bd7d5735f01dbddbc310d228ea843fbec6ada9f83a4197909efd6ebadb364f6b + languageName: node + linkType: hard + +"@aws-sdk/util-user-agent-node@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/util-user-agent-node@npm:3.183.0" + dependencies: + "@aws-sdk/node-config-provider": 3.183.0 + "@aws-sdk/types": 3.183.0 + tslib: ^2.3.1 + peerDependencies: + aws-crt: ">=1.0.0" + peerDependenciesMeta: + aws-crt: + optional: true + checksum: 727d46842053f8f19789fee1550e235adff399559ef6c9b8dd0fe9edd7ac629a9b5c5849377553bfff37deba1ba9889d0c313f059f27cfc40a33895990c1f894 + languageName: node + linkType: hard + +"@aws-sdk/util-utf8-browser@npm:3.183.0, @aws-sdk/util-utf8-browser@npm:^3.0.0": + version: 3.183.0 + resolution: "@aws-sdk/util-utf8-browser@npm:3.183.0" + dependencies: + tslib: ^2.3.1 + checksum: f1c9cbafc3dcf5b04264c3708509117d5e6f6b373fb30712a0cd9d09966a2cdead0a91067a8e9513abac9b082971fd40519e421a2e046b3653ce1ede136197c2 + languageName: node + linkType: hard + +"@aws-sdk/util-utf8-node@npm:3.183.0": + version: 3.183.0 + resolution: "@aws-sdk/util-utf8-node@npm:3.183.0" + dependencies: + "@aws-sdk/util-buffer-from": 3.183.0 + tslib: ^2.3.1 + checksum: c37f2bd388783c33c981afcd5a6a80481cc4e019f42bc5ab10ba2dfb039a4684acb4fa30df579cb3a5b509f61b1261870b30cd966c179029adb2a42672c0a871 + languageName: node + linkType: hard + "@azure/abort-controller@npm:^1.0.0": version: 1.0.2 resolution: "@azure/abort-controller@npm:1.0.2" @@ -3147,7 +3931,8 @@ __metadata: "@backstage/integration": "workspace:^" "@backstage/types": "workspace:^" "@google-cloud/storage": ^6.0.0 - "@keyv/redis": ^2.2.3 + "@keyv/memcache": ^1.3.5 + "@keyv/redis": ^2.5.3 "@kubernetes/client-node": 0.17.0 "@manypkg/get-packages": ^1.1.3 "@octokit/rest": ^19.0.3 @@ -3188,8 +3973,7 @@ __metadata: http-errors: ^2.0.0 isomorphic-git: ^1.8.0 jose: ^4.6.0 - keyv: ^4.0.3 - keyv-memcache: ^1.2.5 + keyv: ^4.5.2 knex: ^2.0.0 lodash: ^4.17.21 logform: ^2.3.2 @@ -3198,7 +3982,7 @@ __metadata: minimist: ^1.2.5 mock-fs: ^5.1.0 morgan: ^1.10.0 - msw: ^0.47.0 + msw: ^0.48.0 mysql2: ^2.2.5 node-abort-controller: ^3.0.1 node-fetch: ^2.6.7 @@ -3283,7 +4067,7 @@ __metadata: "@backstage/config": "workspace:^" better-sqlite3: ^7.5.0 knex: ^2.0.0 - msw: ^0.47.0 + msw: ^0.48.0 mysql2: ^2.2.5 pg: ^8.3.0 testcontainers: ^8.1.2 @@ -3310,7 +4094,7 @@ __metadata: "@backstage/cli": "workspace:^" "@backstage/errors": "workspace:^" cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 languageName: unknown linkType: soft @@ -3452,7 +4236,7 @@ __metadata: mini-css-extract-plugin: ^2.4.2 minimatch: 5.1.0 mock-fs: ^5.1.0 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 node-libs-browser: ^2.2.1 nodemon: ^2.0.2 @@ -3535,7 +4319,7 @@ __metadata: json-schema-merge-allof: ^0.8.1 json-schema-traverse: ^1.0.0 mock-fs: ^5.1.0 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 typescript-json-schema: ^0.54.0 yaml: ^2.0.0 @@ -3583,7 +4367,7 @@ __metadata: "@types/prop-types": ^15.7.3 "@types/zen-observable": ^0.8.0 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 prop-types: ^15.7.2 react-router-beta: "npm:react-router@6.0.0-beta.0" react-router-dom-beta: "npm:react-router-dom@6.0.0-beta.0" @@ -3696,7 +4480,7 @@ __metadata: history: ^5.0.0 immer: ^9.0.1 lodash: ^4.17.21 - msw: ^0.47.0 + msw: ^0.48.0 pluralize: ^8.0.0 prop-types: ^15.7.2 qs: ^6.9.4 @@ -3759,7 +4543,7 @@ __metadata: "@types/zen-observable": ^0.8.0 cross-fetch: ^3.1.5 history: ^5.0.0 - msw: ^0.47.0 + msw: ^0.48.0 prop-types: ^15.7.2 zen-observable: ^0.8.15 peerDependencies: @@ -3887,7 +4671,7 @@ __metadata: "@testing-library/user-event": ^14.0.0 "@types/node": ^16.11.26 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -3926,7 +4710,7 @@ __metadata: git-url-parse: ^13.0.0 lodash: ^4.17.21 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 languageName: unknown linkType: soft @@ -3947,7 +4731,7 @@ __metadata: "@types/supertest": ^2.0.8 luxon: ^3.0.0 marked: ^4.0.14 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.5 supertest: ^6.1.3 winston: ^3.2.1 @@ -3993,7 +4777,7 @@ __metadata: "@types/node": "*" cross-fetch: ^3.1.5 git-url-parse: ^13.0.0 - msw: ^0.47.0 + msw: ^0.48.0 octokit: ^2.0.0 react-markdown: ^8.0.0 react-use: ^17.2.4 @@ -4017,7 +4801,7 @@ __metadata: express: ^4.17.1 express-promise-router: ^4.1.0 http-proxy-middleware: ^2.0.0 - msw: ^0.47.0 + msw: ^0.48.0 supertest: ^6.1.6 winston: ^3.2.1 yn: ^4.0.0 @@ -4046,7 +4830,7 @@ __metadata: "@types/node": ^16.11.26 "@types/object-hash": ^2.2.1 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 object-hash: ^3.0.0 react-use: ^17.2.4 peerDependencies: @@ -4076,7 +4860,7 @@ __metadata: "@testing-library/user-event": ^14.0.0 "@types/node": ^16.11.26 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -4104,7 +4888,7 @@ __metadata: "@testing-library/user-event": ^14.0.0 "@types/node": ^16.11.26 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 react-ga: ^3.3.0 react-use: ^17.2.4 peerDependencies: @@ -4130,7 +4914,7 @@ __metadata: "@testing-library/user-event": ^14.0.0 "@types/node": ^16.11.26 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 qs: ^6.10.1 react-use: ^17.2.4 peerDependencies: @@ -4155,7 +4939,7 @@ __metadata: version: 0.0.0-use.local resolution: "@backstage/plugin-api-docs@workspace:plugins/api-docs" dependencies: - "@asyncapi/react-component": 1.0.0-next.43 + "@asyncapi/react-component": 1.0.0-next.44 "@backstage/catalog-model": "workspace:^" "@backstage/cli": "workspace:^" "@backstage/core-app-api": "workspace:^" @@ -4179,7 +4963,7 @@ __metadata: graphql: ^16.0.0 graphql-ws: ^5.4.1 isomorphic-form-data: ^2.0.0 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 swagger-ui-react: ^4.11.1 peerDependencies: @@ -4210,7 +4994,7 @@ __metadata: "@testing-library/user-event": ^14.0.0 "@types/node": "*" cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 use-deep-compare-effect: ^1.8.1 peerDependencies: @@ -4242,7 +5026,7 @@ __metadata: lodash: ^4.17.21 luxon: ^3.0.0 mock-fs: ^5.1.0 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 supertest: ^6.1.3 winston: ^3.2.1 @@ -4293,7 +5077,7 @@ __metadata: luxon: ^3.0.0 minimatch: ^5.0.0 morgan: ^1.10.0 - msw: ^0.47.0 + msw: ^0.48.0 node-cache: ^5.1.2 node-fetch: ^2.6.7 openid-client: ^5.2.1 @@ -4327,7 +5111,7 @@ __metadata: express: ^4.17.1 jose: ^4.6.0 lodash: ^4.17.21 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 uuid: ^8.0.0 winston: ^3.2.1 @@ -4348,7 +5132,7 @@ __metadata: express: ^4.17.1 express-promise-router: ^4.1.0 mime-types: ^2.1.27 - msw: ^0.47.0 + msw: ^0.48.0 p-limit: ^3.1.0 supertest: ^6.1.6 winston: ^3.2.1 @@ -4389,7 +5173,7 @@ __metadata: cross-fetch: ^3.1.5 humanize-duration: ^3.27.0 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -4412,7 +5196,7 @@ __metadata: "@types/supertest": ^2.0.8 express: ^4.17.1 express-promise-router: ^4.1.0 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 winston: ^3.2.1 yn: ^4.0.0 @@ -4450,7 +5234,7 @@ __metadata: "@types/node": ^16.11.26 cross-fetch: ^3.1.5 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -4501,7 +5285,7 @@ __metadata: "@testing-library/user-event": ^14.0.0 "@types/node": ^16.11.26 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -4565,7 +5349,7 @@ __metadata: "@backstage/integration": "workspace:^" "@openapitools/openapi-generator-cli": ^2.4.26 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 ts-morph: ^15.0.0 languageName: unknown linkType: soft @@ -4594,7 +5378,7 @@ __metadata: cross-fetch: ^3.1.5 lodash: ^4.17.21 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 qs: ^6.9.6 react-use: ^17.2.4 recharts: ^2.0.0 @@ -4650,7 +5434,7 @@ __metadata: "@types/lodash": ^4.14.151 lodash: ^4.17.21 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 uuid: ^8.0.0 winston: ^3.2.1 @@ -4665,14 +5449,19 @@ __metadata: "@backstage/backend-plugin-api": "workspace:^" "@backstage/backend-tasks": "workspace:^" "@backstage/backend-test-utils": "workspace:^" + "@backstage/catalog-client": "workspace:^" + "@backstage/catalog-model": "workspace:^" "@backstage/cli": "workspace:^" "@backstage/config": "workspace:^" "@backstage/integration": "workspace:^" "@backstage/plugin-bitbucket-cloud-common": "workspace:^" "@backstage/plugin-catalog-backend": "workspace:^" + "@backstage/plugin-catalog-common": "workspace:^" "@backstage/plugin-catalog-node": "workspace:^" + "@backstage/plugin-events-node": "workspace:^" luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 + p-limit: ^3.1.0 uuid: ^8.0.0 winston: ^3.2.1 languageName: unknown @@ -4695,7 +5484,7 @@ __metadata: "@backstage/plugin-catalog-node": "workspace:^" "@types/node-fetch": ^2.5.12 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 uuid: ^8.0.0 winston: ^3.2.1 @@ -4718,7 +5507,7 @@ __metadata: "@backstage/types": "workspace:^" "@types/lodash": ^4.14.151 lodash: ^4.17.21 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 winston: ^3.2.1 languageName: unknown @@ -4742,7 +5531,7 @@ __metadata: "@types/fs-extra": ^9.0.1 fs-extra: 10.1.0 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 uuid: ^8.0.0 winston: ^3.2.1 @@ -4772,7 +5561,7 @@ __metadata: git-url-parse: ^13.0.0 lodash: ^4.17.21 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 uuid: ^8.0.0 winston: ^3.2.1 @@ -4799,7 +5588,7 @@ __metadata: "@types/uuid": ^8.0.0 lodash: ^4.17.21 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 uuid: ^8.0.0 winston: ^3.2.1 @@ -4845,7 +5634,7 @@ __metadata: "@types/node-fetch": ^2.5.12 lodash: ^4.17.21 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 p-limit: ^3.0.2 qs: ^6.9.4 @@ -4913,7 +5702,7 @@ __metadata: knex: ^2.0.0 lodash: ^4.17.21 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 p-limit: ^3.0.2 prom-client: ^14.0.1 @@ -5003,7 +5792,7 @@ __metadata: graphql-modules: ^2.0.0 graphql-tag: ^2.11.0 graphql-type-json: ^0.3.2 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 winston: ^3.2.1 languageName: unknown @@ -5039,7 +5828,7 @@ __metadata: git-url-parse: ^13.0.0 js-base64: ^3.6.0 lodash: ^4.17.21 - msw: ^0.47.0 + msw: ^0.48.0 react-hook-form: ^7.12.2 react-use: ^17.2.4 yaml: ^2.0.0 @@ -5252,7 +6041,7 @@ __metadata: humanize-duration: ^3.27.0 lodash: ^4.17.21 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -5283,7 +6072,7 @@ __metadata: "@types/node": ^16.11.26 cross-fetch: ^3.1.5 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 qs: ^6.9.4 react-use: ^17.2.4 peerDependencies: @@ -5317,7 +6106,7 @@ __metadata: cross-fetch: ^3.1.5 humanize-duration: ^3.27.1 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -5343,7 +6132,7 @@ __metadata: express-promise-router: ^4.1.0 express-xml-bodyparser: ^0.3.0 knex: ^2.0.0 - msw: ^0.47.0 + msw: ^0.48.0 supertest: ^6.1.6 uuid: ^8.3.2 winston: ^3.2.1 @@ -5380,7 +6169,7 @@ __metadata: cross-fetch: ^3.1.5 highlight.js: ^10.6.0 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 recharts: ^2.0.0 peerDependencies: @@ -5411,7 +6200,7 @@ __metadata: "@testing-library/user-event": ^14.0.0 "@types/node": "*" cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 rc-progress: 3.4.0 react-use: ^17.2.4 peerDependencies: @@ -5443,7 +6232,7 @@ __metadata: "@types/node": ^16.11.26 cross-fetch: ^3.1.5 jsonschema: ^1.2.6 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 zen-observable: ^0.8.15 peerDependencies: @@ -5470,6 +6259,7 @@ __metadata: "@backstage/core-components": "workspace:^" "@backstage/core-plugin-api": "workspace:^" "@backstage/dev-utils": "workspace:^" + "@backstage/plugin-catalog-react": "workspace:^" "@backstage/plugin-cost-insights-common": "workspace:^" "@backstage/test-utils": "workspace:^" "@backstage/theme": "workspace:^" @@ -5490,7 +6280,7 @@ __metadata: cross-fetch: ^3.1.5 history: ^5.0.0 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 pluralize: ^8.0.0 qs: ^6.9.4 react-use: ^17.2.4 @@ -5524,7 +6314,7 @@ __metadata: "@testing-library/user-event": ^14.0.0 "@types/node": "*" express: ^4.18.1 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: "@backstage/plugin-catalog-react": "workspace:^" @@ -5532,6 +6322,135 @@ __metadata: languageName: unknown linkType: soft +"@backstage/plugin-events-backend-module-aws-sqs@workspace:plugins/events-backend-module-aws-sqs": + version: 0.0.0-use.local + resolution: "@backstage/plugin-events-backend-module-aws-sqs@workspace:plugins/events-backend-module-aws-sqs" + dependencies: + "@aws-sdk/client-sqs": ^3.0.0 + "@backstage/backend-common": "workspace:^" + "@backstage/backend-plugin-api": "workspace:^" + "@backstage/backend-tasks": "workspace:^" + "@backstage/backend-test-utils": "workspace:^" + "@backstage/cli": "workspace:^" + "@backstage/config": "workspace:^" + "@backstage/plugin-events-backend-test-utils": "workspace:^" + "@backstage/plugin-events-node": "workspace:^" + "@backstage/types": "workspace:^" + aws-sdk-client-mock: ^2.0.0 + luxon: ^3.0.0 + winston: ^3.2.1 + languageName: unknown + linkType: soft + +"@backstage/plugin-events-backend-module-azure@workspace:plugins/events-backend-module-azure": + version: 0.0.0-use.local + resolution: "@backstage/plugin-events-backend-module-azure@workspace:plugins/events-backend-module-azure" + dependencies: + "@backstage/backend-plugin-api": "workspace:^" + "@backstage/backend-test-utils": "workspace:^" + "@backstage/cli": "workspace:^" + "@backstage/plugin-events-backend-test-utils": "workspace:^" + "@backstage/plugin-events-node": "workspace:^" + supertest: ^6.1.3 + winston: ^3.2.1 + languageName: unknown + linkType: soft + +"@backstage/plugin-events-backend-module-bitbucket-cloud@workspace:plugins/events-backend-module-bitbucket-cloud": + version: 0.0.0-use.local + resolution: "@backstage/plugin-events-backend-module-bitbucket-cloud@workspace:plugins/events-backend-module-bitbucket-cloud" + dependencies: + "@backstage/backend-plugin-api": "workspace:^" + "@backstage/backend-test-utils": "workspace:^" + "@backstage/cli": "workspace:^" + "@backstage/plugin-events-backend-test-utils": "workspace:^" + "@backstage/plugin-events-node": "workspace:^" + supertest: ^6.1.3 + winston: ^3.2.1 + languageName: unknown + linkType: soft + +"@backstage/plugin-events-backend-module-gerrit@workspace:plugins/events-backend-module-gerrit": + version: 0.0.0-use.local + resolution: "@backstage/plugin-events-backend-module-gerrit@workspace:plugins/events-backend-module-gerrit" + dependencies: + "@backstage/backend-plugin-api": "workspace:^" + "@backstage/backend-test-utils": "workspace:^" + "@backstage/cli": "workspace:^" + "@backstage/plugin-events-backend-test-utils": "workspace:^" + "@backstage/plugin-events-node": "workspace:^" + supertest: ^6.1.3 + winston: ^3.2.1 + languageName: unknown + linkType: soft + +"@backstage/plugin-events-backend-module-github@workspace:plugins/events-backend-module-github": + version: 0.0.0-use.local + resolution: "@backstage/plugin-events-backend-module-github@workspace:plugins/events-backend-module-github" + dependencies: + "@backstage/backend-plugin-api": "workspace:^" + "@backstage/backend-test-utils": "workspace:^" + "@backstage/cli": "workspace:^" + "@backstage/plugin-events-backend-test-utils": "workspace:^" + "@backstage/plugin-events-node": "workspace:^" + supertest: ^6.1.3 + winston: ^3.2.1 + languageName: unknown + linkType: soft + +"@backstage/plugin-events-backend-module-gitlab@workspace:plugins/events-backend-module-gitlab": + version: 0.0.0-use.local + resolution: "@backstage/plugin-events-backend-module-gitlab@workspace:plugins/events-backend-module-gitlab" + dependencies: + "@backstage/backend-plugin-api": "workspace:^" + "@backstage/backend-test-utils": "workspace:^" + "@backstage/cli": "workspace:^" + "@backstage/plugin-events-backend-test-utils": "workspace:^" + "@backstage/plugin-events-node": "workspace:^" + supertest: ^6.1.3 + winston: ^3.2.1 + languageName: unknown + linkType: soft + +"@backstage/plugin-events-backend-test-utils@workspace:^, @backstage/plugin-events-backend-test-utils@workspace:plugins/events-backend-test-utils": + version: 0.0.0-use.local + resolution: "@backstage/plugin-events-backend-test-utils@workspace:plugins/events-backend-test-utils" + dependencies: + "@backstage/cli": "workspace:^" + "@backstage/plugin-events-node": "workspace:^" + languageName: unknown + linkType: soft + +"@backstage/plugin-events-backend@workspace:^, @backstage/plugin-events-backend@workspace:plugins/events-backend": + version: 0.0.0-use.local + resolution: "@backstage/plugin-events-backend@workspace:plugins/events-backend" + dependencies: + "@backstage/backend-common": "workspace:^" + "@backstage/backend-plugin-api": "workspace:^" + "@backstage/backend-test-utils": "workspace:^" + "@backstage/cli": "workspace:^" + "@backstage/config": "workspace:^" + "@backstage/plugin-events-backend-test-utils": "workspace:^" + "@backstage/plugin-events-node": "workspace:^" + "@types/express": ^4.17.6 + express: ^4.17.1 + express-promise-router: ^4.1.0 + supertest: ^6.1.3 + winston: ^3.2.1 + languageName: unknown + linkType: soft + +"@backstage/plugin-events-node@workspace:^, @backstage/plugin-events-node@workspace:plugins/events-node": + version: 0.0.0-use.local + resolution: "@backstage/plugin-events-node@workspace:plugins/events-node" + dependencies: + "@backstage/backend-plugin-api": "workspace:^" + "@backstage/cli": "workspace:^" + "@types/express": ^4.17.6 + express: ^4.17.1 + languageName: unknown + linkType: soft + "@backstage/plugin-explore-react@workspace:^, @backstage/plugin-explore-react@workspace:plugins/explore-react": version: 0.0.0-use.local resolution: "@backstage/plugin-explore-react@workspace:plugins/explore-react" @@ -5545,7 +6464,7 @@ __metadata: "@testing-library/user-event": ^14.0.0 "@types/node": ^16.11.26 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 languageName: unknown linkType: soft @@ -5573,7 +6492,7 @@ __metadata: "@types/node": ^16.11.26 classnames: ^2.2.6 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: "@types/react": ^16.13.1 || ^17.0.0 @@ -5604,7 +6523,7 @@ __metadata: "@types/node": ^16.11.26 cross-fetch: ^3.1.5 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -5634,7 +6553,7 @@ __metadata: "@types/node": ^16.11.26 cross-fetch: ^3.1.5 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 p-limit: ^3.0.2 react-use: ^17.2.4 peerDependencies: @@ -5671,7 +6590,7 @@ __metadata: lodash: ^4.17.21 luxon: ^3.0.0 material-ui-popup-state: ^1.9.3 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -5698,7 +6617,7 @@ __metadata: "@testing-library/user-event": ^14.0.0 "@types/node": ^16.11.26 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 peerDependencies: react: ^16.13.1 || ^17.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 @@ -5729,7 +6648,7 @@ __metadata: "@types/recharts": ^1.8.15 cross-fetch: ^3.1.5 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 qs: ^6.10.1 react-use: ^17.2.4 recharts: ^2.0.0 @@ -5764,7 +6683,7 @@ __metadata: "@types/node": ^16.11.26 cross-fetch: ^3.1.5 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -5799,7 +6718,7 @@ __metadata: "@types/node": ^16.11.26 cross-fetch: ^3.1.5 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -5832,7 +6751,7 @@ __metadata: "@types/react": ^16.13.1 || ^17.0.0 cross-fetch: ^3.1.5 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 octokit: ^2.0.4 react-use: ^17.4.0 peerDependencies: @@ -5864,7 +6783,7 @@ __metadata: "@types/react": ^16.13.1 || ^17.0.0 cross-fetch: ^3.1.5 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 p-limit: ^4.0.0 react-use: ^17.2.4 peerDependencies: @@ -5892,7 +6811,7 @@ __metadata: "@testing-library/user-event": ^14.0.0 "@types/node": ^16.11.26 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -5926,7 +6845,7 @@ __metadata: cross-fetch: ^3.1.5 lodash: ^4.17.21 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 qs: ^6.10.1 react-use: ^17.2.4 peerDependencies: @@ -5957,7 +6876,7 @@ __metadata: graphiql: ^1.5.12 graphql: ^16.0.0 graphql-ws: ^5.4.1 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -5983,7 +6902,7 @@ __metadata: graphql: ^16.0.0 graphql-modules: ^2.0.0 helmet: ^6.0.0 - msw: ^0.47.0 + msw: ^0.48.0 reflect-metadata: ^0.1.13 supertest: ^6.1.3 winston: ^3.2.1 @@ -6039,7 +6958,7 @@ __metadata: "@types/node": ^16.11.26 cross-fetch: ^3.1.5 lodash: ^4.17.21 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: "@types/react": ^16.13.1 || ^17.0.0 @@ -6074,7 +6993,7 @@ __metadata: cross-fetch: ^3.1.5 humanize-duration: ^3.26.0 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -6100,7 +7019,7 @@ __metadata: express: ^4.17.1 express-promise-router: ^4.1.0 jenkins: ^1.0.0 - msw: ^0.47.0 + msw: ^0.48.0 promise-any-polyfill: ^1.0.1 supertest: ^6.1.6 winston: ^3.2.1 @@ -6143,7 +7062,7 @@ __metadata: "@types/testing-library__jest-dom": ^5.9.1 cross-fetch: ^3.1.5 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -6198,7 +7117,7 @@ __metadata: "@types/node": ^16.11.26 cross-fetch: ^3.1.5 jest-when: ^3.1.0 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -6283,7 +7202,7 @@ __metadata: js-yaml: ^4.0.0 lodash: ^4.17.21 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -6315,7 +7234,7 @@ __metadata: "@types/node": ^16.11.26 "@types/react": ^16.13.1 || ^17.0.0 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -6365,7 +7284,7 @@ __metadata: "@testing-library/user-event": ^14.0.0 "@types/node": ^16.11.26 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -6394,7 +7313,7 @@ __metadata: "@testing-library/user-event": ^14.0.0 "@types/node": "*" cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -6423,7 +7342,7 @@ __metadata: "@testing-library/user-event": ^14.0.0 "@types/node": ^16.11.26 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 p-limit: ^3.1.0 pluralize: ^8.0.0 qs: ^6.10.1 @@ -6459,7 +7378,7 @@ __metadata: classnames: ^2.2.6 cross-fetch: ^3.1.5 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: "@types/react": ^16.13.1 || ^17.0.0 @@ -6479,7 +7398,7 @@ __metadata: "@types/supertest": ^2.0.8 express: ^4.17.1 express-promise-router: ^4.1.0 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 supertest: ^6.1.6 winston: ^3.2.1 @@ -6511,7 +7430,7 @@ __metadata: "@types/node": ^16.11.26 cross-fetch: ^3.1.5 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -6537,7 +7456,7 @@ __metadata: express: ^4.17.1 express-promise-router: ^4.1.0 lodash: ^4.17.21 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 supertest: ^6.1.6 winston: ^3.2.1 @@ -6569,7 +7488,7 @@ __metadata: "@backstage/errors": "workspace:^" "@backstage/types": "workspace:^" cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 uuid: ^8.0.0 zod: ^3.11.6 languageName: unknown @@ -6590,7 +7509,7 @@ __metadata: "@types/supertest": ^2.0.8 express: ^4.17.1 express-promise-router: ^4.1.0 - msw: ^0.47.0 + msw: ^0.48.0 supertest: ^6.1.3 zod: ^3.11.6 zod-to-json-schema: ^3.18.1 @@ -6656,7 +7575,7 @@ __metadata: express: ^4.17.1 express-promise-router: ^4.1.0 knex: ^2.0.0 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 supertest: ^6.1.3 uuid: ^8.2.0 @@ -6704,7 +7623,7 @@ __metadata: "@types/node": "*" cross-fetch: ^3.1.5 lodash: ^4.17.21 - msw: ^0.47.0 + msw: ^0.48.0 qs: ^6.9.4 react-hook-form: ^7.13.0 react-use: ^17.2.4 @@ -6732,7 +7651,7 @@ __metadata: express-promise-router: ^4.1.0 http-proxy-middleware: ^2.0.0 morgan: ^1.10.0 - msw: ^0.47.0 + msw: ^0.48.0 supertest: ^6.1.3 uuid: ^8.0.0 winston: ^3.2.1 @@ -6760,7 +7679,7 @@ __metadata: fs-extra: 10.1.0 lodash: ^4.17.21 morgan: ^1.10.0 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 supertest: ^6.1.3 winston: ^3.2.1 @@ -6792,7 +7711,7 @@ __metadata: "@types/react": ^16.13.1 || ^17.0.0 cross-fetch: ^3.1.5 lodash: ^4.17.21 - msw: ^0.47.0 + msw: ^0.48.0 react-sparklines: ^1.7.0 react-use: ^17.2.4 peerDependencies: @@ -6819,7 +7738,7 @@ __metadata: command-exists: ^1.2.9 fs-extra: 10.1.0 mock-fs: ^5.1.0 - msw: ^0.47.0 + msw: ^0.48.0 winston: ^3.2.1 yn: ^4.0.0 languageName: unknown @@ -6910,7 +7829,7 @@ __metadata: luxon: ^3.0.0 mock-fs: ^5.1.0 morgan: ^1.10.0 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 nunjucks: ^3.2.3 octokit: ^2.0.0 @@ -6968,11 +7887,11 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.57 "@react-hookz/web": ^15.0.0 "@rjsf/core": ^3.2.1 - "@rjsf/core-v5": "npm:@rjsf/core@^5.0.0-beta.10" + "@rjsf/core-v5": "npm:@rjsf/core@^5.0.0-beta.12" "@rjsf/material-ui": ^3.2.1 - "@rjsf/material-ui-v5": "npm:@rjsf/material-ui@^5.0.0-beta.10" - "@rjsf/utils": ^5.0.0-beta.10 - "@rjsf/validator-ajv8": ^5.0.0-beta.10 + "@rjsf/material-ui-v5": "npm:@rjsf/material-ui@^5.0.0-beta.12" + "@rjsf/utils": ^5.0.0-beta.12 + "@rjsf/validator-ajv8": ^5.0.0-beta.12 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/react-hooks": ^8.0.0 @@ -6991,7 +7910,7 @@ __metadata: json-schema-library: ^7.0.0 lodash: ^4.17.21 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 qs: ^6.9.4 react-use: ^17.2.4 use-immer: ^0.7.0 @@ -7171,7 +8090,7 @@ __metadata: "@testing-library/user-event": ^14.0.0 "@types/node": ^16.11.26 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 qs: ^6.9.4 react-use: ^17.2.4 peerDependencies: @@ -7207,7 +8126,7 @@ __metadata: "@types/react": ^16.13.1 || ^17.0.0 cross-fetch: ^3.1.5 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 react-sparklines: ^1.7.0 react-use: ^17.2.4 peerDependencies: @@ -7237,7 +8156,7 @@ __metadata: "@types/node": ^16.11.26 "@types/zen-observable": ^0.8.2 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 react-hook-form: ^7.12.2 react-use: ^17.2.4 uuid: ^8.3.2 @@ -7261,7 +8180,7 @@ __metadata: "@types/supertest": ^2.0.12 express: ^4.18.1 express-promise-router: ^4.1.0 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 supertest: ^6.2.4 winston: ^3.2.1 @@ -7291,7 +8210,7 @@ __metadata: "@testing-library/user-event": ^14.0.0 "@types/node": ^16.11.26 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 rc-progress: 3.4.0 react-use: ^17.2.4 peerDependencies: @@ -7323,7 +8242,7 @@ __metadata: classnames: ^2.2.6 cross-fetch: ^3.1.5 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -7390,7 +8309,7 @@ __metadata: "@types/node": ^16.11.26 cross-fetch: ^3.1.5 lodash: ^4.17.21 - msw: ^0.47.0 + msw: ^0.48.0 qs: ^6.9.4 react-use: ^17.2.4 peerDependencies: @@ -7501,7 +8420,7 @@ __metadata: "@testing-library/user-event": ^14.0.0 "@types/node": ^16.11.26 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 qs: ^6.9.4 react-use: ^17.2.4 peerDependencies: @@ -7535,7 +8454,7 @@ __metadata: color: ^4.0.1 cross-fetch: ^3.1.5 d3-force: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 prop-types: ^15.7.2 react-use: ^17.2.4 peerDependencies: @@ -7567,7 +8486,7 @@ __metadata: "@testing-library/user-event": ^14.0.0 "@types/node": ^16.11.26 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 testing-library__dom: ^7.29.4-beta.1 peerDependencies: @@ -7603,7 +8522,7 @@ __metadata: fs-extra: 10.1.0 knex: ^2.0.0 lodash: ^4.17.21 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 p-limit: ^3.1.0 supertest: ^6.1.3 @@ -7637,7 +8556,7 @@ __metadata: "@types/react": ^16.13.1 || ^17.0.0 cross-fetch: ^3.1.5 git-url-parse: ^13.0.0 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -7748,7 +8667,7 @@ __metadata: git-url-parse: ^13.0.0 jss: ~10.8.2 lodash: ^4.17.21 - msw: ^0.47.0 + msw: ^0.48.0 react-helmet: 6.1.0 react-use: ^17.2.4 peerDependencies: @@ -7776,7 +8695,7 @@ __metadata: express: ^4.17.1 express-promise-router: ^4.1.0 leasot: ^12.0.0 - msw: ^0.47.0 + msw: ^0.48.0 supertest: ^6.1.3 winston: ^3.2.1 yn: ^4.0.0 @@ -7805,7 +8724,7 @@ __metadata: "@testing-library/user-event": ^14.0.0 "@types/node": ^16.11.26 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -7857,7 +8776,7 @@ __metadata: "@types/node": ^16.11.26 "@types/react": ^16.13.1 || ^17.0.0 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 zen-observable: ^0.8.15 peerDependencies: @@ -7884,7 +8803,7 @@ __metadata: express: ^4.17.1 express-promise-router: ^4.1.0 helmet: ^6.0.0 - msw: ^0.47.0 + msw: ^0.48.0 node-fetch: ^2.6.7 p-limit: ^3.1.0 supertest: ^6.1.6 @@ -7915,7 +8834,7 @@ __metadata: "@testing-library/user-event": ^14.0.0 "@types/node": "*" cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -7945,7 +8864,7 @@ __metadata: cross-fetch: ^3.1.5 lodash: ^4.17.21 luxon: ^3.0.0 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 recharts: ^2.0.0 peerDependencies: @@ -7961,7 +8880,7 @@ __metadata: "@backstage/test-utils": "workspace:^" "@types/node": ^16.0.0 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 languageName: unknown linkType: soft @@ -7984,7 +8903,7 @@ __metadata: "@testing-library/user-event": ^14.0.0 "@types/node": ^16.11.26 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 zen-observable: ^0.8.15 peerDependencies: "@types/react": ^16.13.1 || ^17.0.0 @@ -8322,8 +9241,8 @@ __metadata: linkType: hard "@codemirror/language@npm:^6.0.0": - version: 6.3.0 - resolution: "@codemirror/language@npm:6.3.0" + version: 6.3.1 + resolution: "@codemirror/language@npm:6.3.1" dependencies: "@codemirror/state": ^6.0.0 "@codemirror/view": ^6.0.0 @@ -8331,7 +9250,7 @@ __metadata: "@lezer/highlight": ^1.0.0 "@lezer/lr": ^1.0.0 style-mod: ^4.0.0 - checksum: 996d6aad1a4cfb455f3459951d5ecfb67ff5240cc29397b3b801e569fcda24f87364aa7e42b63e85ecf62af80eaecd01258303dbf5b5f0b1eba31daa9a5bd258 + checksum: 349b9806e1e2ce5d99ba1f5815cc4772e6032f68c95718594e8335196ef0686bc6378db7cdd5f0fda57ba068eebf0ee413bb336e32cc1ff958a743190a0266da languageName: node linkType: hard @@ -8386,13 +9305,13 @@ __metadata: linkType: hard "@codemirror/view@npm:^6.0.0": - version: 6.4.1 - resolution: "@codemirror/view@npm:6.4.1" + version: 6.4.2 + resolution: "@codemirror/view@npm:6.4.2" dependencies: "@codemirror/state": ^6.0.0 style-mod: ^4.0.0 w3c-keyname: ^2.2.4 - checksum: 51f8e9bf1701cd490708784fd42a90dd9b2ad84aaebfacdbcfa9093e7f99ded38093ac49bc9eb037924b7734a58ed854a19621d931cce3f7962c2a0b30fecc23 + checksum: c79982563ad90adf1d7504b28bb1304a73f669c69634a1630b51521e4023b3630c15601daf2857683b34a86cac4ca24dc5b538a9d944616617f99c1a7da7faa6 languageName: node linkType: hard @@ -8791,13 +9710,13 @@ __metadata: linkType: hard "@graphql-codegen/cli@npm:^2.3.1": - version: 2.13.11 - resolution: "@graphql-codegen/cli@npm:2.13.11" + version: 2.13.12 + resolution: "@graphql-codegen/cli@npm:2.13.12" dependencies: "@babel/generator": ^7.18.13 "@babel/template": ^7.18.10 "@babel/types": ^7.18.13 - "@graphql-codegen/core": 2.6.5 + "@graphql-codegen/core": 2.6.6 "@graphql-codegen/plugin-helpers": ^2.7.2 "@graphql-tools/apollo-engine-loader": ^7.3.6 "@graphql-tools/code-file-loader": ^7.3.1 @@ -8837,21 +9756,21 @@ __metadata: graphql-code-generator: cjs/bin.js graphql-codegen: cjs/bin.js graphql-codegen-esm: esm/bin.js - checksum: 8d5d6f848f245b2091b85785466805cced26d788a66c3e03fbcfd6dc8b5bac4215b6b687d746ad0ee05685c700eecc93b502fd73c3383e5ac4a19cc1b4198ac1 + checksum: 367d4687e1d4bf44f0a7f3cb4e71656774f006512883a51ceae905495b2e76819e6b49dfe63e3effe59abb990a4c17bb985878a4592bf2ff959dc822723c1370 languageName: node linkType: hard -"@graphql-codegen/core@npm:2.6.5": - version: 2.6.5 - resolution: "@graphql-codegen/core@npm:2.6.5" +"@graphql-codegen/core@npm:2.6.6": + version: 2.6.6 + resolution: "@graphql-codegen/core@npm:2.6.6" dependencies: "@graphql-codegen/plugin-helpers": ^2.7.2 "@graphql-tools/schema": ^9.0.0 - "@graphql-tools/utils": 9.0.0 + "@graphql-tools/utils": ^9.1.1 tslib: ~2.4.0 peerDependencies: graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 - checksum: 22a30285af6adf5acd8ed2f45363c77b718a1789f024094a4fcc62fc164440f0fed595b5eecfa216e3568a81ba07dd8f2e6111cb49f2ce46160b14167a330c41 + checksum: 4a506dfb7dad577510b0358444ad5c5080459c00e1740099212d28c08fc4f02824014602172b95a61c6092cc97b3838fafd02b3e2eadf99dd9b6fa390464935a languageName: node linkType: hard @@ -9281,15 +10200,15 @@ __metadata: languageName: node linkType: hard -"@graphql-tools/merge@npm:8.3.10": - version: 8.3.10 - resolution: "@graphql-tools/merge@npm:8.3.10" +"@graphql-tools/merge@npm:8.3.11": + version: 8.3.11 + resolution: "@graphql-tools/merge@npm:8.3.11" dependencies: - "@graphql-tools/utils": 9.0.1 + "@graphql-tools/utils": 9.1.0 tslib: ^2.4.0 peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - checksum: dbe2c6faee8034339c5708a43157b185b8523c131dde1b37bb511d96ac527da51f5be9501d9ffe0a8c424e419d64bb8415ec96e8443d3d0a5a6582a37b0aafa2 + checksum: 3cd16577f1ea1bcc389d232fa620adc0fefc91a6b42b48e7bb5e7bb67b67d206d409a9a8d60cac4d8cd5f0f1c5353369f7c5eb4054b44ce2277545e1fd1de17f languageName: node linkType: hard @@ -9429,16 +10348,16 @@ __metadata: linkType: hard "@graphql-tools/schema@npm:^9.0.0": - version: 9.0.8 - resolution: "@graphql-tools/schema@npm:9.0.8" + version: 9.0.9 + resolution: "@graphql-tools/schema@npm:9.0.9" dependencies: - "@graphql-tools/merge": 8.3.10 - "@graphql-tools/utils": 9.0.1 + "@graphql-tools/merge": 8.3.11 + "@graphql-tools/utils": 9.1.0 tslib: ^2.4.0 value-or-promise: 1.0.11 peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - checksum: fb29c29269622f2636ecccac868fa44a585622e16be74286a4cd97b259ba2d2dad5ec67e77b00117f70e500a9262e0edc58a35a83cea0618618993e5e1d809fb + checksum: 23620a993eff57723302315100d947b81664d6a1e00010ff293b3649f51ab423946d73920cce0ce822b7f7f42b99ea23240902ff47df3d252639613c0df7b971 languageName: node linkType: hard @@ -9536,25 +10455,25 @@ __metadata: languageName: node linkType: hard -"@graphql-tools/utils@npm:9.0.0": - version: 9.0.0 - resolution: "@graphql-tools/utils@npm:9.0.0" +"@graphql-tools/utils@npm:9.1.0": + version: 9.1.0 + resolution: "@graphql-tools/utils@npm:9.1.0" dependencies: tslib: ^2.4.0 peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - checksum: 8da22b13e0cfceac20f2ee08c45f360d0bd1390fa0edd8496ea75a0ca7d10ab3bbafca6b4b0dbc3f233a05cd53096e3063b9208f727c72db00e461751164afbd + checksum: dcf08df3bd1715e25e3b80bf2dd332376239ebcd2a9b93f4d6b72a7bd3feffe2207b9683bb8fcaed9d0d1286f701d0686fe99ac803b91c0df54509b869c0554d languageName: node linkType: hard -"@graphql-tools/utils@npm:9.0.1": - version: 9.0.1 - resolution: "@graphql-tools/utils@npm:9.0.1" +"@graphql-tools/utils@npm:^9.1.1": + version: 9.1.1 + resolution: "@graphql-tools/utils@npm:9.1.1" dependencies: tslib: ^2.4.0 peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - checksum: a41221d8568bfaafa76526eaa89550d67965c43e0cd1ff94979f61c117d0caf880938799b351c4b637ce26309ba5d2ef8c4a657298f5d46702f43759b89bfa05 + checksum: 5a5120417c00b0f8a834b69dca9b7496022f8b1ed3719c2cf7de8253ff639ecc0f4a8e2bcaf0193ce44bd59431098180e94bdd96406e9f260e058b16c0e26975 languageName: node linkType: hard @@ -9758,7 +10677,7 @@ __metadata: "@types/uuid": ^8.0.0 express: ^4.17.1 express-promise-router: ^4.1.0 - msw: ^0.47.0 + msw: ^0.48.0 supertest: ^6.1.6 uuid: ^8.3.2 winston: ^3.2.1 @@ -9777,7 +10696,7 @@ __metadata: "@backstage/test-utils": "workspace:^" "@types/node": ^16.11.26 cross-fetch: ^3.1.5 - msw: ^0.47.0 + msw: ^0.48.0 languageName: unknown linkType: soft @@ -9799,7 +10718,7 @@ __metadata: "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 "@types/node": ^16.11.26 - msw: ^0.47.0 + msw: ^0.48.0 react-use: ^17.2.4 peerDependencies: react: ^16.13.1 || ^17.0.0 @@ -10662,7 +11581,17 @@ __metadata: languageName: node linkType: hard -"@keyv/redis@npm:^2.2.3": +"@keyv/memcache@npm:^1.3.5": + version: 1.3.5 + resolution: "@keyv/memcache@npm:1.3.5" + dependencies: + json-buffer: ^3.0.1 + memjs: ^1.3.0 + checksum: c457863aeff1c5886c273eafa5fd79a4287cae1d9d3721b6ce5aa699033428ec8930db044224a6ab63d951cdac2408850737d0adc65f0a502bf04cd7dbe0d15e + languageName: node + linkType: hard + +"@keyv/redis@npm:^2.5.3": version: 2.5.3 resolution: "@keyv/redis@npm:2.5.3" dependencies: @@ -12152,8 +13081,8 @@ __metadata: linkType: hard "@pmmmwh/react-refresh-webpack-plugin@npm:^0.5.7": - version: 0.5.8 - resolution: "@pmmmwh/react-refresh-webpack-plugin@npm:0.5.8" + version: 0.5.9 + resolution: "@pmmmwh/react-refresh-webpack-plugin@npm:0.5.9" dependencies: ansi-html-community: ^0.0.8 common-path-prefix: ^3.0.0 @@ -12161,7 +13090,7 @@ __metadata: error-stack-parser: ^2.0.6 find-up: ^5.0.0 html-entities: ^2.1.0 - loader-utils: ^2.0.0 + loader-utils: ^2.0.3 schema-utils: ^3.0.0 source-map: ^0.7.3 peerDependencies: @@ -12186,7 +13115,7 @@ __metadata: optional: true webpack-plugin-serve: optional: true - checksum: 48d8b2813dfba7d482e58a2b0161b79e3a5d608603f1a3c34d709ecc2e6e08f8b14f79934c57849d06f153eb327f18e3d8e1539f978e40ca91539c342f27b8ae + checksum: 446c0add9ecf17ed9911bf310bf22ab64f4b3d0ce334e68a3fcac5efee782ef4d7b6260997efaf720c7a2ea39086db89629e4aa07fb18558387d8dc8f0f31da2 languageName: node linkType: hard @@ -12286,9 +13215,9 @@ __metadata: languageName: node linkType: hard -"@rjsf/core-v5@npm:@rjsf/core@^5.0.0-beta.10": - version: 5.0.0-beta.10 - resolution: "@rjsf/core@npm:5.0.0-beta.10" +"@rjsf/core-v5@npm:@rjsf/core@^5.0.0-beta.12": + version: 5.0.0-beta.12 + resolution: "@rjsf/core@npm:5.0.0-beta.12" dependencies: lodash: ^4.17.15 lodash-es: ^4.17.15 @@ -12297,7 +13226,7 @@ __metadata: peerDependencies: "@rjsf/utils": ^5.0.0-beta.1 react: ^16.14.0 || >=17 - checksum: c3e8852c8fedc6ae23da610033e0bded1bd198cebf7f54a5cdcf3b42d22a3b3864da9c735300cadc7d756f26055a7e62408d51a5ebdb906be9b1bf85bf3712ed + checksum: 6c3fe058a29716cb8d31d436e284aa7ab51ec3c272dc34d49275ea0033c3350a2486249767d454bca20a4ccd00ed910f7ed518d2ebe30693b0218db1b3c990ac languageName: node linkType: hard @@ -12320,16 +13249,16 @@ __metadata: languageName: node linkType: hard -"@rjsf/material-ui-v5@npm:@rjsf/material-ui@^5.0.0-beta.10": - version: 5.0.0-beta.10 - resolution: "@rjsf/material-ui@npm:5.0.0-beta.10" +"@rjsf/material-ui-v5@npm:@rjsf/material-ui@^5.0.0-beta.12": + version: 5.0.0-beta.12 + resolution: "@rjsf/material-ui@npm:5.0.0-beta.12" peerDependencies: "@material-ui/core": ^4.12.3 "@material-ui/icons": ^4.11.2 "@rjsf/core": ^5.0.0-beta.1 "@rjsf/utils": ^5.0.0-beta.1 react: ^16.14.0 || >=17 - checksum: c6e602fc331ec37524837123f42e605389c8ea1a9207ed3e9052de380b91fb90365aa962b0020197f0fb2bcbd87baac34bef7dbbb31ea4b57b6587d0fcd81a09 + checksum: 9b67c64956e74af6230d722fe9510fc50e6133c6913642f5bcbcb8da38b7ff5d912bc90a6b6692eb3df315ba9b330136556fb41854fb351e432433d584c1a969 languageName: node linkType: hard @@ -12345,7 +13274,7 @@ __metadata: languageName: node linkType: hard -"@rjsf/utils@npm:^5.0.0-beta.10": +"@rjsf/utils@npm:^5.0.0-beta.12": version: 5.0.0-beta.12 resolution: "@rjsf/utils@npm:5.0.0-beta.12" dependencies: @@ -12360,9 +13289,9 @@ __metadata: languageName: node linkType: hard -"@rjsf/validator-ajv8@npm:^5.0.0-beta.10": - version: 5.0.0-beta.11 - resolution: "@rjsf/validator-ajv8@npm:5.0.0-beta.11" +"@rjsf/validator-ajv8@npm:^5.0.0-beta.12": + version: 5.0.0-beta.12 + resolution: "@rjsf/validator-ajv8@npm:5.0.0-beta.12" dependencies: ajv: ^8.11.0 ajv-formats: ^2.1.1 @@ -12370,7 +13299,7 @@ __metadata: lodash-es: ^4.17.15 peerDependencies: "@rjsf/utils": ^5.0.0-beta.1 - checksum: e9aec2e77c69ee55fd35cc82b2c3fe0c78cf021145500bc86f7e0a5bae794163dfae198df0543ce635e22cd4235880dcbb7c73487ae0baae6b03e1bdea2955c4 + checksum: 2acd420fdd099b35e534c4086ce5d3759574a8b4dc4b4a21ca35e85b023e6d9688aab1dbfca9381bdbf4aecbe3eb195e27453e8dd9cc70712fe2652e1496840c languageName: node linkType: hard @@ -12399,8 +13328,8 @@ __metadata: linkType: hard "@roadiehq/backstage-plugin-github-insights@npm:^2.0.5": - version: 2.1.0 - resolution: "@roadiehq/backstage-plugin-github-insights@npm:2.1.0" + version: 2.1.1 + resolution: "@roadiehq/backstage-plugin-github-insights@npm:2.1.1" dependencies: "@backstage/catalog-model": ^1.1.2 "@backstage/core-components": ^0.11.2 @@ -12422,7 +13351,7 @@ __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: 33ba1f1cf2370bd0af8cd3b9ed117f432de13be7b7a17dc23d427195826a66f696d0dcf916e6105c02b595d6c1eb151e4d280c8f248f75e8cfff05e8480c7cd8 + checksum: 95f02d4e51e88c7e3acf04b4fa54e68bf20800f0c21a22c4231bc6400cfae0cc11e7f0779f6d82e4d76eb6e97c25e7bd4ca869ada14e668d42741fd9b89f7351 languageName: node linkType: hard @@ -12551,7 +13480,7 @@ __metadata: languageName: node linkType: hard -"@rollup/pluginutils@npm:^4.2.1": +"@rollup/pluginutils@npm:^4.1.1, @rollup/pluginutils@npm:^4.2.1": version: 4.2.1 resolution: "@rollup/pluginutils@npm:4.2.1" dependencies: @@ -12561,22 +13490,6 @@ __metadata: languageName: node linkType: hard -"@rollup/pluginutils@npm:^5.0.1": - version: 5.0.2 - resolution: "@rollup/pluginutils@npm:5.0.2" - dependencies: - "@types/estree": ^1.0.0 - estree-walker: ^2.0.2 - picomatch: ^2.3.1 - peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0 - peerDependenciesMeta: - rollup: - optional: true - checksum: edea15e543bebc7dcac3b0ac8bc7b8e8e6dbd46e2864dbe5dd28072de1fbd5b0e10d545a610c0edaa178e8a7ac432e2a2a52e547ece1308471412caba47db8ce - languageName: node - linkType: hard - "@rushstack/node-core-library@npm:3.45.4": version: 3.45.4 resolution: "@rushstack/node-core-library@npm:3.45.4" @@ -12682,7 +13595,16 @@ __metadata: languageName: node linkType: hard -"@sinonjs/samsam@npm:^6.1.1": +"@sinonjs/fake-timers@npm:^7.1.2": + version: 7.1.2 + resolution: "@sinonjs/fake-timers@npm:7.1.2" + dependencies: + "@sinonjs/commons": ^1.7.0 + checksum: c84773d7973edad5511a31d2cc75023447b5cf714a84de9bb50eda45dda88a0d3bd2c30bf6e6e936da50a048d5352e2151c694e13e59b97d187ba1f329e9a00c + languageName: node + linkType: hard + +"@sinonjs/samsam@npm:^6.0.2, @sinonjs/samsam@npm:^6.1.1": version: 6.1.1 resolution: "@sinonjs/samsam@npm:6.1.1" dependencies: @@ -12934,90 +13856,90 @@ __metadata: languageName: node linkType: hard -"@swc/core-darwin-arm64@npm:1.3.14": - version: 1.3.14 - resolution: "@swc/core-darwin-arm64@npm:1.3.14" +"@swc/core-darwin-arm64@npm:1.3.16": + version: 1.3.16 + resolution: "@swc/core-darwin-arm64@npm:1.3.16" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@swc/core-darwin-x64@npm:1.3.14": - version: 1.3.14 - resolution: "@swc/core-darwin-x64@npm:1.3.14" +"@swc/core-darwin-x64@npm:1.3.16": + version: 1.3.16 + resolution: "@swc/core-darwin-x64@npm:1.3.16" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@swc/core-linux-arm-gnueabihf@npm:1.3.14": - version: 1.3.14 - resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.14" +"@swc/core-linux-arm-gnueabihf@npm:1.3.16": + version: 1.3.16 + resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.16" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@swc/core-linux-arm64-gnu@npm:1.3.14": - version: 1.3.14 - resolution: "@swc/core-linux-arm64-gnu@npm:1.3.14" +"@swc/core-linux-arm64-gnu@npm:1.3.16": + version: 1.3.16 + resolution: "@swc/core-linux-arm64-gnu@npm:1.3.16" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-arm64-musl@npm:1.3.14": - version: 1.3.14 - resolution: "@swc/core-linux-arm64-musl@npm:1.3.14" +"@swc/core-linux-arm64-musl@npm:1.3.16": + version: 1.3.16 + resolution: "@swc/core-linux-arm64-musl@npm:1.3.16" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@swc/core-linux-x64-gnu@npm:1.3.14": - version: 1.3.14 - resolution: "@swc/core-linux-x64-gnu@npm:1.3.14" +"@swc/core-linux-x64-gnu@npm:1.3.16": + version: 1.3.16 + resolution: "@swc/core-linux-x64-gnu@npm:1.3.16" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-x64-musl@npm:1.3.14": - version: 1.3.14 - resolution: "@swc/core-linux-x64-musl@npm:1.3.14" +"@swc/core-linux-x64-musl@npm:1.3.16": + version: 1.3.16 + resolution: "@swc/core-linux-x64-musl@npm:1.3.16" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@swc/core-win32-arm64-msvc@npm:1.3.14": - version: 1.3.14 - resolution: "@swc/core-win32-arm64-msvc@npm:1.3.14" +"@swc/core-win32-arm64-msvc@npm:1.3.16": + version: 1.3.16 + resolution: "@swc/core-win32-arm64-msvc@npm:1.3.16" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@swc/core-win32-ia32-msvc@npm:1.3.14": - version: 1.3.14 - resolution: "@swc/core-win32-ia32-msvc@npm:1.3.14" +"@swc/core-win32-ia32-msvc@npm:1.3.16": + version: 1.3.16 + resolution: "@swc/core-win32-ia32-msvc@npm:1.3.16" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@swc/core-win32-x64-msvc@npm:1.3.14": - version: 1.3.14 - resolution: "@swc/core-win32-x64-msvc@npm:1.3.14" +"@swc/core-win32-x64-msvc@npm:1.3.16": + version: 1.3.16 + resolution: "@swc/core-win32-x64-msvc@npm:1.3.16" conditions: os=win32 & cpu=x64 languageName: node linkType: hard "@swc/core@npm:^1.3.9": - version: 1.3.14 - resolution: "@swc/core@npm:1.3.14" + version: 1.3.16 + resolution: "@swc/core@npm:1.3.16" dependencies: - "@swc/core-darwin-arm64": 1.3.14 - "@swc/core-darwin-x64": 1.3.14 - "@swc/core-linux-arm-gnueabihf": 1.3.14 - "@swc/core-linux-arm64-gnu": 1.3.14 - "@swc/core-linux-arm64-musl": 1.3.14 - "@swc/core-linux-x64-gnu": 1.3.14 - "@swc/core-linux-x64-musl": 1.3.14 - "@swc/core-win32-arm64-msvc": 1.3.14 - "@swc/core-win32-ia32-msvc": 1.3.14 - "@swc/core-win32-x64-msvc": 1.3.14 + "@swc/core-darwin-arm64": 1.3.16 + "@swc/core-darwin-x64": 1.3.16 + "@swc/core-linux-arm-gnueabihf": 1.3.16 + "@swc/core-linux-arm64-gnu": 1.3.16 + "@swc/core-linux-arm64-musl": 1.3.16 + "@swc/core-linux-x64-gnu": 1.3.16 + "@swc/core-linux-x64-musl": 1.3.16 + "@swc/core-win32-arm64-msvc": 1.3.16 + "@swc/core-win32-ia32-msvc": 1.3.16 + "@swc/core-win32-x64-msvc": 1.3.16 dependenciesMeta: "@swc/core-darwin-arm64": optional: true @@ -13041,7 +13963,7 @@ __metadata: optional: true bin: swcx: run_swcx.js - checksum: 79e9857ee3d5af22d9a6e644d7608594fa8ccd9102dbc088addc0f6ee9e1e8e3fc8835545730707395aa47197ab119fa323aedf4184cf51892379b307aedddc0 + checksum: 4361252c928c487a02f526aecd8f3072b923244234c2701916944cf13c252b6d5ce2466caf3e0797d3e92e71a89d4a044f8577e51e8f7fe3af0fe30d94e94b13 languageName: node linkType: hard @@ -13083,8 +14005,8 @@ __metadata: linkType: hard "@tanstack/react-query@npm:^4.1.3": - version: 4.14.5 - resolution: "@tanstack/react-query@npm:4.14.5" + version: 4.14.6 + resolution: "@tanstack/react-query@npm:4.14.6" dependencies: "@tanstack/query-core": 4.14.5 use-sync-external-store: ^1.2.0 @@ -13097,7 +14019,7 @@ __metadata: optional: true react-native: optional: true - checksum: fe98c7900c989512c5818b7aa3c81d81ce2c1149a25e9279f8efcf462a00a156c78c398b5e01c50e5da23788709ed36f8dae4236a51fde459a427a5ece474b0f + checksum: 38e293616aa04ccfe2fec47315c5b98f0b157ee6548b4dbb6a8ca01c90de113e437f5effbc82884f2d860bde54eeb07335e9ed4e233543c7039f717d9855ab9e languageName: node linkType: hard @@ -13755,12 +14677,12 @@ __metadata: linkType: hard "@types/dockerode@npm:^3.3.0": - version: 3.3.12 - resolution: "@types/dockerode@npm:3.3.12" + version: 3.3.13 + resolution: "@types/dockerode@npm:3.3.13" dependencies: "@types/docker-modem": "*" "@types/node": "*" - checksum: 65f16894dca4d359395ed9619ed10d5297917a63b9d86660578e38b97380f5f871188556ab1a5003852e9535a5001ecd7d6c03a1da4391e7c31b30762de55e69 + checksum: dbcf3e33f5d8b731a1540d8b72c91d12583eb87d47adf8defb71f8bc1b328a26a035c66068255929ef99a7906da53ac6e4be76099e8fa7e9720c134b1ab3e153 languageName: node linkType: hard @@ -13817,13 +14739,6 @@ __metadata: languageName: node linkType: hard -"@types/estree@npm:^1.0.0": - version: 1.0.0 - resolution: "@types/estree@npm:1.0.0" - checksum: 910d97fb7092c6738d30a7430ae4786a38542023c6302b95d46f49420b797f21619cdde11fa92b338366268795884111c2eb10356e4bd2c8ad5b92941e9e6443 - languageName: node - linkType: hard - "@types/event-source-polyfill@npm:^1.0.0": version: 1.0.0 resolution: "@types/event-source-polyfill@npm:1.0.0" @@ -14017,11 +14932,11 @@ __metadata: linkType: hard "@types/inquirer@npm:^8.1.3": - version: 8.2.4 - resolution: "@types/inquirer@npm:8.2.4" + version: 8.2.5 + resolution: "@types/inquirer@npm:8.2.5" dependencies: "@types/through": "*" - checksum: 3a46231faac1e5df4863a2d501617b3f25e9481ea8a966a9b866bafef01fcc151606d9f25cb66f90492dd0d1d7af7c675a2314f50db85a7f2aeed265d93eb412 + checksum: 932c432e634697bcff5d50fdc9e64f90d2e31c5ebcda909f2e9704d0433b5ec608b6ece985c6e57a283f3b62434f1cd3619b64ca61433d7c3bdb41d3c5f27586 languageName: node linkType: hard @@ -14257,9 +15172,9 @@ __metadata: linkType: hard "@types/luxon@npm:^3.0.0": - version: 3.0.2 - resolution: "@types/luxon@npm:3.0.2" - checksum: e47e199c5d70ce16e4eff54b21fdf385065f1134774109b40c36dba8b5fd29a732b763125e93863d6070dd22ba6a3f18dbdd368cf3748aae9f24bb335c5c210d + version: 3.1.0 + resolution: "@types/luxon@npm:3.1.0" + checksum: 04768029342ad76fc2a9339436c143ea64797b35cf9b03ddded787c13eae30f0ca1246e51c2c5365ed912f98068e13a967a3931b137eb4585248a0ad7ec3fa86 languageName: node linkType: hard @@ -14900,6 +15815,22 @@ __metadata: languageName: node linkType: hard +"@types/sinon@npm:^10.0.10": + version: 10.0.13 + resolution: "@types/sinon@npm:10.0.13" + dependencies: + "@types/sinonjs__fake-timers": "*" + checksum: 46a14c888db50f0098ec53d451877e0111d878ec4a653b9e9ed7f8e54de386d6beb0e528ddc3e95cd3361a8ab9ad54e4cca33cd88d45b9227b83e9fc8fb6688a + languageName: node + linkType: hard + +"@types/sinonjs__fake-timers@npm:*": + version: 8.1.2 + resolution: "@types/sinonjs__fake-timers@npm:8.1.2" + checksum: bbc73a5ab6c0ec974929392f3d6e1e8db4ebad97ec506d785301e1c3d8a4f98a35b1aa95b97035daef02886fd8efd7788a2fa3ced2ec7105988bfd8dce61eedd + 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" @@ -15479,9 +16410,9 @@ __metadata: languageName: node linkType: hard -"@uiw/codemirror-extensions-basic-setup@npm:4.12.4": - version: 4.12.4 - resolution: "@uiw/codemirror-extensions-basic-setup@npm:4.12.4" +"@uiw/codemirror-extensions-basic-setup@npm:4.13.2": + version: 4.13.2 + resolution: "@uiw/codemirror-extensions-basic-setup@npm:4.13.2" dependencies: "@codemirror/autocomplete": ^6.0.0 "@codemirror/commands": ^6.0.0 @@ -15498,19 +16429,19 @@ __metadata: "@codemirror/search": ">=6.0.0" "@codemirror/state": ">=6.0.0" "@codemirror/view": ">=6.0.0" - checksum: 27c65e051383cedf0ea63b3c923caf10aa45dba7cec01b3a767d81d1d0114ba221665bf0d8166f8de67946806fde7348768cf4a7683a70907e9f2eef9c99dbea + checksum: 5597d6bd7ea0304aa15f77c4bec4a071d95ae9b706a2abd6486f5fc51dba4a89101fa1e6faeb8f4fc27f4698993b008c3fd751a864618eef6baef56434d1fafd languageName: node linkType: hard "@uiw/react-codemirror@npm:^4.9.3": - version: 4.12.4 - resolution: "@uiw/react-codemirror@npm:4.12.4" + version: 4.13.2 + resolution: "@uiw/react-codemirror@npm:4.13.2" 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.12.4 + "@uiw/codemirror-extensions-basic-setup": 4.13.2 codemirror: ^6.0.0 peerDependencies: "@babel/runtime": ">=7.11.0" @@ -15520,7 +16451,7 @@ __metadata: codemirror: ">=6.0.0" react: ">=16.8.0" react-dom: ">=16.8.0" - checksum: e7228beb95e918929e99e819c4f3b3920a16c5aca2477775c41bd16166af5bb7b5cefe240bd75b80fd9f61cde82086f93f8cd2dc1e2a4ecf02ff6d756cfd6f42 + checksum: 8f35aa2f54beabc440027584ccd6244f4d2e52e0792f700fb8612f1a5c8d0d705203ddddd202b3d6b82a3b1426bd4bdb230f76a5ec1ae41ec3806e9b2c955900 languageName: node linkType: hard @@ -15789,7 +16720,7 @@ __metadata: languageName: node linkType: hard -"abbrev@npm:1": +"abbrev@npm:1, abbrev@npm:^1.0.0": version: 1.1.1 resolution: "abbrev@npm:1.1.1" checksum: a4a97ec07d7ea112c517036882b2ac22f3109b7b19077dc656316d07d308438aac28e4d9746dc4d84bf6b1e75b4a7b0a5f3cb30592419f128ca9a8cee3bcfa17 @@ -16004,7 +16935,7 @@ __metadata: languageName: node linkType: hard -"ajv@npm:^8.0.0, ajv@npm:^8.10.0, ajv@npm:^8.11.0, ajv@npm:^8.6.3, ajv@npm:^8.8.0": +"ajv@npm:^8.0.0, ajv@npm:^8.11.0, ajv@npm:^8.6.3, ajv@npm:^8.8.0": version: 8.11.0 resolution: "ajv@npm:8.11.0" dependencies: @@ -16016,6 +16947,18 @@ __metadata: languageName: node linkType: hard +"ajv@npm:^8.10.0": + version: 8.11.2 + resolution: "ajv@npm:8.11.2" + dependencies: + fast-deep-equal: ^3.1.1 + json-schema-traverse: ^1.0.0 + require-from-string: ^2.0.2 + uri-js: ^4.2.2 + checksum: 53435bf79ee7d1eabba8085962dba4c08d08593334b304db7772887f0b7beebc1b3d957432f7437ed4b60e53b5d966a57b439869890209c50fed610459999e3e + languageName: node + linkType: hard + "alphanum-sort@npm:^1.0.2": version: 1.0.2 resolution: "alphanum-sort@npm:1.0.2" @@ -16739,6 +17682,17 @@ __metadata: languageName: node linkType: hard +"aws-sdk-client-mock@npm:^2.0.0": + version: 2.0.0 + resolution: "aws-sdk-client-mock@npm:2.0.0" + dependencies: + "@types/sinon": ^10.0.10 + sinon: ^11.1.1 + tslib: ^2.1.0 + checksum: e6081ca6bb72f5c082dfcd93155bbb7e1c9e8d3d346914ed05d736c495a5ef99ab3d0253507aff2e07b5b995fae63671e53e094437ddfaf8649d69725628ff8f + languageName: node + linkType: hard + "aws-sdk-mock@npm:^5.2.1": version: 5.7.0 resolution: "aws-sdk-mock@npm:5.7.0" @@ -17395,6 +18349,13 @@ __metadata: languageName: node linkType: hard +"bowser@npm:^2.11.0": + version: 2.11.0 + resolution: "bowser@npm:2.11.0" + checksum: 29c3f01f22e703fa6644fc3b684307442df4240b6e10f6cfe1b61c6ca5721073189ca97cdeedb376081148c8518e33b1d818a57f781d70b0b70e1f31fb48814f + languageName: node + linkType: hard + "brace-expansion@npm:^1.1.7": version: 1.1.11 resolution: "brace-expansion@npm:1.1.11" @@ -18152,6 +19113,13 @@ __metadata: languageName: node linkType: hard +"ci-info@npm:^2.0.0": + version: 2.0.0 + resolution: "ci-info@npm:2.0.0" + checksum: 3b374666a85ea3ca43fa49aa3a048d21c9b475c96eb13c133505d2324e7ae5efd6a454f41efe46a152269e9b6a00c9edbe63ec7fa1921957165aae16625acd67 + languageName: node + linkType: hard + "ci-info@npm:^3.1.0, ci-info@npm:^3.2.0": version: 3.3.2 resolution: "ci-info@npm:3.3.2" @@ -19022,7 +19990,7 @@ __metadata: languageName: node linkType: hard -"copy-to-clipboard@npm:^3, copy-to-clipboard@npm:^3.2.0, copy-to-clipboard@npm:^3.3.1": +"copy-to-clipboard@npm:^3.2.0, copy-to-clipboard@npm:^3.3.1": version: 3.3.1 resolution: "copy-to-clipboard@npm:3.3.1" dependencies: @@ -19077,9 +20045,9 @@ __metadata: linkType: hard "core-js@npm:^3.6.5": - version: 3.26.0 - resolution: "core-js@npm:3.26.0" - checksum: 0149eb9d3909fde9c17626af3a6e625c326e8598d0bb5e6c5b48a18e5fcd4eaf48d4964d873667d8148542ff590fb98eb3f93618da114ca54999d6bc0349734b + version: 3.26.1 + resolution: "core-js@npm:3.26.1" + checksum: 0a01149f51ff1e9f41d1ea49cc4c9222047949ea597189ede7c4cf8cde3b097766b9c7615acc77c86fe65b4002f20b638a133dfba7b41dba830d707aeeed45ad languageName: node linkType: hard @@ -19290,6 +20258,19 @@ __metadata: languageName: node linkType: hard +"cross-spawn@npm:^6.0.5": + version: 6.0.5 + resolution: "cross-spawn@npm:6.0.5" + dependencies: + nice-try: ^1.0.4 + path-key: ^2.0.1 + semver: ^5.5.0 + shebang-command: ^1.2.0 + which: ^1.2.9 + checksum: f893bb0d96cd3d5751d04e67145bdddf25f99449531a72e82dcbbd42796bbc8268c1076c6b3ea51d4d455839902804b94bc45dfb37ecbb32ea8e54a6741c3ab9 + languageName: node + linkType: hard + "cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.1, cross-spawn@npm:^7.0.2, cross-spawn@npm:^7.0.3": version: 7.0.3 resolution: "cross-spawn@npm:7.0.3" @@ -20985,6 +21966,13 @@ __metadata: languageName: node linkType: hard +"entities@npm:2.2.0": + version: 2.2.0 + resolution: "entities@npm:2.2.0" + checksum: 19010dacaf0912c895ea262b4f6128574f9ccf8d4b3b65c7e8334ad0079b3706376360e28d8843ff50a78aabcb8f08f0a32dbfacdc77e47ed77ca08b713669b3 + languageName: node + linkType: hard + "entities@npm:^2.0.0, entities@npm:~2.1.0": version: 2.1.0 resolution: "entities@npm:2.1.0" @@ -21111,20 +22099,13 @@ __metadata: languageName: node linkType: hard -"es-module-lexer@npm:^0.9.0": +"es-module-lexer@npm:^0.9.0, es-module-lexer@npm:^0.9.3": version: 0.9.3 resolution: "es-module-lexer@npm:0.9.3" checksum: 84bbab23c396281db2c906c766af58b1ae2a1a2599844a504df10b9e8dc77ec800b3211fdaa133ff700f5703d791198807bba25d9667392d27a5e9feda344da8 languageName: node linkType: hard -"es-module-lexer@npm:^1.0.5": - version: 1.1.0 - resolution: "es-module-lexer@npm:1.1.0" - checksum: 3e9f5019b69c6b2f04eb8478c4fdb4ed72cb8b4c97511b5dd39c1f498386ed8f5083c32067c15efcfabc7e8460cb65ed4627dd32405475715a898009922f41fa - languageName: node - linkType: hard - "es-shim-unscopables@npm:^1.0.0": version: 1.0.0 resolution: "es-shim-unscopables@npm:1.0.0" @@ -21786,8 +22767,8 @@ __metadata: linkType: hard "eslint-plugin-jest@npm:^27.0.0": - version: 27.1.4 - resolution: "eslint-plugin-jest@npm:27.1.4" + version: 27.1.5 + resolution: "eslint-plugin-jest@npm:27.1.5" dependencies: "@typescript-eslint/utils": ^5.10.0 peerDependencies: @@ -21798,7 +22779,7 @@ __metadata: optional: true jest: optional: true - checksum: b7e3bf0dc092d9936ac1c10a0aceda411935c411c9323def109c2429ccf8486b3faead80fb769119add578c200352729ff96523bffec083f421e1b151404f642 + checksum: 7c9de765793f7161afa0bdcdce67f4d072944152880fa638b25d228188dcee47a4b4aada26c57db72bc10193c96a1979e17afb8a7c3e400e961d8adfbf23ddbe languageName: node linkType: hard @@ -22077,13 +23058,6 @@ __metadata: languageName: node linkType: hard -"estree-walker@npm:^2.0.2": - version: 2.0.2 - resolution: "estree-walker@npm:2.0.2" - checksum: 6151e6f9828abe2259e57f5fd3761335bb0d2ebd76dc1a01048ccee22fabcfef3c0859300f6d83ff0d1927849368775ec5a6d265dde2f6de5a1be1721cd94efc - languageName: node - linkType: hard - "esutils@npm:^2.0.2": version: 2.0.3 resolution: "esutils@npm:2.0.3" @@ -22318,7 +23292,10 @@ __metadata: "@backstage/plugin-azure-sites-backend": "workspace:^" "@backstage/plugin-badges-backend": "workspace:^" "@backstage/plugin-catalog-backend": "workspace:^" + "@backstage/plugin-catalog-node": "workspace:^" "@backstage/plugin-code-coverage-backend": "workspace:^" + "@backstage/plugin-events-backend": "workspace:^" + "@backstage/plugin-events-node": "workspace:^" "@backstage/plugin-graphql-backend": "workspace:^" "@backstage/plugin-jenkins-backend": "workspace:^" "@backstage/plugin-kafka-backend": "workspace:^" @@ -22742,6 +23719,15 @@ __metadata: languageName: node linkType: hard +"fast-xml-parser@npm:3.19.0": + version: 3.19.0 + resolution: "fast-xml-parser@npm:3.19.0" + bin: + xml2js: cli.js + checksum: d9da9145f73d90c05ee2746d80c78eca4da0249dea8c81ea8f1a6e1245e62988ed4a040dbd1c7229b1e0bdcbf69d33c882e0ac337d10c7eedb159a4dc9779327 + languageName: node + linkType: hard + "fastest-stable-stringify@npm:^2.0.2": version: 2.0.2 resolution: "fastest-stable-stringify@npm:2.0.2" @@ -23014,6 +24000,15 @@ __metadata: languageName: node linkType: hard +"find-yarn-workspace-root@npm:^2.0.0": + version: 2.0.0 + resolution: "find-yarn-workspace-root@npm:2.0.0" + dependencies: + micromatch: ^4.0.2 + checksum: fa5ca8f9d08fe7a54ce7c0a5931ff9b7e36f9ee7b9475fb13752bcea80ec6b5f180fa5102d60b376d5526ce924ea3fc6b19301262efa0a5d248dd710f3644242 + languageName: node + linkType: hard + "first-chunk-stream@npm:^2.0.0": version: 2.0.0 resolution: "first-chunk-stream@npm:2.0.0" @@ -23876,8 +24871,8 @@ __metadata: linkType: hard "google-auth-library@npm:^8.0.0": - version: 8.6.0 - resolution: "google-auth-library@npm:8.6.0" + version: 8.7.0 + resolution: "google-auth-library@npm:8.7.0" dependencies: arrify: ^2.0.0 base64-js: ^1.3.0 @@ -23888,7 +24883,7 @@ __metadata: gtoken: ^6.1.0 jws: ^4.0.0 lru-cache: ^6.0.0 - checksum: ba2eed30dc495393cbaa4159e85504944c88c751f780fdff03a98e065c72f160e0918f5ddeb2af3631867f5018d1812ea8c75067d4be051cafdbdcc7b9cc0247 + checksum: 978d1c5f763aceddbc0218cd76fa578c8ba54a0653cefffaf61847bb8d246ebf26e7fcd276d8885b8a3354c17eef0a11cfae9e60e4df62c01cae4378d4eb78e4 languageName: node linkType: hard @@ -24856,11 +25851,11 @@ __metadata: linkType: hard "husky@npm:^8.0.0": - version: 8.0.1 - resolution: "husky@npm:8.0.1" + version: 8.0.2 + resolution: "husky@npm:8.0.2" bin: husky: lib/bin.js - checksum: 943a73a13d0201318fd30e83d299bb81d866bd245b69e6277804c3b462638dc1921694cb94c2b8c920a4a187060f7d6058d3365152865406352e934c5fff70dc + checksum: e101656fcb56163d610488f186448c78b132626aa427094489d886ce9374955a90274912b0f3a34af3326eaa74977883b032e5f701d7aaf4554daa5a7931be43 languageName: node linkType: hard @@ -25464,6 +26459,17 @@ __metadata: languageName: node linkType: hard +"is-ci@npm:^2.0.0": + version: 2.0.0 + resolution: "is-ci@npm:2.0.0" + dependencies: + ci-info: ^2.0.0 + bin: + is-ci: bin.js + checksum: 77b869057510f3efa439bbb36e9be429d53b3f51abd4776eeea79ab3b221337fe1753d1e50058a9e2c650d38246108beffb15ccfd443929d77748d8c0cc90144 + languageName: node + linkType: hard + "is-ci@npm:^3.0.0, is-ci@npm:^3.0.1": version: 3.0.1 resolution: "is-ci@npm:3.0.1" @@ -25534,16 +26540,6 @@ __metadata: languageName: node linkType: hard -"is-dom@npm:^1.0.0": - version: 1.1.0 - resolution: "is-dom@npm:1.1.0" - dependencies: - is-object: ^1.0.1 - is-window: ^1.0.2 - checksum: 72aff0a7366b801c9d598d49452ec06544b52c3da92a0c6c3cacace33bb0c3df5ba1b4e422ac39224773316a553699d5920a1eb136919319f57d00e6384eb41b - languageName: node - linkType: hard - "is-extglob@npm:^2.1.1": version: 2.1.1 resolution: "is-extglob@npm:2.1.1" @@ -25695,13 +26691,6 @@ __metadata: languageName: node linkType: hard -"is-object@npm:^1.0.1": - version: 1.0.1 - resolution: "is-object@npm:1.0.1" - checksum: 845eea5ecea9723c04809c9c502a19f318b486f796b128a7b8e5a228c7256c3db8c8201043577542075632e292cd4dfeb04627f12f53817d7bd9f30485cf4c34 - languageName: node - linkType: hard - "is-path-cwd@npm:^2.2.0": version: 2.2.0 resolution: "is-path-cwd@npm:2.2.0" @@ -25966,13 +26955,6 @@ __metadata: languageName: node linkType: hard -"is-window@npm:^1.0.2": - version: 1.0.2 - resolution: "is-window@npm:1.0.2" - checksum: aeaacd2ca816d38d4e2fba4670158fba2190061f28a61c5d84df7c479abf8897b8cb634d22cb76cdf7805035e95bebd430faaab6231ac2ebc814eae02d2c8fd4 - languageName: node - linkType: hard - "is-windows@npm:^1.0.0, is-windows@npm:^1.0.1": version: 1.0.2 resolution: "is-windows@npm:1.0.2" @@ -25980,7 +26962,7 @@ __metadata: languageName: node linkType: hard -"is-wsl@npm:^2.2.0": +"is-wsl@npm:^2.1.1, is-wsl@npm:^2.2.0": version: 2.2.0 resolution: "is-wsl@npm:2.2.0" dependencies: @@ -26792,13 +27774,20 @@ __metadata: languageName: node linkType: hard -"jose@npm:^4.10.0, jose@npm:^4.6.0": +"jose@npm:^4.10.0": version: 4.10.4 resolution: "jose@npm:4.10.4" checksum: 0e6caaae0b0303534c0ac23711d45eadfbdbff63d9aeed80965c668b5532c254ab25b48afddc3e1ecfcfd36b4275dee41174a097c5a47a25ce04268c78f3c130 languageName: node linkType: hard +"jose@npm:^4.6.0": + version: 4.11.0 + resolution: "jose@npm:4.11.0" + checksum: 8d81e978e0da306911b61b1de1e2d78bd4903b4aa68a4b338b7c89c41edc3d56aea4d5ef4784a078a630dd6aa81f6328901ae3ce215f33b90d51ee8ebf4c9dbd + languageName: node + linkType: hard + "joycon@npm:^3.0.1": version: 3.1.0 resolution: "joycon@npm:3.1.0" @@ -26806,13 +27795,6 @@ __metadata: languageName: node linkType: hard -"joycon@npm:^3.1.1": - version: 3.1.1 - resolution: "joycon@npm:3.1.1" - checksum: 8003c9c3fc79c5c7602b1c7e9f7a2df2e9916f046b0dbad862aa589be78c15734d11beb9fe846f5e06138df22cb2ad29961b6a986ba81c4920ce2b15a7f11067 - languageName: node - linkType: hard - "jpeg-js@npm:^0.3.4": version: 0.3.7 resolution: "jpeg-js@npm:0.3.7" @@ -27289,7 +28271,7 @@ __metadata: languageName: node linkType: hard -"jsonc-parser@npm:^3.2.0": +"jsonc-parser@npm:^3.0.0, jsonc-parser@npm:^3.2.0": version: 3.2.0 resolution: "jsonc-parser@npm:3.2.0" checksum: 946dd9a5f326b745aa326d48a7257e3f4a4b62c5e98ec8e49fa2bdd8d96cef7e6febf1399f5c7016114fd1f68a1c62c6138826d5d90bc650448e3cf0951c53c7 @@ -27601,17 +28583,7 @@ __metadata: languageName: node linkType: hard -"keyv-memcache@npm:^1.2.5": - version: 1.2.9 - resolution: "keyv-memcache@npm:1.2.9" - dependencies: - json-buffer: ^3.0.1 - memjs: ^1.3.0 - checksum: d5134c69be50407498b425d4b8a45204d3a69cfcc2572dd089804f95f4fd9516e7bc6e1fce0e90d036a615e79d72fe8f0f9b17c30dbc66ceabf77f891ac4bbcf - languageName: node - linkType: hard - -"keyv@npm:^4.0.0, keyv@npm:^4.0.3": +"keyv@npm:^4.0.0": version: 4.5.0 resolution: "keyv@npm:4.5.0" dependencies: @@ -27620,6 +28592,15 @@ __metadata: languageName: node linkType: hard +"keyv@npm:^4.5.2": + version: 4.5.2 + resolution: "keyv@npm:4.5.2" + dependencies: + json-buffer: 3.0.1 + checksum: 13ad58303acd2261c0d4831b4658451603fd159e61daea2121fcb15feb623e75ee328cded0572da9ca76b7b3ceaf8e614f1806c6b3af5db73c9c35a345259651 + languageName: node + linkType: hard + "kind-of@npm:^6.0.2, kind-of@npm:^6.0.3": version: 6.0.3 resolution: "kind-of@npm:6.0.3" @@ -27627,6 +28608,15 @@ __metadata: languageName: node linkType: hard +"klaw-sync@npm:^6.0.0": + version: 6.0.0 + resolution: "klaw-sync@npm:6.0.0" + dependencies: + graceful-fs: ^4.1.11 + checksum: 0da397f8961313c3ef8f79fb63af9002cde5a8fb2aeb1a37351feff0dd6006129c790400c3f5c3b4e757bedcabb13d21ec0a5eaef5a593d59515d4f2c291e475 + languageName: node + linkType: hard + "klaw@npm:^3.0.0": version: 3.0.0 resolution: "klaw@npm:3.0.0" @@ -27995,13 +28985,13 @@ __metadata: linkType: hard "loader-utils@npm:^1.1.0": - version: 1.4.0 - resolution: "loader-utils@npm:1.4.0" + version: 1.4.1 + resolution: "loader-utils@npm:1.4.1" dependencies: big.js: ^5.2.2 emojis-list: ^3.0.0 json5: ^1.0.1 - checksum: d150b15e7a42ac47d935c8b484b79e44ff6ab4c75df7cc4cb9093350cf014ec0b17bdb60c5d6f91a37b8b218bd63b973e263c65944f58ca2573e402b9a27e717 + checksum: ea0b648cba0194e04a90aab6270619f0e35be009e33a443d9e642e93056cd49e6ca4c9678bd1c777a2392551bc5f4d0f24a87f5040608da1274aa84c6eebb502 languageName: node linkType: hard @@ -28016,6 +29006,17 @@ __metadata: languageName: node linkType: hard +"loader-utils@npm:^2.0.3": + version: 2.0.3 + resolution: "loader-utils@npm:2.0.3" + dependencies: + big.js: ^5.2.2 + emojis-list: ^3.0.0 + json5: ^2.1.2 + checksum: d055c61ce5927b64cb4af40218606603a7d3a39adb7b6eec116bb31d19203875950e478152dea056de404eced8e87e9bfd336ec636591ded040ea451f63c7d88 + languageName: node + linkType: hard + "loader-utils@npm:^3.2.0": version: 3.2.0 resolution: "loader-utils@npm:3.2.0" @@ -28465,9 +29466,9 @@ __metadata: linkType: hard "luxon@npm:^3.0.0": - version: 3.0.4 - resolution: "luxon@npm:3.0.4" - checksum: d0908c3951da2a10ccf23040210ead23b0da5366a9d0954e7d5db3560189a7bd703d8af1e00084f197effc9cd7158d1bddf32886d98a70d59ce9bc3fe88bbce0 + version: 3.1.0 + resolution: "luxon@npm:3.1.0" + checksum: f8a850b759ba7a2e009d904c522ed7bc264bf4add57578f8948e52a0ed96b627b025b5aad8032295b570ae19fac41f0ffab91bdb128715fb0cc020798a7ba886 languageName: node linkType: hard @@ -29742,9 +30743,9 @@ __metadata: linkType: hard "mock-fs@npm:^5.1.0, mock-fs@npm:^5.1.1": - version: 5.1.4 - resolution: "mock-fs@npm:5.1.4" - checksum: e5621c9162be71f88ba264c32cbbc2df737b4e243608ca9126f05b6b1410f1ca911e155a36d3785f194b4219438df8fa33d79cd7ef0b8c7701efd0e4a11f0630 + version: 5.2.0 + resolution: "mock-fs@npm:5.2.0" + checksum: c25835247bd26fa4e0189addd61f98973f61a72741e4d2a5694b143a2069b84978443a7ac0fdb1a71aead99273ec22ff4e9c968de11bbd076db020264c5b8312 languageName: node linkType: hard @@ -29832,9 +30833,9 @@ __metadata: languageName: node linkType: hard -"msw@npm:^0.47.0": - version: 0.47.4 - resolution: "msw@npm:0.47.4" +"msw@npm:^0.48.0": + version: 0.48.0 + resolution: "msw@npm:0.48.0" dependencies: "@mswjs/cookies": ^0.2.2 "@mswjs/interceptors": ^0.17.5 @@ -29863,7 +30864,7 @@ __metadata: optional: true bin: msw: cli/index.js - checksum: 10ff632641d40384d6622abf4df6399e4ae649db0f676b5d1ee2d0a515ec96f33abe9d4fecba08cdba4b2e43255af419da9eefc020d40a7e10669d0906457197 + checksum: a931232d18ad02c8b98ffb5db507824d619860743eab6ecf2c228a403b5a20e2b167d4e0ef6cdd7ca2c0d1e4cc913dce1a690e80d7ef3ec6724d3ee060abc477 languageName: node linkType: hard @@ -30031,7 +31032,14 @@ __metadata: languageName: node linkType: hard -"nise@npm:^5.1.1": +"nice-try@npm:^1.0.4": + version: 1.0.5 + resolution: "nice-try@npm:1.0.5" + checksum: 0b4af3b5bb5d86c289f7a026303d192a7eb4417231fe47245c460baeabae7277bcd8fd9c728fb6bd62c30b3e15cd6620373e2cf33353b095d8b403d3e8a15aff + languageName: node + linkType: hard + +"nise@npm:^5.1.0, nise@npm:^5.1.1": version: 5.1.1 resolution: "nise@npm:5.1.1" dependencies: @@ -30136,7 +31144,27 @@ __metadata: languageName: node linkType: hard -"node-gyp@npm:^9.1.0, node-gyp@npm:latest": +"node-gyp@npm:^9.1.0": + version: 9.3.0 + resolution: "node-gyp@npm:9.3.0" + dependencies: + env-paths: ^2.2.0 + glob: ^7.1.4 + graceful-fs: ^4.2.6 + make-fetch-happen: ^10.0.3 + nopt: ^6.0.0 + npmlog: ^6.0.0 + rimraf: ^3.0.2 + semver: ^7.3.5 + tar: ^6.1.2 + which: ^2.0.2 + bin: + node-gyp: bin/node-gyp.js + checksum: 589ddd3ed967724ef425f9624bfa47cf73022640ab3eba6d556e92cdc4ddef33b63fce3a467c93b995a3f61df92eafd3c3d1e8dbe4a2c00c383334487dea99c3 + languageName: node + linkType: hard + +"node-gyp@npm:latest": version: 9.1.0 resolution: "node-gyp@npm:9.1.0" dependencies: @@ -30257,6 +31285,17 @@ __metadata: languageName: node linkType: hard +"nopt@npm:^6.0.0": + version: 6.0.0 + resolution: "nopt@npm:6.0.0" + dependencies: + abbrev: ^1.0.0 + bin: + nopt: bin/nopt.js + checksum: 82149371f8be0c4b9ec2f863cc6509a7fd0fa729929c009f3a58e4eb0c9e4cae9920e8f1f8eb46e7d032fec8fb01bede7f0f41a67eb3553b7b8e14fa53de1dac + languageName: node + linkType: hard + "normalize-package-data@npm:^2.3.2, normalize-package-data@npm:^2.5.0": version: 2.5.0 resolution: "normalize-package-data@npm:2.5.0" @@ -30624,11 +31663,11 @@ __metadata: linkType: hard "octokit-plugin-create-pull-request@npm:^3.10.0": - version: 3.12.2 - resolution: "octokit-plugin-create-pull-request@npm:3.12.2" + version: 3.13.1 + resolution: "octokit-plugin-create-pull-request@npm:3.13.1" dependencies: "@octokit/types": ^6.8.2 - checksum: 1f23b6ab62f148795eb7d0109bbfbaf022760ccd17eca2d8d6e0dd860ec76d509fcc0e94841caedaf1e5fe48885cec080fdf8c1cddf0736d0c119070eb7f371f + checksum: 169e393046cecc51b9c9be23321086fc60681bfdfe2bcec5477d0916e5b8e3b64b54588f631f61d98677a0561f5d44fa85589abd75ff851122c798795921292b languageName: node linkType: hard @@ -30723,6 +31762,16 @@ __metadata: languageName: node linkType: hard +"open@npm:^7.4.2": + version: 7.4.2 + resolution: "open@npm:7.4.2" + dependencies: + is-docker: ^2.0.0 + is-wsl: ^2.1.1 + checksum: 3333900ec0e420d64c23b831bc3467e57031461d843c801f569b2204a1acc3cd7b3ec3c7897afc9dde86491dfa289708eb92bba164093d8bd88fb2c231843c91 + languageName: node + linkType: hard + "open@npm:^8.0.0, open@npm:^8.0.9, open@npm:^8.4.0": version: 8.4.0 resolution: "open@npm:8.4.0" @@ -30751,7 +31800,7 @@ __metadata: languageName: node linkType: hard -"openid-client@npm:^5.1.6, openid-client@npm:^5.2.1": +"openid-client@npm:^5.1.6": version: 5.2.1 resolution: "openid-client@npm:5.2.1" dependencies: @@ -30763,6 +31812,18 @@ __metadata: languageName: node linkType: hard +"openid-client@npm:^5.2.1": + version: 5.3.0 + resolution: "openid-client@npm:5.3.0" + dependencies: + jose: ^4.10.0 + lru-cache: ^6.0.0 + object-hash: ^2.0.1 + oidc-token-hash: ^5.0.1 + checksum: 27faa298e083daae2a2a99629b25cc89f648302f4845dd1acd04ec6e7105a6edf13a5c38ab1159bcb7b88c5bc54be08e021c911e22f0b8bfcca1b2d686ae3d95 + languageName: node + linkType: hard + "optionator@npm:^0.8.1": version: 0.8.3 resolution: "optionator@npm:0.8.3" @@ -31435,6 +32496,30 @@ __metadata: languageName: node linkType: hard +"patch-package@npm:^6.5.0": + version: 6.5.0 + resolution: "patch-package@npm:6.5.0" + dependencies: + "@yarnpkg/lockfile": ^1.1.0 + chalk: ^4.1.2 + cross-spawn: ^6.0.5 + find-yarn-workspace-root: ^2.0.0 + fs-extra: ^7.0.1 + is-ci: ^2.0.0 + klaw-sync: ^6.0.0 + minimist: ^1.2.6 + open: ^7.4.2 + rimraf: ^2.6.3 + semver: ^5.6.0 + slash: ^2.0.0 + tmp: ^0.0.33 + yaml: ^1.10.2 + bin: + patch-package: index.js + checksum: d300e87617e3fb990d1f78fd5be205b5a5e65dfdf197b1e7f76f3b3dfe1551a03d276cb5ee6b82ab4d57e78f54ddc22bde803eec1b0896560262b276d0b2c4ab + languageName: node + linkType: hard + "path-browserify@npm:0.0.1": version: 0.0.1 resolution: "path-browserify@npm:0.0.1" @@ -31503,6 +32588,13 @@ __metadata: languageName: node linkType: hard +"path-key@npm:^2.0.1": + version: 2.0.1 + resolution: "path-key@npm:2.0.1" + checksum: f7ab0ad42fe3fb8c7f11d0c4f849871e28fbd8e1add65c370e422512fc5887097b9cf34d09c1747d45c942a8c1e26468d6356e2df3f740bf177ab8ca7301ebfd + 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" @@ -32367,13 +33459,13 @@ __metadata: linkType: hard "postcss@npm:^8.1.0": - version: 8.4.17 - resolution: "postcss@npm:8.4.17" + version: 8.4.19 + resolution: "postcss@npm:8.4.19" dependencies: nanoid: ^3.3.4 picocolors: ^1.0.0 source-map-js: ^1.0.2 - checksum: a6d9096dd711e17f7b1d18ff5dcb4fdedf3941d5a3dc8b0e4ea873b8f31972d57f73d6da9a8aed7ff389eb52190ed34f6a94f299a7f5ddc68b08a24a48f77eb9 + checksum: 62782723a385f92b7525f66d29614624de7c5643855423db3a5efd9287e677650300192749adddbbb6734cea9b1d5f5fd4f6ea00ca3f9a95dbbb88f835f5ca64 languageName: node linkType: hard @@ -33207,19 +34299,7 @@ __metadata: languageName: node linkType: hard -"react-copy-to-clipboard@npm:5.0.4": - version: 5.0.4 - resolution: "react-copy-to-clipboard@npm:5.0.4" - dependencies: - copy-to-clipboard: ^3 - prop-types: ^15.5.8 - peerDependencies: - react: ^15.3.0 || ^16.0.0 || ^17.0.0 - checksum: dae8caae192d4937a151ec3ddad540fe4846d28646aee6d90774abcc6a077761926c99f2bcd9506a76a65524ec2c32b5ec1341e8096fcd3f6335365eaf065137 - languageName: node - linkType: hard - -"react-copy-to-clipboard@npm:^5.0.4": +"react-copy-to-clipboard@npm:5.1.0, react-copy-to-clipboard@npm:^5.0.4": version: 5.1.0 resolution: "react-copy-to-clipboard@npm:5.1.0" dependencies: @@ -33400,16 +34480,12 @@ __metadata: languageName: node linkType: hard -"react-inspector@npm:^5.1.1": - version: 5.1.1 - resolution: "react-inspector@npm:5.1.1" - dependencies: - "@babel/runtime": ^7.0.0 - is-dom: ^1.0.0 - prop-types: ^15.0.0 +"react-inspector@npm:^6.0.1": + version: 6.0.1 + resolution: "react-inspector@npm:6.0.1" peerDependencies: - react: ^16.8.4 || ^17.0.0 - checksum: ca9e4c1fedb94e4e956dd3142838c5a25a9d61375aee5e8a74dd623bae09a263098a93f220e8d84c7fd39e569e1fa4297d363ddbc91b15bca91baeb7281d7f4f + react: ^16.8.4 || ^17.0.0 || ^18.0.0 + checksum: 877cbccf36fdc6213abb9611fb9279c4bb76ef7ecb4ec554b3935419a99d55e6d30a80799a054d468d43cc59a9777f21d22d6219a4597bfbd27f3f08a4cdfdc6 languageName: node linkType: hard @@ -33628,7 +34704,7 @@ __metadata: languageName: node linkType: hard -"react-syntax-highlighter@npm:^15.4.5": +"react-syntax-highlighter@npm:^15.4.5, react-syntax-highlighter@npm:^15.5.0": version: 15.5.0 resolution: "react-syntax-highlighter@npm:15.5.0" dependencies: @@ -34789,18 +35865,18 @@ __metadata: linkType: hard "rollup-plugin-esbuild@npm:^4.7.2": - version: 4.10.2 - resolution: "rollup-plugin-esbuild@npm:4.10.2" + version: 4.10.3 + resolution: "rollup-plugin-esbuild@npm:4.10.3" dependencies: - "@rollup/pluginutils": ^5.0.1 - debug: ^4.3.4 - es-module-lexer: ^1.0.5 - joycon: ^3.1.1 - jsonc-parser: ^3.2.0 + "@rollup/pluginutils": ^4.1.1 + debug: ^4.3.3 + es-module-lexer: ^0.9.3 + joycon: ^3.0.1 + jsonc-parser: ^3.0.0 peerDependencies: esbuild: ">=0.10.1" - rollup: ^1.20.0 || ^2.0.0 || ^3.0.0 - checksum: 0f8e57fe40bf3b9a575cec039bf6d6789dedcbdc3ffee868fccdfe15f5e30e7fd68d7c6550cdbe9de1db7855c700f0bda8b4f10bf3d09b9f6b7516bc48334bc4 + rollup: ^1.20.0 || ^2.0.0 + checksum: 490a6a77573672cfda64a0222bb0dc2c202060bf4e9162571e24f2c26689e0e9faffced9c409eac80b35943dab06d1f0bd8bb3e2d3c6957b6bac1c0d6e5155cc languageName: node linkType: hard @@ -35169,7 +36245,16 @@ __metadata: languageName: node linkType: hard -"selfsigned@npm:^2.0.0, selfsigned@npm:^2.0.1": +"selfsigned@npm:^2.0.0": + version: 2.1.1 + resolution: "selfsigned@npm:2.1.1" + dependencies: + node-forge: ^1 + checksum: aa9ce2150a54838978d5c0aee54d7ebe77649a32e4e690eb91775f71fdff773874a4fbafd0ac73d8ec3b702ff8a395c604df4f8e8868528f36fd6c15076fb43a + languageName: node + linkType: hard + +"selfsigned@npm:^2.0.1": version: 2.0.1 resolution: "selfsigned@npm:2.0.1" dependencies: @@ -35192,7 +36277,7 @@ __metadata: languageName: node linkType: hard -"semver@npm:2 || 3 || 4 || 5, semver@npm:^5.4.1, semver@npm:^5.6.0, semver@npm:^5.7.1": +"semver@npm:2 || 3 || 4 || 5, semver@npm:^5.4.1, semver@npm:^5.5.0, semver@npm:^5.6.0, semver@npm:^5.7.1": version: 5.7.1 resolution: "semver@npm:5.7.1" bin: @@ -35555,6 +36640,20 @@ __metadata: languageName: node linkType: hard +"sinon@npm:^11.1.1": + version: 11.1.2 + resolution: "sinon@npm:11.1.2" + dependencies: + "@sinonjs/commons": ^1.8.3 + "@sinonjs/fake-timers": ^7.1.2 + "@sinonjs/samsam": ^6.0.2 + diff: ^5.0.0 + nise: ^5.1.0 + supports-color: ^7.2.0 + checksum: 1d01377e230c9ba976bf33f28b588bae7901b0b5a503d2f6b2a7914b0dbaa9f09823481926c6f2abed820123c7fa865519695af3ae2e9ba18d8b025616163501 + languageName: node + linkType: hard + "sinon@npm:^13.0.2": version: 13.0.2 resolution: "sinon@npm:13.0.2" @@ -35583,6 +36682,13 @@ __metadata: languageName: node linkType: hard +"slash@npm:^2.0.0": + version: 2.0.0 + resolution: "slash@npm:2.0.0" + checksum: 512d4350735375bd11647233cb0e2f93beca6f53441015eea241fe784d8068281c3987fbaa93e7ef1c38df68d9c60013045c92837423c69115297d6169aa85e6 + languageName: node + linkType: hard + "slash@npm:^3.0.0": version: 3.0.0 resolution: "slash@npm:3.0.0" @@ -35682,13 +36788,13 @@ __metadata: linkType: hard "socket.io-parser@npm:~3.3.0": - version: 3.3.2 - resolution: "socket.io-parser@npm:3.3.2" + version: 3.3.3 + resolution: "socket.io-parser@npm:3.3.3" dependencies: component-emitter: ~1.3.0 debug: ~3.1.0 isarray: 2.0.1 - checksum: 794b3f374faff583a74e2b4fdf55a01761622022d763a0261e3e13889f3088b288caa0f42f092451f7bcc088a4bbad1c48d86871388ff7d5cc5dfc1b15a928b5 + checksum: 6cf464e324e4207811dbf994822c0aa18ba01d615fbed8e3f069927e0e402fdc9b3ac3d2657f18d481fb8c584b1fd40152ced15b3686982a51ec843c6a76dbc2 languageName: node linkType: hard @@ -36620,7 +37726,7 @@ __metadata: languageName: node linkType: hard -"sucrase@npm:^3.18.0, sucrase@npm:^3.20.2": +"sucrase@npm:^3.18.0": version: 3.25.0 resolution: "sucrase@npm:3.25.0" dependencies: @@ -36637,6 +37743,23 @@ __metadata: languageName: node linkType: hard +"sucrase@npm:^3.20.2": + version: 3.28.0 + resolution: "sucrase@npm:3.28.0" + dependencies: + commander: ^4.0.0 + glob: 7.1.6 + lines-and-columns: ^1.1.6 + mz: ^2.7.0 + pirates: ^4.0.1 + ts-interface-checker: ^0.1.9 + bin: + sucrase: bin/sucrase + sucrase-node: bin/sucrase-node + checksum: 6a2369c140cee674988ebcf83538f38b11270e47ebaffc811baabe1db3fc586f1a357d4bbc66388a6b99054ba06a08f31b44b764e777abbd457b9e29332b12d0 + languageName: node + linkType: hard + "superagent@npm:^8.0.0": version: 8.0.0 resolution: "superagent@npm:8.0.0" @@ -36756,8 +37879,8 @@ __metadata: linkType: hard "swagger-ui-react@npm:^4.11.1": - version: 4.14.3 - resolution: "swagger-ui-react@npm:4.14.3" + version: 4.15.5 + resolution: "swagger-ui-react@npm:4.15.5" dependencies: "@babel/runtime-corejs3": ^7.18.9 "@braintree/sanitize-url": =6.0.0 @@ -36771,16 +37894,17 @@ __metadata: js-file-download: ^0.4.12 js-yaml: =4.1.0 lodash: ^4.17.21 + patch-package: ^6.5.0 prop-types: ^15.8.1 randexp: ^0.5.3 randombytes: ^2.1.0 - react-copy-to-clipboard: 5.0.4 + react-copy-to-clipboard: 5.1.0 react-debounce-input: =3.3.0 react-immutable-proptypes: 2.2.0 react-immutable-pure-component: ^2.2.0 - react-inspector: ^5.1.1 + react-inspector: ^6.0.1 react-redux: ^7.2.4 - react-syntax-highlighter: ^15.4.5 + react-syntax-highlighter: ^15.5.0 redux: ^4.1.2 redux-immutable: ^4.0.0 remarkable: ^2.0.1 @@ -36795,7 +37919,7 @@ __metadata: peerDependencies: react: ">=17.0.0" react-dom: ">=17.0.0" - checksum: ae8e932ff7eb0b4be71fd1ad7f00ef3eb461636a83985bd36ea28647f60769e6234a9921ff2f84aa33c370f30b8fa1c30a6ca7cf3c4a6ded963aaf9a337aa197 + checksum: 22a72947da865ebfa9269f66b42c2b50105b6285bcb6546f8f356cf73961f76e397b7d79003641c9569bfb2163ea98e2f3f73a27b5b66843d308786c37362e1c languageName: node linkType: hard @@ -37083,8 +38207,8 @@ __metadata: linkType: hard "testcontainers@npm:^8.1.2": - version: 8.13.1 - resolution: "testcontainers@npm:8.13.1" + version: 8.16.0 + resolution: "testcontainers@npm:8.16.0" dependencies: "@balena/dockerignore": ^1.0.2 "@types/archiver": ^5.3.1 @@ -37098,7 +38222,7 @@ __metadata: properties-reader: ^2.2.0 ssh-remote-port-forward: ^1.0.4 tar-fs: ^2.1.1 - checksum: a15345bed5a7e28cf521a01348ca5c0a9de67e274b628345ac91e6db69793c0f2044fb7634166d849eac1d9ea592c79319bdc7e1ec6c5a0208e2e74548c57a5a + checksum: 2fb8250591691a4bd86640b53e13236ad507ba9e03ac3043683de5e9dd632bc29d52827c22ccfe2b0d28dec6896cbaa56dcb153ce65f7f74212ddefc204e8d6a languageName: node linkType: hard @@ -37577,7 +38701,7 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^1.10.0, tslib@npm:^1.8.1, tslib@npm:^1.9.0, tslib@npm:^1.9.3": +"tslib@npm:^1.10.0, tslib@npm:^1.11.1, tslib@npm:^1.8.1, tslib@npm:^1.9.0, tslib@npm:^1.9.3": version: 1.14.1 resolution: "tslib@npm:1.14.1" checksum: dbe628ef87f66691d5d2959b3e41b9ca0045c3ee3c7c7b906cc1e328b39f199bb1ad9e671c39025bd56122ac57dfbf7385a94843b1cc07c60a4db74795829acd