diff --git a/.changeset/analyze-next-software-creation.md b/.changeset/analyze-next-software-creation.md
new file mode 100644
index 0000000000..0a4ce20e9d
--- /dev/null
+++ b/.changeset/analyze-next-software-creation.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-scaffolder': patch
+---
+
+The `create` and `click` analytics events are now also captured on the "next" version of the component creation page.
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-items-shop.md b/.changeset/blue-items-shop.md
new file mode 100644
index 0000000000..fbf2287864
--- /dev/null
+++ b/.changeset/blue-items-shop.md
@@ -0,0 +1,6 @@
+---
+'@backstage/plugin-cost-insights': patch
+'@backstage/plugin-techdocs': patch
+---
+
+Bumped `canvas` dependency to the latest version, which has better Node.js v18 support.
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/bright-pillows-build.md b/.changeset/bright-pillows-build.md
new file mode 100644
index 0000000000..9939fddf42
--- /dev/null
+++ b/.changeset/bright-pillows-build.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-explore': patch
+---
+
+Added a section to explore plugin README that describes the customization of explore tools content.
diff --git a/.changeset/calm-clouds-smoke.md b/.changeset/calm-clouds-smoke.md
new file mode 100644
index 0000000000..1209c6e071
--- /dev/null
+++ b/.changeset/calm-clouds-smoke.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-github-actions': patch
+---
+
+Add error panel when the plugin fails.
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/clean-socks-call.md b/.changeset/clean-socks-call.md
new file mode 100644
index 0000000000..9b802618f6
--- /dev/null
+++ b/.changeset/clean-socks-call.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-catalog-backend-module-msgraph': patch
+---
+
+Added cause information to logged warnings
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/cool-suns-add.md b/.changeset/cool-suns-add.md
new file mode 100644
index 0000000000..c66de2e2ad
--- /dev/null
+++ b/.changeset/cool-suns-add.md
@@ -0,0 +1,6 @@
+---
+'@backstage/plugin-auth-backend': patch
+'@backstage/plugin-github-actions': patch
+---
+
+Fix wrong GitHub callback URL documentation
diff --git a/.changeset/create-app-1667233110.md b/.changeset/create-app-1667233110.md
new file mode 100644
index 0000000000..b50d431d4b
--- /dev/null
+++ b/.changeset/create-app-1667233110.md
@@ -0,0 +1,5 @@
+---
+'@backstage/create-app': patch
+---
+
+Bumped create-app version.
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/cyan-seahorses-itch.md b/.changeset/cyan-seahorses-itch.md
new file mode 100644
index 0000000000..32d25aa39d
--- /dev/null
+++ b/.changeset/cyan-seahorses-itch.md
@@ -0,0 +1,5 @@
+---
+'@backstage/core-components': patch
+---
+
+Add optional step to SimpleStepper
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/eighty-planets-train.md b/.changeset/eighty-planets-train.md
new file mode 100644
index 0000000000..c4d5d57f6c
--- /dev/null
+++ b/.changeset/eighty-planets-train.md
@@ -0,0 +1,6 @@
+---
+'@backstage/backend-common': patch
+'@backstage/cli': patch
+---
+
+Bumped `tar` dependency to `^6.1.12` in order to ensure Node.js v18 compatibility.
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/funny-singers-serve.md b/.changeset/funny-singers-serve.md
new file mode 100644
index 0000000000..5812bdf5e3
--- /dev/null
+++ b/.changeset/funny-singers-serve.md
@@ -0,0 +1,9 @@
+---
+'@backstage/plugin-splunk-on-call': minor
+---
+
+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.
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/great-planes-arrive.md b/.changeset/great-planes-arrive.md
new file mode 100644
index 0000000000..563c061627
--- /dev/null
+++ b/.changeset/great-planes-arrive.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-org-react': minor
+---
+
+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
diff --git a/.changeset/grumpy-clouds-drum.md b/.changeset/grumpy-clouds-drum.md
new file mode 100644
index 0000000000..cf2d5d2a32
--- /dev/null
+++ b/.changeset/grumpy-clouds-drum.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-scaffolder-backend': minor
+---
+
+- The GitLab Project ID for the `publish:gitlab:merge-request` action is now passed through the query parameter `project` in the `repoUrl`. It still allows people to not use the `projectid` and use the `repoUrl` with the `owner` and `repo` query parameters instead. This makes it easier to publish to repositories instead of writing the full path to the project.
diff --git a/.changeset/hungry-kiwis-scream.md b/.changeset/hungry-kiwis-scream.md
new file mode 100644
index 0000000000..f11125b8c0
--- /dev/null
+++ b/.changeset/hungry-kiwis-scream.md
@@ -0,0 +1,12 @@
+---
+'@backstage/plugin-catalog-graph': patch
+---
+
+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.
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/little-plums-look.md b/.changeset/little-plums-look.md
new file mode 100644
index 0000000000..4fd40ad32a
--- /dev/null
+++ b/.changeset/little-plums-look.md
@@ -0,0 +1,5 @@
+---
+'@backstage/core-components': patch
+---
+
+MissingAnnotationEmptyState now accepts either a string or an array of strings to support multiple missing annotations.
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-cobras-sell.md b/.changeset/lucky-cobras-sell.md
new file mode 100644
index 0000000000..16d86d52e8
--- /dev/null
+++ b/.changeset/lucky-cobras-sell.md
@@ -0,0 +1,9 @@
+---
+'@backstage/plugin-playlist': patch
+'@backstage/plugin-playlist-backend': patch
+---
+
+Updated Playlist plugin docs:
+
+- Updated `playlist` plugin README to include note about installing backend plugin and added images for the various features
+- Updated `playlist-backend` plugin README to remove `IdentityClient` import in example as it is not used and made minor change to headings
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/metal-hairs-mix.md b/.changeset/metal-hairs-mix.md
new file mode 100644
index 0000000000..f795c37506
--- /dev/null
+++ b/.changeset/metal-hairs-mix.md
@@ -0,0 +1,6 @@
+---
+'@backstage/plugin-azure-devops-backend': patch
+---
+
+- Adjusted the asset parser to accept case sensitive
+- Fixed fetching data that was using the deprecated function
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/popular-ants-mix.md b/.changeset/popular-ants-mix.md
new file mode 100644
index 0000000000..f0e6b17f8d
--- /dev/null
+++ b/.changeset/popular-ants-mix.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-org': minor
+---
+
+Updates the User and Group Profile cards to add the links from the UserEntity or the GroupEntity
diff --git a/.changeset/pre.json b/.changeset/pre.json
index a2fd9eb458..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,21 +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",
@@ -199,26 +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",
@@ -226,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-25512c2.md b/.changeset/renovate-25512c2.md
new file mode 100644
index 0000000000..64690469d3
--- /dev/null
+++ b/.changeset/renovate-25512c2.md
@@ -0,0 +1,6 @@
+---
+'@backstage/cli': patch
+'@backstage/plugin-scaffolder-backend': patch
+---
+
+Updated dependency `esbuild` to `^0.15.0`.
diff --git a/.changeset/renovate-3d08223.md b/.changeset/renovate-3d08223.md
new file mode 100644
index 0000000000..76c89644d1
--- /dev/null
+++ b/.changeset/renovate-3d08223.md
@@ -0,0 +1,5 @@
+---
+'@backstage/codemods': patch
+---
+
+Updated dependency `jscodeshift` to `^0.14.0`.
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/rude-mayflies-heal.md b/.changeset/rude-mayflies-heal.md
new file mode 100644
index 0000000000..01cbf01e28
--- /dev/null
+++ b/.changeset/rude-mayflies-heal.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-vault-backend': patch
+---
+
+Added `errorHandler()` middleware to `router` to prevent crashes caused by fatal errors in plugin backend
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/silent-moles-chew.md b/.changeset/silent-moles-chew.md
new file mode 100644
index 0000000000..be71272e28
--- /dev/null
+++ b/.changeset/silent-moles-chew.md
@@ -0,0 +1,8 @@
+---
+'@backstage/backend-common': patch
+'@backstage/plugin-kubernetes': patch
+'@backstage/plugin-kubernetes-backend': patch
+'@backstage/plugin-kubernetes-common': patch
+---
+
+Pin `@kubernetes/client-node` version to `0.17.0`.
diff --git a/.changeset/silly-meals-teach.md b/.changeset/silly-meals-teach.md
new file mode 100644
index 0000000000..ffd80463a3
--- /dev/null
+++ b/.changeset/silly-meals-teach.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-auth-backend': patch
+---
+
+Improve logging
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/thirty-deers-float.md b/.changeset/thirty-deers-float.md
new file mode 100644
index 0000000000..198d6f909d
--- /dev/null
+++ b/.changeset/thirty-deers-float.md
@@ -0,0 +1,19 @@
+---
+'@backstage/create-app': patch
+---
+
+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",
+```
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/two-timers-pump.md b/.changeset/two-timers-pump.md
new file mode 100644
index 0000000000..e3c1ec2351
--- /dev/null
+++ b/.changeset/two-timers-pump.md
@@ -0,0 +1,5 @@
+---
+'@backstage/cli': minor
+---
+
+Switched `tsconfig.json` to target and support `ES2021`, in line with the bump to Node.js 16 & 18.
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/.changeset/witty-carrots-live.md b/.changeset/witty-carrots-live.md
new file mode 100644
index 0000000000..4bafd47dfa
--- /dev/null
+++ b/.changeset/witty-carrots-live.md
@@ -0,0 +1,31 @@
+---
+'@backstage/create-app': patch
+---
+
+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'
+```
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/ISSUE_TEMPLATE/bug.yaml b/.github/ISSUE_TEMPLATE/bug.yaml
new file mode 100644
index 0000000000..782b5fdfa0
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug.yaml
@@ -0,0 +1,84 @@
+name: '๐ Bug Report'
+description: 'Submit a bug report to help us improve'
+title: '๐ Bug Report: '
+labels:
+ - bug
+body:
+ - type: markdown
+ attributes:
+ value: We value your time and effort to submit this bug report. ๐
+ - type: textarea
+ id: description
+ validations:
+ required: true
+ attributes:
+ label: '๐ Description'
+ description: 'A clear and concise description of what the bug is.'
+ placeholder: 'It bugs out when ...'
+ - type: textarea
+ id: expected-behavior
+ validations:
+ required: true
+ attributes:
+ label: '๐ Expected behavior'
+ description: 'What did you think should happen?'
+ placeholder: 'It should ...'
+ - type: textarea
+ id: actual-behavior
+ validations:
+ required: true
+ attributes:
+ label: '๐ Actual Behavior with Screenshots'
+ description: 'What did actually happen? Add screenshots, if applicable.'
+ placeholder: 'It actually ...'
+ - type: textarea
+ id: steps-to-reproduce
+ validations:
+ required: true
+ attributes:
+ label: '๐ Reproduction steps'
+ description: 'How do you trigger this bug? Please walk us through it step by step.'
+ placeholder:
+ "Provide a link to a live example, or an unambiguous set of steps to reproduce this bug. Include code or configuration to reproduce, if relevant.\n
+ 1. Go to '...'\n
+ 2. Click on '....'\n
+ 3. Scroll down to '....'"
+ - type: textarea
+ id: context
+ validations:
+ required: false
+ attributes:
+ label: '๐ Provide the context for the Bug.'
+ description: 'How has this issue affected you? What are you trying to accomplish?'
+ placeholder: 'Providing context (e.g. links to configuration settings, stack trace or log data) helps us come up with a solution that is most useful in the real world.'
+ - type: textarea
+ id: environment
+ validations:
+ required: false
+ attributes:
+ label: '๐ฅ๏ธ Your Environment'
+ description: 'Provide Browser Information
+ Provide Output of `yarn backstage-cli info`'
+ placeholder: 'Include as many relevant details about the environment you experienced the bug in.'
+ - type: checkboxes
+ id: no-duplicate-issues
+ attributes:
+ label: '๐ Have you spent some time to check if this bug has been raised before?'
+ options:
+ - label: "I checked and didn't find similar issue"
+ required: true
+ - type: checkboxes
+ id: read-code-of-conduct
+ attributes:
+ label: '๐ข Have you read the Code of Conduct?'
+ options:
+ - label: 'I have read the [Code of Conduct](https://github.com/backstage/backstage/blob/master/CODE_OF_CONDUCT.md)'
+ required: true
+ - type: dropdown
+ attributes:
+ label: Are you willing to submit PR?
+ description: This is absolutely not required, but we are happy to guide you in the contribution process.
+ options:
+ - Yes I am willing to submit a PR!
+ - No, but I'm happy to collaborate on a PR with someone else
+ - No, I don't have time to work on this right now
diff --git a/.github/ISSUE_TEMPLATE/bug_template.md b/.github/ISSUE_TEMPLATE/bug_template.md
deleted file mode 100644
index 04f8fd68d0..0000000000
--- a/.github/ISSUE_TEMPLATE/bug_template.md
+++ /dev/null
@@ -1,44 +0,0 @@
----
-name: 'Bug Report'
-about: 'Create Bug Report'
-labels: bug
----
-
-
-
-## Expected Behavior
-
-
-
-## Actual Behavior
-
-
-
-## Steps to Reproduce
-
-
-
-
-1. Step 1
-2. Step 2
-3. ...
-
-## Context
-
-
-
-
-
-## Your Environment
-
-
-
-- Browser Information:
-
-- Output of `yarn backstage-cli info`:
-
-```text
-
-```
diff --git a/.github/ISSUE_TEMPLATE/feature.yaml b/.github/ISSUE_TEMPLATE/feature.yaml
new file mode 100644
index 0000000000..9cac5055f1
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature.yaml
@@ -0,0 +1,54 @@
+name: ๐ Feature
+description: 'Submit a proposal for a new feature'
+title: '๐ Feature: '
+labels: [enhancement]
+body:
+ - type: markdown
+ attributes:
+ value: |
+ We value your time and efforts to submit this Feature request form. ๐
+ - type: textarea
+ id: feature-description
+ validations:
+ required: true
+ attributes:
+ label: '๐ Feature description'
+ description: 'A clear and concise description of what the feature is.'
+ placeholder: 'You should add ...'
+ - type: textarea
+ id: context
+ validations:
+ required: true
+ attributes:
+ label: '๐ค Context'
+ description: 'Please explain why this feature should be implemented and how it would be used. Add examples, if applicable.'
+ placeholder: 'In my use-case, ...'
+ - type: textarea
+ id: implementation
+ attributes:
+ label: 'โ๏ธ Possible Implementation'
+ description: 'A clear and concise description of what you want to happen.'
+ placeholder: 'Not obligatory, but ideas as to the implementation of the addition or change'
+ - type: checkboxes
+ id: no-duplicate-issues
+ attributes:
+ label: '๐ Have you spent some time to check if this feature request has been raised before?'
+ options:
+ - label: "I checked and didn't find similar issue"
+ required: true
+ - type: checkboxes
+ id: read-code-of-conduct
+ attributes:
+ label: '๐ข Have you read the Code of Conduct?'
+ options:
+ - label: 'I have read the [Contributing Guidelines](https://github.com/backstage/backstage/blob/master/CODE_OF_CONDUCT.md)'
+ required: true
+ - type: dropdown
+ id: willing-to-submit-pr
+ attributes:
+ label: Are you willing to submit PR?
+ description: This is absolutely not required, but we are happy to guide you in the contribution process.
+ options:
+ - Yes I am willing to submit a PR!
+ - No, but I'm happy to collaborate on a PR with someone else
+ - No, I don't have time to work on this right now
diff --git a/.github/ISSUE_TEMPLATE/feature_template.md b/.github/ISSUE_TEMPLATE/feature_template.md
deleted file mode 100644
index d70622bf52..0000000000
--- a/.github/ISSUE_TEMPLATE/feature_template.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-name: 'Feature Request'
-about: 'Suggest new features and changes'
-labels: enhancement
----
-
-
-
-## Feature Suggestion
-
-
-
-
-## Possible Implementation
-
-
-
-## Context
-
-
-
-
diff --git a/.github/ISSUE_TEMPLATE/plugin.yaml b/.github/ISSUE_TEMPLATE/plugin.yaml
new file mode 100644
index 0000000000..9f3a708b41
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/plugin.yaml
@@ -0,0 +1,52 @@
+name: ๐ Plugin
+description: 'Submit a proposal for a new Plugin'
+title: '๐ Plugin: '
+labels: [plugin]
+body:
+ - type: markdown
+ attributes:
+ value: |
+ We value your time and efforts to submit this Plugin request form. ๐
+ - type: textarea
+ id: plugin-summary
+ validations:
+ required: true
+ attributes:
+ label: '๐ Summary'
+ description: 'Provide a general summary of the plugin and how it should work'
+ placeholder: 'You should add ...'
+ - type: textarea
+ id: website
+ attributes:
+ label: '๐ Project website (if applicable)'
+ description: 'Add a link to the open source project or product this plugin will integrate with, if existing'
+ placeholder: 'Website Link is ...'
+ - type: textarea
+ id: context
+ attributes:
+ label: 'โ๏ธ Context'
+ description: 'A clear and concise description about the Plugin.'
+ placeholder: 'Providing additional context'
+ - type: checkboxes
+ id: no-duplicate-issues
+ attributes:
+ label: '๐ Have you spent some time to check if this plugin request has been raised before?'
+ options:
+ - label: "I checked and didn't find similar issue"
+ required: true
+ - type: checkboxes
+ id: read-code-of-conduct
+ attributes:
+ label: '๐ข Have you read the Code of Conduct?'
+ options:
+ - label: 'I have read the [Contributing Guidelines](https://github.com/backstage/backstage/blob/master/CODE_OF_CONDUCT.md)'
+ required: true
+ - type: dropdown
+ id: willing-to-submit-pr
+ attributes:
+ label: Are you willing to submit PR?
+ description: This is absolutely not required, but we are happy to guide you in the contribution process.
+ options:
+ - Yes I am willing to submit a PR!
+ - No, but I'm happy to collaborate on a PR with someone else
+ - No, I don't have time to work on this right now
diff --git a/.github/ISSUE_TEMPLATE/plugin_template.md b/.github/ISSUE_TEMPLATE/plugin_template.md
deleted file mode 100644
index 75f0828848..0000000000
--- a/.github/ISSUE_TEMPLATE/plugin_template.md
+++ /dev/null
@@ -1,21 +0,0 @@
----
-name: 'Plugin suggestion'
-about: 'Suggest a new Backstage plugin'
-title: '[Plugin] THE PLUGIN NAME'
-labels: plugin
----
-
-
-
-
-## Summary
-
-
-
-## Project website (if applicable)
-
-
-
-## Context
-
-
diff --git a/.github/ISSUE_TEMPLATE/rfc.yaml b/.github/ISSUE_TEMPLATE/rfc.yaml
new file mode 100644
index 0000000000..775c64e674
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/rfc.yaml
@@ -0,0 +1,51 @@
+name: ๐ฌ RFC
+description: 'Request For Comments (RFC) from the community'
+title: '๐ฌ RFC: '
+labels: [rfc]
+body:
+ - type: markdown
+ attributes:
+ value: |
+ We value your time and efforts to submit this RFC form. ๐
+ - type: textarea
+ id: rfc-need
+ validations:
+ required: true
+ attributes:
+ label: '๐ Need'
+ description: 'Let us know why are you proposing this change'
+ placeholder: 'The problem weโre trying to address and the benefits/impact we expect to get from this are ...'
+ - type: textarea
+ id: proposal
+ validations:
+ required: true
+ attributes:
+ label: '๐ Proposal'
+ description: 'Describe the proposal in as much detail as needed for reviewers to give concrete feedback.'
+ placeholder: 'Take special care in this section to describe any implications on data privacy or security.'
+ - type: textarea
+ id: alternatives
+ attributes:
+ label: 'ใฝ๏ธ Alternatives'
+ description: 'What alternatives to the proposed solution were considered?'
+ placeholder: 'What criteria/data was used to discard these?'
+ - type: textarea
+ id: risk
+ attributes:
+ label: 'โ Risks'
+ description: 'What other things happening could conflict or compete (for example for resources) with the proposal?'
+ placeholder: 'What risk are there and how do we plan to handle them?'
+ - type: checkboxes
+ id: no-duplicate-issues
+ attributes:
+ label: '๐ Have you spent some time to check if this RFC has been raised before?'
+ options:
+ - label: "I checked and didn't find similar issue"
+ required: true
+ - type: checkboxes
+ id: read-code-of-conduct
+ attributes:
+ label: '๐ข Have you read the Code of Conduct?'
+ options:
+ - label: 'I have read the [Code of Conduct](https://github.com/backstage/backstage/blob/master/CODE_OF_CONDUCT.md)'
+ required: true
diff --git a/.github/ISSUE_TEMPLATE/rfc_template.md b/.github/ISSUE_TEMPLATE/rfc_template.md
deleted file mode 100644
index c4990ee5d6..0000000000
--- a/.github/ISSUE_TEMPLATE/rfc_template.md
+++ /dev/null
@@ -1,26 +0,0 @@
----
-name: 'RFC'
-about: 'Request For Comments (RFC) from the community'
-labels: rfc
-title: '[RFC] '
----
-
-**Status:** Open for comments
-
-
-
-## Need
-
-
-
-## Proposal
-
-
-
-## Alternatives
-
-
-
-## Risks
-
-
diff --git a/.github/ISSUE_TEMPLATE/ux-component_template.md b/.github/ISSUE_TEMPLATE/ux-component_template.md
deleted file mode 100644
index 95b8f47615..0000000000
--- a/.github/ISSUE_TEMPLATE/ux-component_template.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-name: 'UX Component'
-about: 'For designers to request UX components to be added to the Backstage Storybook'
-labels: design
----
-
-## ๐ General
-
-
-
-
-## ๐ป Usage
-
-
-
-## ๐ Specs
-
-
-
-
-## ๐ฎ Future
-
-
diff --git a/.github/ISSUE_TEMPLATE/ux_component.yaml b/.github/ISSUE_TEMPLATE/ux_component.yaml
new file mode 100644
index 0000000000..453f1e8278
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/ux_component.yaml
@@ -0,0 +1,53 @@
+name: ๐ฆ UX Component
+description: 'For designers to request UX components to be added to the Backstage Storybook'
+title: '๐ฆ UX Component: '
+labels: [design]
+body:
+ - type: markdown
+ attributes:
+ value: |
+ We value your time and efforts to submit this RFC form. ๐
+ - type: textarea
+ id: ux-general
+ validations:
+ required: true
+ attributes:
+ label: '๐ General'
+ description: 'Write a nice note to the community requesting the creation of a new component.'
+ placeholder: 'Include an image of your component. Bonus points for a GIF!'
+ - type: textarea
+ id: usage
+ validations:
+ required: true
+ attributes:
+ label: '๐ป Usage'
+ description: "Tell us what's the point of this component/pattern is."
+ placeholder: 'How does it help? How should it work? Any rules?'
+ - type: textarea
+ id: specs
+ validations:
+ required: true
+ attributes:
+ label: '๐ Specs'
+ description: 'Include images that detail the redlines for your component.'
+ placeholder: "Once we get our Figma workspace set up, we'll be posting the Figma files rather than doing specs by hand."
+ - type: textarea
+ id: future
+ attributes:
+ label: '๐ฎ Future'
+ description: 'List out any upcoming, exciting functionality for this component.'
+ placeholder: 'The component will have ...'
+ - type: checkboxes
+ id: no-duplicate-issues
+ attributes:
+ label: '๐ Have you spent some time to check if this UX Component request has been raised before?'
+ options:
+ - label: "I checked and didn't find similar issue"
+ required: true
+ - type: checkboxes
+ id: read-code-of-conduct
+ attributes:
+ label: '๐ข Have you read the Code of Conduct?'
+ options:
+ - label: 'I have read the [Code of Conduct](https://github.com/backstage/backstage/blob/master/CODE_OF_CONDUCT.md)'
+ required: true
diff --git a/.github/vale/Vocab/Backstage/accept.txt b/.github/vale/Vocab/Backstage/accept.txt
index d21d0f9f25..58f5b57004 100644
--- a/.github/vale/Vocab/Backstage/accept.txt
+++ b/.github/vale/Vocab/Backstage/accept.txt
@@ -4,9 +4,11 @@ ACLs
addon
addons
ADRs
+airbrake
Airbrake
Airbrakes
-airbrake
+Alaria
+Alef
Anddddd
Apdex
api
@@ -26,9 +28,9 @@ Billett
bitbucket
Bitrise
Blackbox
-Brex
bool
boolean
+Brex
builtins
callout
CDNs
@@ -42,6 +44,7 @@ CI/CD
classname
cli
cloudbuild
+Cloudflare
Cloudformation
cncf
Cobertura
@@ -49,11 +52,11 @@ codeblocks
Codecov
codehilite
Codehilite
-codescene
-CodeScene
codemod
codemods
codeowners
+codescene
+CodeScene
composability
composable
config
@@ -75,8 +78,8 @@ Debounce
debuggability
declaratively
deduplicated
-deps
dependabot
+deps
destructured
destructuring
dev
@@ -95,9 +98,9 @@ don'ts
dynatrace
Dynatrace
ecco
+elasticsearch
env
Env
-elasticsearch
esbuild
eslint
ESModule
@@ -117,12 +120,12 @@ Francesco
gerrit
Gerrit
gitbeaker
+gitea
+Gitea
github
Gitiles
gitlab
GitLab
-gitea
-Gitea
Gource
Grafana
graphql
@@ -140,6 +143,7 @@ hotspots
http
https
Iain
+Iglesias
iLert
img
incentivised
@@ -153,12 +157,12 @@ JaCoCo
JavaScript
jenkins
Jira
-JWTs
jq
js
json
jsonnet
jsx
+JWTs
Kaewkasi
Keyv
Knex
@@ -230,6 +234,8 @@ onboarding
Onboarding
OpenShift
orgs
+padding
+paddings
pagerduty
pageview
parallelization
@@ -268,14 +274,13 @@ rebase
Recharts
Redash
replicasets
-statefulsets
repo
Repo
repos
rerender
rerenders
-Reusability
reusability
+Reusability
roadmaps
rollbar
Rollbar
@@ -298,9 +303,9 @@ semver
serializable
Serverless
shoutout
-siloed
SIG
SIGs
+siloed
Sinon
Snyk
Sonarqube
@@ -313,9 +318,11 @@ Spotify
sqlite
squidfunk
src
+statefulsets
stdout
-stringify
+storable
stringified
+stringify
subcomponent
subcomponents
subfolder
@@ -329,10 +336,10 @@ superfences
Superfences
superset
supertype
-storable
SVGs
talkdesk
Talkdesk
+Tanzu
tasklist
techdocs
Telenor
@@ -347,6 +354,7 @@ theia
thumbsup
todo
todos
+togglable
tolerations
Tolerations
toolchain
@@ -374,9 +382,11 @@ upvote
URIs
URLs
utils
+Valentina
validator
validators
varchar
+VMware
VPCs
VSCode
Wayfair
@@ -393,7 +403,6 @@ yaml
Zalando
Zhou
zod
+Zolotusky
zoomable
zsh
-Alef
-Cloudflare
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/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 64067188bb..64d3c166aa 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -17,7 +17,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- node-version: [14.x, 16.x]
+ node-version: [16.x, 18.x]
env:
CI: true
@@ -33,7 +33,7 @@ jobs:
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
- uses: backstage/actions/yarn-install@v0.5.6
+ uses: backstage/actions/yarn-install@v0.5.7
with:
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
@@ -47,7 +47,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- node-version: [14.x, 16.x]
+ node-version: [16.x, 18.x]
env:
CI: true
@@ -63,7 +63,7 @@ jobs:
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
- uses: backstage/actions/yarn-install@v0.5.6
+ uses: backstage/actions/yarn-install@v0.5.7
with:
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
@@ -121,7 +121,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- node-version: [14.x, 16.x]
+ node-version: [16.x, 18.x]
services:
postgres13:
@@ -178,7 +178,7 @@ jobs:
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
- uses: backstage/actions/yarn-install@v0.5.6
+ uses: backstage/actions/yarn-install@v0.5.7
with:
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
@@ -208,7 +208,7 @@ jobs:
- name: test all packages (and upload coverage)
if: ${{ steps.yarn-lock.outcome == 'failure' }}
run: |
- yarn backstage-cli repo test --maxWorkers=2 --workerIdleMemoryLimit=1300M --coverage
+ yarn backstage-cli repo test --maxWorkers=2 --workerIdleMemoryLimit=800M --coverage
bash <(curl -s https://codecov.io/bash) -N $(git rev-parse FETCH_HEAD)
env:
BACKSTAGE_NEXT_TESTS: 1
diff --git a/.github/workflows/cron.yml b/.github/workflows/cron.yml
index 467c817baf..4629d656ce 100644
--- a/.github/workflows/cron.yml
+++ b/.github/workflows/cron.yml
@@ -8,7 +8,7 @@ jobs:
cron:
runs-on: ubuntu-latest
steps:
- - uses: backstage/actions/cron@v0.5.6
+ - uses: backstage/actions/cron@v0.5.7
with:
app-id: ${{ secrets.BACKSTAGE_GOALIE_APPLICATION_ID }}
private-key: ${{ secrets.BACKSTAGE_GOALIE_PRIVATE_KEY }}
diff --git a/.github/workflows/deploy_microsite.yml b/.github/workflows/deploy_microsite.yml
index af6f222377..1f87c30af2 100644
--- a/.github/workflows/deploy_microsite.yml
+++ b/.github/workflows/deploy_microsite.yml
@@ -10,7 +10,7 @@ jobs:
strategy:
matrix:
- node-version: [14.x]
+ node-version: [16.x]
env:
CI: true
diff --git a/.github/workflows/deploy_nightly.yml b/.github/workflows/deploy_nightly.yml
index 476e5dd10b..360a74e012 100644
--- a/.github/workflows/deploy_nightly.yml
+++ b/.github/workflows/deploy_nightly.yml
@@ -11,7 +11,7 @@ jobs:
strategy:
matrix:
- node-version: [14.x]
+ node-version: [16.x]
env:
CI: true
@@ -26,7 +26,7 @@ jobs:
node-version: ${{ matrix.node-version }}
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
- uses: backstage/actions/yarn-install@v0.5.6
+ uses: backstage/actions/yarn-install@v0.5.7
with:
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
diff --git a/.github/workflows/deploy_packages.yml b/.github/workflows/deploy_packages.yml
index f3736d93a2..1d03c210cd 100644
--- a/.github/workflows/deploy_packages.yml
+++ b/.github/workflows/deploy_packages.yml
@@ -13,7 +13,7 @@ jobs:
strategy:
matrix:
- node-version: [14.x, 16.x]
+ node-version: [16.x, 18.x]
services:
postgres13:
@@ -67,7 +67,7 @@ jobs:
node-version: ${{ matrix.node-version }}
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
- uses: backstage/actions/yarn-install@v0.5.6
+ uses: backstage/actions/yarn-install@v0.5.7
with:
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
@@ -130,7 +130,7 @@ jobs:
strategy:
matrix:
- node-version: [14.x]
+ node-version: [16.x]
env:
CI: 'true'
@@ -145,7 +145,7 @@ jobs:
node-version: ${{ matrix.node-version }}
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
- uses: backstage/actions/yarn-install@v0.5.6
+ uses: backstage/actions/yarn-install@v0.5.7
with:
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
diff --git a/.github/workflows/issue.yaml b/.github/workflows/issue.yaml
index 95e91dda30..a42b9b6f7b 100644
--- a/.github/workflows/issue.yaml
+++ b/.github/workflows/issue.yaml
@@ -10,4 +10,4 @@ jobs:
if: github.repository == 'backstage/backstage'
steps:
- name: Issue sync
- uses: backstage/actions/issue-sync@v0.5.6
+ uses: backstage/actions/issue-sync@v0.5.7
diff --git a/.github/workflows/pr-review-comment.yaml b/.github/workflows/pr-review-comment.yaml
index e822209e03..6104a802d9 100644
--- a/.github/workflows/pr-review-comment.yaml
+++ b/.github/workflows/pr-review-comment.yaml
@@ -35,7 +35,7 @@ jobs:
const prNumber = artifact.name.slice('pr_number-'.length)
console.log(`::set-output name=pr-number::${prNumber}`);
- - uses: backstage/actions/re-review@v0.5.6
+ - uses: backstage/actions/re-review@v0.5.7
with:
app-id: ${{ secrets.BACKSTAGE_GOALIE_APPLICATION_ID }}
private-key: ${{ secrets.BACKSTAGE_GOALIE_PRIVATE_KEY }}
diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml
index e13928ccee..4ab7da8e07 100644
--- a/.github/workflows/pr.yaml
+++ b/.github/workflows/pr.yaml
@@ -18,7 +18,7 @@ jobs:
if: github.repository == 'backstage/backstage' && ( github.event.pull_request || github.event.issue.pull_request )
steps:
- name: PR sync
- uses: backstage/actions/pr-sync@v0.5.6
+ uses: backstage/actions/pr-sync@v0.5.7
with:
github-token: ${{ secrets.GH_SERVICE_ACCOUNT_TOKEN }}
app-id: ${{ secrets.BACKSTAGE_GOALIE_APPLICATION_ID }}
diff --git a/.github/workflows/sync_code-formatting.yml b/.github/workflows/sync_code-formatting.yml
index 779284818f..2113efe924 100644
--- a/.github/workflows/sync_code-formatting.yml
+++ b/.github/workflows/sync_code-formatting.yml
@@ -20,7 +20,7 @@ jobs:
node-version: ${{ matrix.node-version }}
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
- uses: backstage/actions/yarn-install@v0.5.6
+ uses: backstage/actions/yarn-install@v0.5.7
with:
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
diff --git a/.github/workflows/sync_snyk-github-issues.yml b/.github/workflows/sync_snyk-github-issues.yml
index dd35ba26f3..c1fb727c33 100644
--- a/.github/workflows/sync_snyk-github-issues.yml
+++ b/.github/workflows/sync_snyk-github-issues.yml
@@ -12,7 +12,7 @@ jobs:
strategy:
matrix:
- node-version: [14.x]
+ node-version: [16.x]
steps:
- uses: actions/checkout@v3
@@ -23,7 +23,7 @@ jobs:
node-version: ${{ matrix.node-version }}
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
- uses: backstage/actions/yarn-install@v0.5.6
+ uses: backstage/actions/yarn-install@v0.5.7
with:
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
diff --git a/.github/workflows/verify_e2e-linux.yml b/.github/workflows/verify_e2e-linux.yml
index 3353a84f3b..a84b315e33 100644
--- a/.github/workflows/verify_e2e-linux.yml
+++ b/.github/workflows/verify_e2e-linux.yml
@@ -31,7 +31,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest]
- node-version: [14.x, 16.x]
+ node-version: [16.x, 18.x]
env:
CI: true
@@ -52,7 +52,7 @@ jobs:
node-version: ${{ matrix.node-version }}
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
- uses: backstage/actions/yarn-install@v0.5.6
+ uses: backstage/actions/yarn-install@v0.5.7
with:
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
diff --git a/.github/workflows/verify_e2e-techdocs.yml b/.github/workflows/verify_e2e-techdocs.yml
index e1bb2246dc..8d59d15899 100644
--- a/.github/workflows/verify_e2e-techdocs.yml
+++ b/.github/workflows/verify_e2e-techdocs.yml
@@ -18,7 +18,7 @@ jobs:
strategy:
matrix:
- node-version: [14.x, 16.x]
+ node-version: [16.x, 18.x]
env:
CI: true
diff --git a/.github/workflows/verify_e2e-tugboat.yml b/.github/workflows/verify_e2e-tugboat.yml
index 04d9e686e2..cb3a463a0d 100644
--- a/.github/workflows/verify_e2e-tugboat.yml
+++ b/.github/workflows/verify_e2e-tugboat.yml
@@ -52,7 +52,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
- node-version: '14'
+ node-version: '16.x'
- name: yarn install
run: yarn --cwd cypress install
diff --git a/.github/workflows/verify_e2e-windows.yml b/.github/workflows/verify_e2e-windows.yml
index 4e8025f7d5..fc29c1f03b 100644
--- a/.github/workflows/verify_e2e-windows.yml
+++ b/.github/workflows/verify_e2e-windows.yml
@@ -22,7 +22,7 @@ jobs:
strategy:
matrix:
os: [windows-2019]
- node-version: [14.x, 16.x]
+ node-version: [16.x, 18.x]
env:
CI: true
diff --git a/.github/workflows/verify_kubernetes.yml b/.github/workflows/verify_kubernetes.yml
index e64ddec586..b92deb96ac 100644
--- a/.github/workflows/verify_kubernetes.yml
+++ b/.github/workflows/verify_kubernetes.yml
@@ -12,7 +12,7 @@ jobs:
strategy:
matrix:
- node-version: [14.x, 16.x]
+ node-version: [16.x, 18.x]
env:
CI: true
@@ -28,7 +28,7 @@ jobs:
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
- uses: backstage/actions/yarn-install@v0.5.6
+ uses: backstage/actions/yarn-install@v0.5.7
with:
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
diff --git a/.github/workflows/verify_microsite.yml b/.github/workflows/verify_microsite.yml
index 50c2116090..3a24befa84 100644
--- a/.github/workflows/verify_microsite.yml
+++ b/.github/workflows/verify_microsite.yml
@@ -12,7 +12,7 @@ jobs:
strategy:
matrix:
- node-version: [14.x]
+ node-version: [16.x]
env:
CI: true
diff --git a/.github/workflows/verify_storybook.yml b/.github/workflows/verify_storybook.yml
index cac94ff682..4fe39fe244 100644
--- a/.github/workflows/verify_storybook.yml
+++ b/.github/workflows/verify_storybook.yml
@@ -35,7 +35,7 @@ jobs:
node-version: ${{ matrix.node-version }}
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
- uses: backstage/actions/yarn-install@v0.5.6
+ uses: backstage/actions/yarn-install@v0.5.7
with:
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
- name: storybook yarn install
diff --git a/.github/workflows/verify_windows.yml b/.github/workflows/verify_windows.yml
index 8bbaa645bf..75a0633cbe 100644
--- a/.github/workflows/verify_windows.yml
+++ b/.github/workflows/verify_windows.yml
@@ -13,7 +13,7 @@ jobs:
strategy:
matrix:
- node-version: [14.x, 16.x]
+ node-version: [16.x, 18.x]
env:
CI: true
diff --git a/ADOPTERS.md b/ADOPTERS.md
index cc5db5dea7..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. |
@@ -215,4 +215,9 @@ _You can do this by using the [Adopter form](https://info.backstage.spotify.com/
| [Ferrovial](https://ferrovial.com) | [Jose Luis Rosado](mailto:jlrosado@ferrovial.com) | Backstage is helping us to improve and acelerate dev experience helping teams to quickly find technical documentation, infrastructure templates, pipelines, software components and quickstarters that have been developed by our squads in a inner source friendly environment. |
| [Inter&Co](https://bancointer.com.br) | [Arnaud Lanna](https://github.com/arnaudlanna), [Adriano Silva](https://github.com/adrianovss), [Bruno Grossi](https://github.com/begrossi) | We're using Backstage as our internal Developer Portal to catalog and collect repositories and microservices pieces of information like ownership, deployment time, and documentation. |
| [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 |
+| [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/README.md b/README.md
index 9a3c4cdb5a..8a2bd338d9 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@
[](https://discord.gg/EBHEGzX)

[](https://codecov.io/gh/backstage/backstage)
-[](https://github.com/backstage/backstage/releases)
+[](https://github.com/backstage/backstage/releases)
## What is Backstage?
@@ -52,7 +52,7 @@ Check out [the documentation](https://backstage.io/docs/getting-started) on how
- [Code of Conduct](CODE_OF_CONDUCT.md) - This is how we roll
- [Adopters](ADOPTERS.md) - Companies already using Backstage
- [Blog](https://backstage.io/blog/) - Announcements and updates
-- [Newsletter](https://mailchi.mp/spotify/backstage-community) - Subscribe to our email newsletter
+- [Newsletter](https://spoti.fi/backstagenewsletter) - Subscribe to our email newsletter
- [Backstage Community Sessions](https://github.com/backstage/community) - Join monthly meetups and explore Backstage community
- Give us a star โญ๏ธ - If you are using Backstage or think it is an interesting project, we would love a star โค๏ธ
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/contrib/docker/devops/Dockerfile b/contrib/docker/devops/Dockerfile
index a7c194618a..8703b2ab48 100644
--- a/contrib/docker/devops/Dockerfile
+++ b/contrib/docker/devops/Dockerfile
@@ -1,4 +1,4 @@
-ARG IMAGE_TAG=14-alpine
+ARG IMAGE_TAG=16-alpine
FROM node:${IMAGE_TAG}
diff --git a/contrib/docker/frontend-with-nginx/Dockerfile.dockerbuild b/contrib/docker/frontend-with-nginx/Dockerfile.dockerbuild
index 41f931544f..053b4fb492 100644
--- a/contrib/docker/frontend-with-nginx/Dockerfile.dockerbuild
+++ b/contrib/docker/frontend-with-nginx/Dockerfile.dockerbuild
@@ -35,7 +35,7 @@
-FROM node:14-buster AS build
+FROM node:16-buster AS build
RUN mkdir /app
COPY . /app
diff --git a/contrib/docs/tutorials/authenticate-api-requests.md b/contrib/docs/tutorials/authenticate-api-requests.md
index 6c5fabd709..49b6ae0a4d 100644
--- a/contrib/docs/tutorials/authenticate-api-requests.md
+++ b/contrib/docs/tutorials/authenticate-api-requests.md
@@ -4,19 +4,15 @@ The Backstage backend APIs are by default available without authentication. To a
API requests from frontend plugins include an authorization header with a Backstage identity token acquired when the user logs in. By adding a middleware that verifies said token to be valid and signed by Backstage, non-authenticated requests can be blocked with a 401 Unauthorized response.
-**NOTE**: Enabling this means that Backstage will stop working for guests, as no token is issued for them.
+**NOTE**: Enabling this means that Backstage will stop working for guests, as no token is issued for them. If you have not done so already, you will also need to implement [service-to-service auth](https://backstage.io/docs/auth/service-to-service-auth).
As techdocs HTML pages load assets without an Authorization header the code below also sets a token cookie when the user logs in (and when the token is about to expire).
Create `packages/backend/src/authMiddleware.ts`:
```typescript
-import { SingleHostDiscovery } from '@backstage/backend-common';
import type { Config } from '@backstage/config';
-import {
- getBearerTokenFromAuthorizationHeader,
- IdentityClient,
-} from '@backstage/plugin-auth-node';
+import { getBearerTokenFromAuthorizationHeader } from '@backstage/plugin-auth-node';
import { NextFunction, Request, Response, RequestHandler } from 'express';
import { decodeJwt } from 'jose';
import { URL } from 'url';
@@ -45,11 +41,6 @@ export const createAuthMiddleware = async (
config: Config,
appEnv: PluginEnvironment,
) => {
- const discovery = SingleHostDiscovery.fromConfig(config);
- const identity = IdentityClient.create({
- discovery,
- issuer: await discovery.getExternalBaseUrl('auth'),
- });
const baseUrl = config.getString('backend.baseUrl');
const secure = baseUrl.startsWith('https://');
const cookieDomain = new URL(baseUrl).hostname;
@@ -61,13 +52,13 @@ export const createAuthMiddleware = async (
try {
const token =
getBearerTokenFromAuthorizationHeader(req.headers.authorization) ||
- (req.cookies.token as string | undefined);
+ (req.cookies?.token as string | undefined);
if (!token) {
res.status(401).send('Unauthorized');
return;
}
try {
- req.user = await identity.authenticate(token);
+ req.user = await appEnv.identity.getIdentity({ request: req });
} catch {
await appEnv.tokenManager.authenticate(token);
}
@@ -180,7 +171,12 @@ export async function setTokenCookie(url: string, identityApi: IdentityApi) {
```
```typescript
-// packages/app/src/App.tsx from a create-app deployment
+// required types and packages for example below
+
+import type { IdentityApi } from '@backstage/core-plugin-api';
+import { discoveryApiRef, useApi } from '@backstage/core-plugin-api';
+
+// additional packages/app/src/App.tsx from a create-app deployment
import { setTokenCookie } from './cookieAuth';
diff --git a/contrib/scaffolder/README.md b/contrib/scaffolder/README.md
new file mode 100644
index 0000000000..e22c4b391f
--- /dev/null
+++ b/contrib/scaffolder/README.md
@@ -0,0 +1,15 @@
+# Scaffolder contrib tools
+
+## Testing Templates with Dry-run
+
+Scaffolder templates support anything that backstage.io and custom actions can do, so testing them is hard without actually running the instance of Backstage that they're designed for.
+
+Please leave [feedback on the RFC](https://github.com/backstage/backstage/issues/14280) on your experience with this approach.
+
+The [command line script](template-testing-dry-run.md) might offer a way for you to do so using the dry-run API used for the Template Editor. Run it against a running instance, either locally or remote, and use it like
+
+```sh
+scaffolder-dry http://localhost:7007/ template-directory values.yml output-directory
+```
+
+If you're using backend permissions, pass a front-end auth token from a current browser session via `--token $FRONTEND_TOKEN`.
diff --git a/contrib/scaffolder/template-testing-dry-run.md b/contrib/scaffolder/template-testing-dry-run.md
new file mode 100644
index 0000000000..70e0c572ab
--- /dev/null
+++ b/contrib/scaffolder/template-testing-dry-run.md
@@ -0,0 +1,150 @@
+```js
+/*
+ * 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.
+ */
+
+/**
+ * A CLI that helps you test Backstage software templates
+ *
+ * @packageDocumentation
+ */
+
+import { dirname, join, relative } from 'node:path';
+import { readFile, writeFile } from 'node:fs/promises';
+import { gzipSync } from 'node:zlib';
+import { ensureDir } from 'fs-extra';
+import { program } from 'commander';
+import fetch from 'node-fetch';
+import ora from 'ora';
+import readdir from 'recursive-readdir';
+import { parse } from 'yaml';
+import { version } from '../../../package.json';
+import type { ScaffolderDryRunResponse } from '@backstage/plugin-scaffolder';
+
+const loadDirectoryContents = async (template_path: string) => {
+ const spinner = ora('Loading template').start();
+ const files = await await readdir(template_path, ['.git']);
+ const contents = await Promise.all(
+ files.map(async p => {
+ return {
+ path: relative(template_path, p),
+ base64Content: (await readFile(p)).toString('base64'),
+ };
+ }),
+ );
+ spinner.succeed();
+ return contents;
+};
+
+const writeResultContents = async (
+ root: string,
+ directoryContents: ScaffolderDryRunResponse['directoryContents'],
+) => {
+ const directories = new Set(
+ directoryContents.map(({ path }) => dirname(join(root, path))),
+ );
+ await Promise.all(Array.from(directories).map(d => ensureDir(d)));
+ await Promise.all(
+ directoryContents.map(async ({ path, base64Content, executable }) =>
+ writeFile(join(root, path), Buffer.from(base64Content, 'base64'), {
+ mode: executable ? 0o755 : 0o644,
+ }),
+ ),
+ );
+};
+
+const api = async (
+ bodyObj: Record,
+ { baseURL, token }: { baseURL: string; token: string | false },
+) => {
+ const body = gzipSync(JSON.stringify(bodyObj));
+ return fetch(new URL('/api/scaffolder/v2/dry-run', baseURL), {
+ method: 'POST',
+ headers: {
+ Authorization: `Bearer ${token || ''}`,
+ 'Content-Type': 'application/json',
+ 'Content-Encoding': 'gzip',
+ },
+ body,
+ });
+};
+
+const handle = async (
+ baseURL: string,
+ template_path: string,
+ data: string,
+ target: string,
+ { token }: { token: string | false },
+) => {
+ const directoryContents = await loadDirectoryContents(template_path);
+ const values = parse(await readFile(data, 'utf-8'));
+ const secrets = {};
+ const template = parse(
+ await readFile(`${template_path}/template.yaml`, 'utf-8'),
+ );
+ const response = await api(
+ {
+ directoryContents,
+ values,
+ secrets,
+ template,
+ },
+ { baseURL, token },
+ );
+ if (!response.ok) {
+ const contentType = response.headers.get('content-type');
+ if (contentType?.startsWith('application/json')) {
+ const responseData = await response.json();
+ if (responseData.error) {
+ throw responseData.error;
+ }
+ if (responseData.errors) {
+ throw responseData.errors;
+ }
+ throw responseData;
+ }
+ throw await response.text();
+ }
+ const { log, directoryContents: resultContents } =
+ (await response.json()) as ScaffolderDryRunResponse;
+ for (const logEntry of log) {
+ console.log(logEntry.body.message);
+ }
+ await writeResultContents(target, resultContents);
+};
+
+const main = async (argv: string[]) => {
+ program
+ .name('backstage-scaffolder')
+ .version(version)
+ .description('Creates a dry-run output of a given template')
+ .option('-t, --token ', 'JWT to use for auth')
+ .argument('url', 'URL of your Backstage instance')
+ .argument('template-path', 'Source directory of template')
+ .argument('data-path', 'YAML file with input to render')
+ .argument('target', 'Output directory')
+ .action(handle);
+
+ await program.parseAsync(argv);
+ process.exit();
+};
+
+process.on('unhandledRejection', rejection => {
+ console.error(rejection);
+ process.exit(1);
+});
+
+main(process.argv);
+```
diff --git a/cypress/tsconfig.json b/cypress/tsconfig.json
index d9b4869ecd..9c4a63b76c 100644
--- a/cypress/tsconfig.json
+++ b/cypress/tsconfig.json
@@ -10,7 +10,7 @@
"incremental": true,
"isolatedModules": true,
"jsx": "react",
- "lib": ["DOM", "DOM.Iterable", "ScriptHost", "ES2020", "ESNext.Promise"],
+ "lib": ["DOM", "DOM.Iterable", "ScriptHost", "ES2021", "ESNext.Promise"],
"module": "ESNext",
"moduleResolution": "node",
"noEmit": true,
@@ -31,7 +31,7 @@
"strictNullChecks": true,
"strictPropertyInitialization": true,
"stripInternal": true,
- "target": "ES2019",
+ "target": "ES2021",
"types": ["node", "cypress"]
}
}
diff --git a/cypress/yarn.lock b/cypress/yarn.lock
index 3b1358156e..07249a29fc 100644
--- a/cypress/yarn.lock
+++ b/cypress/yarn.lock
@@ -414,8 +414,8 @@ __metadata:
linkType: hard
"cypress@npm:^10.0.0":
- version: 10.10.0
- resolution: "cypress@npm:10.10.0"
+ version: 10.11.0
+ resolution: "cypress@npm:10.11.0"
dependencies:
"@cypress/request": ^2.88.10
"@cypress/xvfb": ^1.2.4
@@ -461,7 +461,7 @@ __metadata:
yauzl: ^2.10.0
bin:
cypress: bin/cypress
- checksum: 668a32534a527dba79754abbf98af176b80c539a12ec00058932ba2a19c794c7888323e59e738c30f726ad740c5451c31d02548a0cb7c1b1c8ad01c55a984ca2
+ checksum: 938cc6a20f7eeace5c8e850d234904ee1651cbb36d94666fe600cf17ce964e73d4f7d8d944aab677491702a57364e6aceeb4fe8bcbd96147ff5e2b575a956fb2
languageName: node
linkType: hard
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/github/provider.md b/docs/auth/github/provider.md
index a8c6020cae..353b8ebe08 100644
--- a/docs/auth/github/provider.md
+++ b/docs/auth/github/provider.md
@@ -24,7 +24,7 @@ Settings for local development:
- Application name: Backstage (or your custom app name)
- Homepage URL: `http://localhost:3000`
-- Authorization callback URL: `http://localhost:7007/api/auth/github`
+- Authorization callback URL: `http://localhost:7007/api/auth/github/handler/frame`
## Configuration
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/identity-resolver.md b/docs/auth/identity-resolver.md
index d96c9fc45a..a65f3d7899 100644
--- a/docs/auth/identity-resolver.md
+++ b/docs/auth/identity-resolver.md
@@ -49,7 +49,7 @@ A user identity within Backstage is built up from two pieces of information, a
user [entity reference](../features/software-catalog/references.md), and a
set of ownership entity references.
When a user signs in, a Backstage token is generated with these two pieces of information,
-which is then used to identity the user within the Backstage ecosystem.
+which is then used to identify the user within the Backstage ecosystem.
The user entity reference should uniquely identify the logged in user in Backstage.
It is encouraged that a matching user entity also exists within the Software Catalog,
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/features/search/how-to-guides.md b/docs/features/search/how-to-guides.md
index 01d85b8aa2..5cc2ab5f06 100644
--- a/docs/features/search/how-to-guides.md
+++ b/docs/features/search/how-to-guides.md
@@ -171,6 +171,6 @@ const highlightOverride = {
};
```
-[obj-mode]: https://nodejs.org/docs/latest-v14.x/api/stream.html#stream_object_mode
-[read-stream]: https://nodejs.org/docs/latest-v14.x/api/stream.html#stream_readable_streams
+[obj-mode]: https://nodejs.org/dist/latest-v16.x/docs/api/stream.html#stream_object_mode
+[read-stream]: https://nodejs.org/dist/latest-v16.x/docs/api/stream.html#readable-streams
[async-gen]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of#iterating_over_async_generators
diff --git a/docs/features/software-catalog/external-integrations.md b/docs/features/software-catalog/external-integrations.md
index 40f917e2f3..65f97fb8da 100644
--- a/docs/features/software-catalog/external-integrations.md
+++ b/docs/features/software-catalog/external-integrations.md
@@ -261,6 +261,129 @@ the `connect` call has been made to the provider.
Start up the backend - it should now start reading from the previously
registered location and you'll see your entities start to appear in Backstage.
+### Example User Entity Provider
+
+If you have a 3rd party entity provider such as an internal HR system that you wish to use you are not limited to using our entity providers, (or simply wish to add to existing entity providers with your own data).
+
+We can create an entity provider to read entities that are based off that provider.
+
+We create a basic entity provider as shown above. In the example below we might want to extract our users from an HR system, I am assuming the HR system already has the slackUserId to get that information please see the [Slack Api](https://api.slack.com/methods).
+
+```typescript
+import {
+ ANNOTATION_LOCATION,
+ ANNOTATION_ORIGIN_LOCATION,
+} from '@backstage/catalog-model'
+import {
+ EntityProvider,
+ EntityProviderConnection,
+} from '@backstage/plugin-catalog-backend'
+import { WebClient } from '@slack/web-api'
+import {kebabCase} from 'lodash'
+
+interface Staff {
+ displayName: string
+ slackUserId: string
+ jobTitle: string
+ photoUrl: string
+ address: string
+ email:string
+}
+
+export class UserEntityProvider implements EntityProvider {
+ private readonly getStaffUrl: string
+ protected readonly slackTeam: string
+ protected readonly slackToken: string
+ protected connection?: EntityProviderConnection
+
+ static fromConfig(config: Config, options: { logger: Logger }) {
+ const getStaffUrl = config.getString('staff.url')
+ const slackToken = config.getString('slack.token')
+ const slackTeam = config.getString('slack.team')
+ return new UserEntityProvider({
+ ...options,
+ getStaffUrl,
+ slackToken,
+ slackTeam,
+ })
+ }
+
+ private constructor(options: {
+ getStaffUrl: string
+ slackToken: string
+ slackTeam: string
+ }) {
+ this.getStaffUrl = options.getStaffUrl
+ this.slackToken = options.slackToken
+ this.slackTeam = options.slackTeam
+ }
+
+ async getAllStaff(): Promise{
+ await return axios.get(this.getStaffUrl)
+ }
+
+ public async connect(connection: EntityProviderConnection): Promise {
+ this.connection = connection
+ }
+
+ async run(): Promise {
+ if (!this.connection) {
+ throw new Error('User Connection Not initialized')
+ }
+
+ const userResources: UserEntity[] = []
+ const staff = await this.getAllStaff()
+
+ for (const user of staff) {
+ // we can add any links here in this case it would be adding a slack link to the users so you can directly slack them.
+ const links =
+ user.slackUserId != null && user.slackUserId.length > 0
+ ? [
+ {
+ url: `slack://user?team=${this.slackTeam}&id=${user.slackUserId}`,
+ title: 'Slack',
+ icon: 'message',
+ },
+ ]
+ : undefined
+ const userEntity: UserEntity = {
+ kind: 'User',
+ apiVersion: 'backstage.io/v1alpha1',
+ metadata: {
+ annotations: {
+ [ANNOTATION_LOCATION]: 'hr-user-https://www.hrurl.com/',
+ [ANNOTATION_ORIGIN_LOCATION]: 'hr-user-https://www.hrurl.com/',
+ },
+ links,
+ // name of the entity
+ name: kebabCase(user.displayName),
+ // name for display purposes could be anything including email
+ title: user.displayName,
+ },
+ spec: {
+ profile: {
+ displayName: user.displayName,
+ email: user.email,
+ picture: user.photoUrl,
+ },
+ memberOf: [],
+ },
+ }
+
+ userResources.push(userEntity)
+ }
+
+ await this.connection.applyMutation({
+ type: 'full',
+ entities: userResources.map((entity) => ({
+ entity,
+ locationKey: 'hr-user-https://www.hrurl.com/',
+ })),
+ })
+}
+
+```
+
## Custom Processors
The other possible way of ingesting data into the catalog is through the use of
diff --git a/docs/features/software-templates/input-examples.md b/docs/features/software-templates/input-examples.md
new file mode 100644
index 0000000000..c44ee39269
--- /dev/null
+++ b/docs/features/software-templates/input-examples.md
@@ -0,0 +1,195 @@
+---
+id: input-examples
+title: Input Examples
+description: Some examples to use in your template
+---
+
+All the examples on this page you can test using _create/edit_ from your Backstage installation.
+
+It is important to remember that all examples are based on [react-jsonschema-form](https://rjsf-team.github.io/react-jsonschema-form/).
+
+## Simple text input
+
+### Simple input with basic validations
+
+```yaml
+parameters:
+ - title: Fill in some steps
+ properties:
+ name:
+ title: Simple text input
+ type: string
+ description: Description about input
+ maxLength: 8
+ pattern: '^([a-zA-Z][a-zA-Z0-9]*)(-[a-zA-Z0-9]+)*$'
+ ui:autofocus: true
+ ui:help: 'Hint: additional description...'
+```
+
+### Multi line text input
+
+```yaml
+parameters:
+ - title: Fill in some steps
+ properties:
+ multiline:
+ title: Text area input
+ type: string
+ description: Insert your multi line string
+ ui:widget: textarea
+ ui:options:
+ rows: 10
+ ui:help: 'Hint: Make it strong!'
+ ui:placeholder: |
+ apiVersion: backstage.io/v1alpha1
+ kind: Component
+ metadata:
+ name: backstage
+ spec:
+ type: library
+ owner: CNCF
+ lifecycle: experimental
+```
+
+## Arrays options
+
+### Array with custom titles
+
+```yaml
+parameters:
+ - title: Fill in some steps
+ properties:
+ volume_type:
+ title: Volume Type
+ type: string
+ description: The volume type to be used
+ default: gp2
+ enum:
+ - gp2
+ - gp3
+ - io1
+ - io2
+ - sc1
+ - st1
+ - standard
+ enumNames:
+ - 'General Purpose SSD (gp2)'
+ - 'General Purpose SSD (gp3)'
+ - 'Provisioned IOPS (io1)'
+ - 'Provisioned IOPS (io2)'
+ - 'Cold HDD (sc1)'
+ - 'Throughput Optimized HDD (st1)'
+ - 'Magnetic (standard)'
+```
+
+### A multiple choices list
+
+```yaml
+parameters:
+ - title: Fill in some steps
+ properties:
+ name:
+ title: Select environments
+ type: array
+ items:
+ type: string
+ enum:
+ - production
+ - staging
+ - development
+ uniqueItems: true
+ ui:widget: checkboxes
+```
+
+### Array with another types
+
+```yaml
+parameters:
+ - title: Fill in some steps
+ properties:
+ arrayObjects:
+ title: Array with custom objects
+ type: array
+ ui:options:
+ addable: false
+ orderable: false
+ removable: false
+ items:
+ type: object
+ properties:
+ array:
+ title: Array string with default value
+ type: string
+ default: value3
+ enum:
+ - value1
+ - value2
+ - value3
+ flag:
+ title: Boolean flag
+ type: boolean
+ ui:widget: radio
+ someInput:
+ title: Simple text input
+ type: string
+```
+
+## Boolean options
+
+### Boolean
+
+```yaml
+parameters:
+ - title: Fill in some steps
+ properties:
+ name:
+ title: Checkbox boolean
+ type: boolean
+```
+
+### Boolean Yes or No options
+
+```yaml
+parameters:
+ - title: Fill in some steps
+ properties:
+ name:
+ title: Yes or No options
+ type: boolean
+ ui:widget: radio
+```
+
+### Boolean multiple options
+
+```yaml
+parameters:
+ - title: Fill in some steps
+ properties:
+ name:
+ title: Select features
+ type: array
+ items:
+ type: boolean
+ enum:
+ - 'Enable scraping'
+ - 'Enable HPA'
+ - 'Enable cache'
+ uniqueItems: true
+ ui:widget: checkboxes
+```
+
+## Use parameters as condition in steps
+
+```yaml
+- name: Only development environments
+ if: ${{ parameters.environment === "staging" and parameters.environment === "development" }}
+ action: debug:log
+ input:
+ message: 'development step'
+
+- name: Only production environments
+ if: ${{ parameters.environment === "prod" or parameters.environment === "production" }}
+ action: debug:log
+ input:
+ message: 'production step'
+```
diff --git a/docs/getting-started/running-backstage-locally.md b/docs/getting-started/running-backstage-locally.md
index 7cc6f6be6a..3e3e8b0727 100644
--- a/docs/getting-started/running-backstage-locally.md
+++ b/docs/getting-started/running-backstage-locally.md
@@ -21,12 +21,12 @@ This is made easy with a version manager such as
# Installing current LTS release
nvm install --lts
> Installing latest LTS version.
-> Downloading and installing node v14.15.1...
-> Now using node v14.15.1 (npm v6.14.8)
+> Downloading and installing node v16.16.0...
+> Now using node v16.16.0 (npm v8.11.0)
# Checking your version
node --version
-> v14.15.1
+> v16.16.0
```
- Yarn
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 5482733a58..9e3c450adc 100644
--- a/docs/integrations/github/org.md
+++ b/docs/integrations/github/org.md
@@ -38,7 +38,7 @@ schedule it:
```diff
// packages/backend/src/plugins/catalog.ts
-+import { GitHubOrgEntityProvider } from '@backstage/plugin-catalog-backend-module-github';
++import { GithubOrgEntityProvider } from '@backstage/plugin-catalog-backend-module-github';
export default async function createPlugin(
env: PluginEnvironment,
@@ -48,7 +48,7 @@ schedule it:
+ // The org URL below needs to match a configured integrations.github entry
+ // specified in your app-config.
+ builder.addEntityProvider(
-+ GitHubOrgEntityProvider.fromConfig(env.config, {
++ GithubOrgEntityProvider.fromConfig(env.config, {
+ id: 'production',
+ orgUrl: 'https://github.com/backstage',
+ logger: env.logger,
@@ -97,6 +97,66 @@ that must be approved first before the changes are applied.**

+### 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/overview/architecture-overview.md b/docs/overview/architecture-overview.md
index 3c9417268b..45f3190a5d 100644
--- a/docs/overview/architecture-overview.md
+++ b/docs/overview/architecture-overview.md
@@ -249,7 +249,7 @@ however likely to change in the future.
The common packages are the packages effectively depended on by all other pages.
This is a much smaller set of packages but they are also very pervasive. Because
the common packages are isomorphic and must execute both in the frontend and
-backend, they are never allowed to depend on any of the frontend of backend
+backend, they are never allowed to depend on any of the frontend or backend
packages.
The Backstage CLI is in a category of its own and is depended on by virtually
diff --git a/docs/overview/versioning-policy.md b/docs/overview/versioning-policy.md
index 885a599ed8..a989f104b5 100644
--- a/docs/overview/versioning-policy.md
+++ b/docs/overview/versioning-policy.md
@@ -144,9 +144,10 @@ following schedule for determining the [Node.js releases](https://nodejs.org/en/
- At any given point in time we support exactly two adjacent even-numbered
releases of Node.js, for example v12 and v14.
-- Three months before a Node.js release becomes _Active LTS_ we switch support
- to that release and the previous one. This is halfway through the _Current LTS_
- cycle for that release and occurs at the end of July every year.
+- Once a new Node.js release becomes _Active LTS_ we switch to support that
+ release and the previous one. The switch is not immediate but done as soon
+ as possible. You can find the Node.js version supported by each release
+ in the `engines` field in the root `package.json` of a new app.
When we say _Supporting_ a Node.js release, that means the following:
diff --git a/docs/releases/v1.8.0-next.1-changelog.md b/docs/releases/v1.8.0-next.1-changelog.md
new file mode 100644
index 0000000000..1f65dfdc9c
--- /dev/null
+++ b/docs/releases/v1.8.0-next.1-changelog.md
@@ -0,0 +1,106 @@
+# Release v1.8.0-next.1
+
+## @backstage/plugin-scaffolder-backend@1.8.0-next.1
+
+### Minor Changes
+
+- 5921b5ce49: - The GitLab Project ID for the `publish:gitlab:merge-request` action is now passed through the query parameter `project` in the `repoUrl`. It still allows people to not use the `projectid` and use the `repoUrl` with the `owner` and `repo` query parameters instead. This makes it easier to publish to repositories instead of writing the full path to the project.
+
+## @backstage/create-app@0.4.33-next.1
+
+### Patch Changes
+
+- Bumped create-app version.
+
+## @backstage/plugin-azure-devops-backend@0.3.17-next.1
+
+### Patch Changes
+
+- 62f284e394: - Adjusted the asset parser to accept case sensitive
+ - Fixed fetching data that was using the deprecated function
+
+## @backstage/plugin-playlist@0.1.2-next.1
+
+### Patch Changes
+
+- 605f269f0d: Updated Playlist plugin docs:
+
+ - Updated `playlist` plugin README to include note about installing backend plugin and added images for the various features
+ - Updated `playlist-backend` plugin README to remove `IdentityClient` import in example as it is not used and made minor change to headings
+
+## @backstage/plugin-playlist-backend@0.2.1-next.1
+
+### Patch Changes
+
+- 605f269f0d: Updated Playlist plugin docs:
+
+ - Updated `playlist` plugin README to include note about installing backend plugin and added images for the various features
+ - Updated `playlist-backend` plugin README to remove `IdentityClient` import in example as it is not used and made minor change to headings
+
+## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.2.13-next.1
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/plugin-scaffolder-backend@1.8.0-next.1
+
+## @backstage/plugin-scaffolder-backend-module-rails@0.4.6-next.1
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/plugin-scaffolder-backend@1.8.0-next.1
+
+## @backstage/plugin-scaffolder-backend-module-yeoman@0.2.11-next.1
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/plugin-scaffolder-backend@1.8.0-next.1
+
+## @backstage/plugin-techdocs@1.4.0-next.1
+
+### Patch Changes
+
+- 9e4d8e6198: Fix logic bug that broke techdocs-cli-embedded-app
+
+## @backstage/plugin-techdocs-addons-test-utils@1.0.6-next.1
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/plugin-techdocs@1.4.0-next.1
+
+## example-app@0.2.77-next.1
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/plugin-techdocs@1.4.0-next.1
+ - @backstage/plugin-playlist@0.1.2-next.1
+ - @backstage/plugin-techdocs-module-addons-contrib@1.0.6-next.0
+
+## example-backend@0.2.77-next.1
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/plugin-scaffolder-backend@1.8.0-next.1
+ - @backstage/plugin-playlist-backend@0.2.1-next.1
+ - @backstage/plugin-azure-devops-backend@0.3.17-next.1
+ - example-app@0.2.77-next.1
+ - @backstage/plugin-scaffolder-backend-module-rails@0.4.6-next.1
+
+## example-backend-next@0.0.5-next.1
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/plugin-scaffolder-backend@1.8.0-next.1
+
+## techdocs-cli-embedded-app@0.2.76-next.1
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/plugin-techdocs@1.4.0-next.1
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/docs/tutorials/quickstart-app-plugin.md b/docs/tutorials/quickstart-app-plugin.md
index d1ca61a11f..ea0a511c93 100644
--- a/docs/tutorials/quickstart-app-plugin.md
+++ b/docs/tutorials/quickstart-app-plugin.md
@@ -20,7 +20,7 @@ title: Adding Custom Plugin to Existing Monorepo App
> functionality, extend the Sidebar to make our life easy. Finally, we add
> custom code to display GitHub repository information.
>
-> This document assumes you have Node.js 14 active along with Yarn and Python.
+> This document assumes you have Node.js 16 active along with Yarn and Python.
> Please note, that at the time of this writing, the current version is
> 0.1.1-alpha.21. This guide can still be used with future versions, just,
> verify as you go. If you run into issues, you can compare your setup with mine
diff --git a/microsite/blog/2022-10-28-backstagecon-kubecon-2022.md b/microsite/blog/2022-10-28-backstagecon-kubecon-2022.md
new file mode 100644
index 0000000000..ffc44ed432
--- /dev/null
+++ b/microsite/blog/2022-10-28-backstagecon-kubecon-2022.md
@@ -0,0 +1,36 @@
+---
+title: 'ICYMI: BackstageCon & KubeCon NA 2022 Recap'
+description: 'We had a great time in Detroit! Learn more about our first dedicated conference to Backstage and KubeCon NA 2022.'
+author: Emma White, Spotify
+authorURL: https://www.linkedin.com/in/emmamckeewhite/
+---
+
+## ICYMI: BackstageCon & KubeCon NA 2022 Recap
+
+
+
+What an action-packed and memorable week for the Backstage community meeting up IRL at KubeCon North America 2022 in (unseasonably warm and sunny) Detroit. Letโs see what the community was up to:
+
+### BackstageCon: A full day of nothing but Backstage
+
+
+
+We started the week off strong, packing a ballroom for [BackstageCon](https://events.linuxfoundation.org/backstagecon-north-america/) on Monday. It was a smorgasbord of some of our active community members at the first official Backstage conference โ as well as some new faces interested in learning more about Backstage! To welcome us, Roadieโs [Martina Iglesias Fernandez](https://github.com/martina-if) and Spotifyโs [Suzanne Daniels](https://github.com/suuus) took center stage. Next up, we listened to three keynotes from the eventโs top sponsors: Roadieโs [David Tuite](https://github.com/dtuite) enlightened us on how to 10x developer effectiveness for teams, [Dave Zolotusky](https://github.com/dzolotusky) from Spotify discussed developer happiness and [announced](https://www.linkedin.com/posts/spotify-r%26d_backstage-devex-activity-6990305201710587904-SnDQ?utm_source=share&utm_medium=member_desktop) that [Spotify Plugins for Backstage](https://backstage.spotify.com/blog/spotify-plugins-for-backstage/) are launching soon, and [Valentina Alaria](https://www.linkedin.com/in/valentinaalaria/) from VMware Tanzu talked about how to curate the Backstage experience to enable developer velocity. In between some creative snacks (lemon blueberry popcorn, anyone?) and coffee breaks, we heard from adopters including [Telus](https://backstage.spotify.com/blog/building-for-simplicity-TELUS/), [DAZN](https://backstage.spotify.com/blog/adopter-spotlight/dazn/), HP, US Bank, and more on lessons learned through their adoption journeys, we talked about different ways to leverage data within Backstage, and we discussed new ways to customize Backstage for specific adopter needs.
+
+You can watch all the BackstageCon sessions, talks, and keynotes [here](https://www.youtube.com/playlist?list=PLj6h78yzYM2OKySsTuiip3BqmdYZQRnSf)!
+
+### Project Meeting: Building a better Backstage together
+
+
+
+The following day, the Backstage maintainers hosted a lively project meeting, where we engaged with a lot of folks that had been at BackstageCon the day before. Over the course of the meeting, the Backstage community talked through recommended approaches for maintaining your Software Catalog as a source of truth, sourcing internal contributors for organizationโs Backstage apps, improving frontend performance in a few plugins, how Backstage maintainers work, and appreciation for the contributions from our community. You can read more detailed notes from the project meeting in the repo [here](https://github.com/backstage/community/blob/main/project-meetings/kubecon-na-2022.md).
+
+### KubeCon: Demos, swag, and standing-room only
+
+And last but not least: three days of [KubeCon North America](https://events.linuxfoundation.org/kubecon-cloudnativecon-north-america/)! At KubeCon, the Backstage team met and greeted so many new faces at our kiosk in the Project Pavilion. We ran demos, answered questions, and handed out lots and lots of SWAG!
+
+
+
+Spotifyโs [Francesco Corti](https://github.com/fcorti) and core maintainer [Ben Lambert](https://github.com/benjdlambert) took the stage on Wednesday to present the Backstage maintainer talk to a PACKED audience. They discussed how core features of Backstage are changing the way end-user developers interact and manage their ecosystem, and encouraged folks to create the future of developer experience with the rest of the Backstage community. If you missed it, no worries! Their talk track will be posted on the [CNCF YouTube channel](https://www.youtube.com/c/cloudnativefdn).
+
+โฆand thatโs a wrap! What an incredible week. Our growing Backstage community continues to amaze us with its dedication and enthusiasm. We canโt wait to see you all again at KubeCon Europe in The Netherlands! In fact, weโd love to see our adopters give Backstage talks next year (hint, hint). The KubeCon Europe [CFP is open](https://events.linuxfoundation.org/kubecon-cloudnativecon-europe/program/cfp/#overview) until Friday, November 18, 2022.
diff --git a/microsite/blog/assets/2022-10-28/groupimage.jpg b/microsite/blog/assets/2022-10-28/groupimage.jpg
new file mode 100644
index 0000000000..ef12667e0a
Binary files /dev/null and b/microsite/blog/assets/2022-10-28/groupimage.jpg differ
diff --git a/microsite/blog/assets/2022-10-28/preview.png b/microsite/blog/assets/2022-10-28/preview.png
new file mode 100644
index 0000000000..67774e7744
Binary files /dev/null and b/microsite/blog/assets/2022-10-28/preview.png differ
diff --git a/microsite/blog/assets/2022-10-28/project_meeting.jpg b/microsite/blog/assets/2022-10-28/project_meeting.jpg
new file mode 100644
index 0000000000..8e3bc91ddf
Binary files /dev/null and b/microsite/blog/assets/2022-10-28/project_meeting.jpg differ
diff --git a/microsite/blog/assets/2022-10-28/real_project_meeting.jpeg b/microsite/blog/assets/2022-10-28/real_project_meeting.jpeg
new file mode 100644
index 0000000000..f1e0ff40bf
Binary files /dev/null and b/microsite/blog/assets/2022-10-28/real_project_meeting.jpeg differ
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 2e7801d581..a5fd5353e0 100644
--- a/microsite/pages/en/community.js
+++ b/microsite/pages/en/community.js
@@ -103,64 +103,79 @@ const Background = props => {
Stay tuned to the latest developments
+
-
-
- Community sessions
-
- Maintainers and adopters meet monthly to share updates, demos,
- and ideas. Yep, all sessions are recorded!
-
+
+
+
+ Community sessions
+
+ Maintainers and adopters meet monthly to share updates, demos,
+ and ideas. Yep, all sessions are recorded!
+
+
Join a session
-
-
- Newsletter
-
- The official monthly Backstage newsletter. Don't miss the latest
- news from your favorite project!
-
+
+
+
+
+ Newsletter
+
+ The official monthly Backstage newsletter. Don't miss the
+ latest news from your favorite project!
+
+
Subscribe
-
-
- Contributor Spotlight
-
- A recognition for valuable community work. Nominate contributing
- members for their efforts! We'll put them in the spotlight โค๏ธ
-
+
+
+
+
+ Contributor Spotlight
+
+ A recognition for valuable community work. Nominate
+ contributing members for their efforts! We'll put them in the
+ spotlight โค๏ธ
+
+
Nominate now
-
+
+
Community initiatives
-
- Open Mic Meetup
-
- A casual get together of Backstage users sharing their experiences
- and helping each other. Hosted by{' '}
- Roadie.io and{' '}
- Frontside Software .
-
+
+
+ Open Mic Meetup
+
+ A casual get together of Backstage users sharing their
+ experiences and helping each other. Hosted by{' '}
+ Roadie.io and{' '}
+ Frontside Software .
+
+
Learn more
-
- Backstage Weekly Newsletter
-
- A weekly newsletter with news, updates and things community from
- your friends at Roadie.io .
-
+
+
+ Backstage Weekly Newsletter
+
+ A weekly newsletter with news, updates and things community from
+ your friends at Roadie.io .
+
+
Learn more
@@ -168,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 e758fe9100..725290cb69 100644
--- a/microsite/sidebars.json
+++ b/microsite/sidebars.json
@@ -95,6 +95,7 @@
"features/software-templates/configuration",
"features/software-templates/adding-templates",
"features/software-templates/writing-templates",
+ "features/software-templates/input-examples",
"features/software-templates/builtin-actions",
"features/software-templates/writing-custom-actions",
"features/software-templates/writing-custom-field-extensions",
@@ -315,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 43efc32f8e..f3194f0d61 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -62,6 +62,7 @@ nav:
- Configuration: 'features/software-templates/configuration.md'
- Adding your own Templates: 'features/software-templates/adding-templates.md'
- Writing Templates: 'features/software-templates/writing-templates.md'
+ - Input Examples: 'features/software-templates/input-examples.md'
- Builtin Actions: 'features/software-templates/builtin-actions.md'
- Writing Custom Actions: 'features/software-templates/writing-custom-actions.md'
- Writing Custom Step Layouts: 'features/software-templates/writing-custom-step-layouts.md'
@@ -177,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 168f24787d..3977bcc18f 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
"name": "root",
"private": true,
"engines": {
- "node": "14 || 16"
+ "node": "16 || 18"
},
"scripts": {
"dev": "concurrently \"yarn start\" \"yarn start-backend\"",
@@ -44,7 +44,7 @@
"@types/react": "^17",
"@types/react-dom": "^17"
},
- "version": "1.8.0-next.0",
+ "version": "1.8.0-next.2",
"dependencies": {
"@backstage/errors": "workspace:^",
"@manypkg/get-packages": "^1.1.3",
@@ -73,6 +73,7 @@
"husky": "^8.0.0",
"lint-staged": "^13.0.0",
"minimist": "^1.2.5",
+ "node-gyp": "^9.1.0",
"prettier": "^2.2.1",
"semver": "^7.3.2",
"shx": "^0.3.2",
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 d909773ff4..5780e61681 100644
--- a/packages/app/CHANGELOG.md
+++ b/packages/app/CHANGELOG.md
@@ -1,5 +1,77 @@
# 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
+
+- Updated dependencies
+ - @backstage/plugin-techdocs@1.4.0-next.1
+ - @backstage/plugin-playlist@0.1.2-next.1
+ - @backstage/plugin-techdocs-module-addons-contrib@1.0.6-next.0
+
## 0.2.77-next.0
### Patch Changes
diff --git a/packages/app/package.json b/packages/app/package.json
index 9388f305f6..b7f7f40b89 100644
--- a/packages/app/package.json
+++ b/packages/app/package.json
@@ -1,6 +1,6 @@
{
"name": "example-app",
- "version": "0.2.77-next.0",
+ "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')) { %>
-
- <% } %>
You need to enable JavaScript to run this app.
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/e2e-test/src/commands/run.ts b/packages/e2e-test/src/commands/run.ts
index 3f9d28eadd..f32d577cd4 100644
--- a/packages/e2e-test/src/commands/run.ts
+++ b/packages/e2e-test/src/commands/run.ts
@@ -507,6 +507,7 @@ async function testBackendStart(appDir: string, ...args: string[]) {
// Skipping the whole block
throw new Error(stderr);
}
+ await new Promise(resolve => setTimeout(resolve, 500));
print('Try to fetch entities from the backend');
// Try fetch entities, should be ok
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 fc7dbe743b..e6d842d121 100644
--- a/packages/techdocs-cli-embedded-app/CHANGELOG.md
+++ b/packages/techdocs-cli-embedded-app/CHANGELOG.md
@@ -1,5 +1,31 @@
# 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
+
+- Updated dependencies
+ - @backstage/plugin-techdocs@1.4.0-next.1
+
## 0.2.76-next.0
### Patch Changes
diff --git a/packages/techdocs-cli-embedded-app/package.json b/packages/techdocs-cli-embedded-app/package.json
index c34c52e3f2..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.0",
+ "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() : '-'}
+
+
+
+ }
+ aria-label="Link To Detail"
+ color="primary"
+ variant="outlined"
+ >
+
+ Graph
+
+
+
+
+ );
+};
+
+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/README.md b/plugins/auth-backend/README.md
index d13a5e5a20..ba0042c6f9 100644
--- a/plugins/auth-backend/README.md
+++ b/plugins/auth-backend/README.md
@@ -34,8 +34,8 @@ Follow this link, [Create new OAuth App](https://github.com/settings/application
1. Set Application Name to `backstage-dev` or something along those lines.
1. You can set the Homepage URL to whatever you want to.
1. The Authorization Callback URL should match the redirect URI set in Backstage.
- 1. Set this to `http://localhost:7007/api/auth/github` for local development.
- 1. Set this to `http://{APP_FQDN}:{APP_BACKEND_PORT}/api/auth/github` for non-local deployments.
+ 1. Set this to `http://localhost:7007/api/auth/github/handler/frame` for local development.
+ 1. Set this to `http://{APP_FQDN}:{APP_BACKEND_PORT}/api/auth/github/handler/frame` for non-local deployments.
```bash
export AUTH_GITHUB_CLIENT_ID=x
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 4b3d7910e5..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",
@@ -60,7 +60,7 @@
"morgan": "^1.10.0",
"node-cache": "^5.1.2",
"node-fetch": "^2.6.7",
- "openid-client": "^5.1.3",
+ "openid-client": "^5.2.1",
"passport": "^0.6.0",
"passport-auth0": "^1.4.3",
"passport-bitbucket-oauth2": "^0.1.2",
@@ -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 8fd758f1b4..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) {
@@ -114,7 +115,7 @@ export async function createRouter(
allProviderFactories,
)) {
if (configuredProviders.includes(providerId)) {
- logger.info(`Configuring provider, ${providerId}`);
+ logger.info(`Configuring auth provider: ${providerId}`);
try {
const provider = providerFactory({
providerId,
@@ -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 dfaffa8e35..e6a148f278 100644
--- a/plugins/azure-devops-backend/CHANGELOG.md
+++ b/plugins/azure-devops-backend/CHANGELOG.md
@@ -1,5 +1,21 @@
# @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
+
+- 62f284e394: - Adjusted the asset parser to accept case sensitive
+ - Fixed fetching data that was using the deprecated function
+
## 0.3.17-next.0
### Patch Changes
diff --git a/plugins/azure-devops-backend/package.json b/plugins/azure-devops-backend/package.json
index 940b24ed44..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.0",
+ "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-backend/src/api/AzureDevOpsApi.ts b/plugins/azure-devops-backend/src/api/AzureDevOpsApi.ts
index 2bf2988a98..24c13020b6 100644
--- a/plugins/azure-devops-backend/src/api/AzureDevOpsApi.ts
+++ b/plugins/azure-devops-backend/src/api/AzureDevOpsApi.ts
@@ -408,14 +408,15 @@ export class AzureDevOpsApi {
content: string;
}> {
const url = buildEncodedUrl(host, org, project, repo, 'README.md');
- const response = await this.urlReader.read(url);
+ const response = await this.urlReader.readUrl(url);
+ const buffer = await response.buffer();
const content = await replaceReadme(
this.urlReader,
host,
org,
project,
repo,
- response.toString(),
+ buffer.toString(),
);
return { url, content };
}
diff --git a/plugins/azure-devops-backend/src/utils/azure-devops-utils.test.ts b/plugins/azure-devops-backend/src/utils/azure-devops-utils.test.ts
index f044a20968..74932c9653 100644
--- a/plugins/azure-devops-backend/src/utils/azure-devops-utils.test.ts
+++ b/plugins/azure-devops-backend/src/utils/azure-devops-utils.test.ts
@@ -167,30 +167,30 @@ describe('extractAssets', () => {
it('should return assets', () => {
const readme = `
## Images
- .png)
+ .PNG)

))).jpeg)

- mple.gif)
+ mple.GIf)
`;
const result = extractAssets(readme);
expect(result).toEqual([
- '[Image 1](./images/sample-4(2).png)',
+ '[Image 1](./images/sample-4(2).PNG)',
'[Image 2](./images/cdCSj+-012340.jpg)',
'[Image 3](/images/test-4(2)))).jpeg)',
'[Image 4](./images/test-2211jd.webp)',
- '[Image 5](/images/sa)mple.gif)',
+ '[Image 5](/images/sa)mple.GIf)',
]);
});
});
describe('extractPartsFromAsset', () => {
it('should return parts from asset - PNG', () => {
- const result = extractPartsFromAsset('[Image 1](./images/sample-4(2).png)');
+ const result = extractPartsFromAsset('[Image 1](./images/sample-4(2).PNG)');
expect(result).toEqual({
label: 'Image 1',
path: '/images/sample-4(2)',
- ext: '.png',
+ ext: '.PNG',
});
});
@@ -207,12 +207,12 @@ describe('extractPartsFromAsset', () => {
it('should return parts from asset - JPEG', () => {
const result = extractPartsFromAsset(
- '[Image 2](/images/test-4(2)))).jpeg)',
+ '[Image 2](/images/test-4(2)))).JpEg)',
);
expect(result).toEqual({
label: 'Image 2',
path: '/images/test-4(2))))',
- ext: '.jpeg',
+ ext: '.JpEg',
});
});
@@ -247,10 +247,15 @@ describe('replaceReadme', () => {
`;
const reader: UrlReader = {
- read: url => new Promise(resolve => resolve(Buffer.from(url))),
+ readUrl: url =>
+ Promise.resolve({
+ buffer: async () => Buffer.from(url),
+ etag: 'buffer',
+ stream: jest.fn(),
+ }),
readTree: jest.fn(),
search: jest.fn(),
- readUrl: jest.fn(),
+ read: jest.fn(),
};
const result = await replaceReadme(
diff --git a/plugins/azure-devops-backend/src/utils/azure-devops-utils.ts b/plugins/azure-devops-backend/src/utils/azure-devops-utils.ts
index 191486a925..0aafb54a0a 100644
--- a/plugins/azure-devops-backend/src/utils/azure-devops-utils.ts
+++ b/plugins/azure-devops-backend/src/utils/azure-devops-utils.ts
@@ -223,8 +223,9 @@ export async function replaceReadme(
const { label, path, ext } = extractPartsFromAsset(filePath);
const data = mime.lookup(ext);
const url = buildEncodedUrl(host, org, project, repo, path + ext);
- const buffer = await urlReader.read(url);
- const file = await buffer.toString('base64');
+ const response = await urlReader.readUrl(url);
+ const buffer = await response.buffer();
+ const file = buffer.toString('base64');
return content.replace(
filePath,
`[${label}](data:${data};base64,${file})`,
@@ -320,7 +321,7 @@ export function extractPartsFromAsset(content: string): {
ext: string;
} {
const regExp =
- /\[(.*?)\]\((?!https?:\/\/)(.*?)(\.png|\.jpg|\.jpeg|\.gif|\.webp)(.*)\)/;
+ /\[(.*?)\]\((?!https?:\/\/)(.*?)(\.png|\.jpg|\.jpeg|\.gif|\.webp)(.*)\)/i;
const [_, label, path, ext] = regExp.exec(content) || [];
return {
ext,
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 25878c2005..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,22 +15,32 @@
*/
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';
+
+// Workaround for Node.js 18, where native fetch is available, but not yet picked up by msw
+// TODO(Rugvip): remove once https://github.com/mswjs/msw/issues/1388 is resolved
+(global as any).fetch = fetch;
describe('github', () => {
const server = setupServer();
setupRequestMockHandlers(server);
- describe('getOrganizationUsers', () => {
+ describe('getOrganizationUsers using defaultUserMapper', () => {
it('reads members', async () => {
const input: QueryResponse = {
organization: {
@@ -71,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(() => {
@@ -90,7 +213,7 @@ describe('github', () => {
parentTeam: {
slug: 'parent',
combinedSlug: '',
- members: { pageInfo: { hasNextPage: false }, nodes: [] },
+ members: [],
},
members: {
pageInfo: { hasNextPage: false },
@@ -124,10 +247,10 @@ describe('github', () => {
},
parent: 'parent',
children: [],
+ members: ['user'],
},
}),
],
- groupMemberUsers: new Map([['team', ['user']]]),
};
server.use(
@@ -136,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);
});
});
@@ -186,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-msgraph/src/microsoftGraph/read.ts b/plugins/catalog-backend-module-msgraph/src/microsoftGraph/read.ts
index 8e1d9a3776..0ed411bfea 100644
--- a/plugins/catalog-backend-module-msgraph/src/microsoftGraph/read.ts
+++ b/plugins/catalog-backend-module-msgraph/src/microsoftGraph/read.ts
@@ -122,7 +122,7 @@ export async function readMicrosoftGraphUsers(
120,
);
} catch (e) {
- options.logger.warn(`Unable to load photo for ${user.id}`);
+ options.logger.warn(`Unable to load photo for ${user.id}, ${e}`);
}
const entity = await transformer(user, userPhoto);
@@ -206,7 +206,7 @@ export async function readMicrosoftGraphUsersInGroups(
expand: options.userExpand,
});
} catch (e) {
- options.logger.warn(`Unable to load user for ${userId}`);
+ options.logger.warn(`Unable to load user for ${userId}, ${e}`);
}
if (user) {
try {
@@ -217,7 +217,7 @@ export async function readMicrosoftGraphUsersInGroups(
120,
);
} catch (e) {
- options.logger.warn(`Unable to load userphoto for ${userId}`);
+ options.logger.warn(`Unable to load userphoto for ${userId}, ${e}`);
}
const entity = await transformer(user, userPhoto);
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/config.d.ts b/plugins/catalog-backend/config.d.ts
index 950ed2f63c..daa70656bc 100644
--- a/plugins/catalog-backend/config.d.ts
+++ b/plugins/catalog-backend/config.d.ts
@@ -25,7 +25,7 @@ export interface Config {
* An undefined list of matchers means match all, an empty list of
* matchers means match none.
*
- * This is commonly used to put in what amounts to a whitelist of kinds
+ * This is commonly used to put in what amounts to an allowlist of kinds
* that regular users of Backstage are permitted to register locations
* for. This can be used to stop them from registering yaml files
* describing for example a Group entity called "admin" that they make
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.test.tsx b/plugins/catalog-graph/src/components/CatalogGraphCard/CatalogGraphCard.test.tsx
index 74fcd4e501..7cd6d29bbc 100644
--- a/plugins/catalog-graph/src/components/CatalogGraphCard/CatalogGraphCard.test.tsx
+++ b/plugins/catalog-graph/src/components/CatalogGraphCard/CatalogGraphCard.test.tsx
@@ -116,7 +116,31 @@ describe(' ', () => {
expect(button).toBeInTheDocument();
expect(button.closest('a')).toHaveAttribute(
'href',
- '/catalog-graph?rootEntityRefs%5B%5D=b%3Ad%2Fc',
+ '/catalog-graph?rootEntityRefs%5B%5D=b%3Ad%2Fc&maxDepth=2&unidirectional=true&mergeRelations=true&direction=LR',
+ );
+ });
+
+ test('renders link to standalone viewer with custom config', async () => {
+ const { findByText, getByText } = await renderInTestApp(
+
+
+
+
+ ,
+ {
+ mountedRoutes: {
+ '/entity/{kind}/{namespace}/{name}': entityRouteRef,
+ '/catalog-graph': catalogGraphRouteRef,
+ },
+ },
+ );
+
+ expect(await findByText('b:d/c')).toBeInTheDocument();
+ const button = getByText('View graph');
+ expect(button).toBeInTheDocument();
+ expect(button.closest('a')).toHaveAttribute(
+ 'href',
+ '/catalog-graph?rootEntityRefs%5B%5D=b%3Ad%2Fc&maxDepth=3&unidirectional=true&mergeRelations=false&direction=LR',
);
});
diff --git a/plugins/catalog-graph/src/components/CatalogGraphCard/CatalogGraphCard.tsx b/plugins/catalog-graph/src/components/CatalogGraphCard/CatalogGraphCard.tsx
index ae1ca9c22d..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;
@@ -106,7 +109,15 @@ export const CatalogGraphCard = (props: {
);
const catalogGraphParams = qs.stringify(
- { rootEntityRefs: [stringifyEntityRef(entity)] },
+ {
+ rootEntityRefs: [stringifyEntityRef(entity)],
+ maxDepth: maxDepth + 1,
+ unidirectional,
+ mergeRelations,
+ kinds,
+ relations,
+ direction,
+ },
{ arrayFormat: 'brackets', addQueryPrefix: true },
);
const catalogGraphUrl = `${catalogGraphRoute()}${catalogGraphParams}`;
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 bb90595340..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",
@@ -665,7 +659,7 @@
"type": "object",
"properties": {
"rules": {
- "description": "Rules to apply to all catalog entities, from any location.\n\nAn undefined list of matchers means match all, an empty list of\nmatchers means match none.\n\nThis is commonly used to put in what amounts to a whitelist of kinds\nthat regular users of Backstage are permitted to register locations\nfor. This can be used to stop them from registering yaml files\ndescribing for example a Group entity called \"admin\" that they make\nthemselves members of, or similar.",
+ "description": "Rules to apply to all catalog entities, from any location.\n\nAn undefined list of matchers means match all, an empty list of\nmatchers means match none.\n\nThis is commonly used to put in what amounts to an allowlist of kinds\nthat regular users of Backstage are permitted to register locations\nfor. This can be used to stop them from registering yaml files\ndescribing for example a Group entity called \"admin\" that they make\nthemselves members of, or similar.",
"type": "array",
"items": {
"type": "object",
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 b5859fa886..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",
@@ -71,9 +72,9 @@
"@types/recharts": "^1.8.14",
"@types/regression": "^2.0.0",
"@types/yup": "^0.29.13",
- "canvas": "^2.6.1",
+ "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/README.md b/plugins/explore/README.md
index 8e1cbaed02..94ab0984a0 100644
--- a/plugins/explore/README.md
+++ b/plugins/explore/README.md
@@ -79,3 +79,39 @@ const routes = (
);
```
+
+## ToolExplorer Content Customization
+
+Override the `exploreToolsConfigRef` API in `/packages/app/src/apis.ts`.
+
+```tsx
+import { exploreToolsConfigRef } from '@backstage/plugin-explore-react';
+
+export const apis: AnyApiFactory[] = [
+ ...
+
+ createApiFactory({
+ api: exploreToolsConfigRef,
+ deps: {},
+ factory: () => ({
+ async getTools() {
+ return tools;
+ },
+ /* e.g. tools = [
+ {
+ title: 'New Relic',
+ description:'new relic plugin,
+ url: '/newrelic',
+ image: 'https://i.imgur.com/L37ikrX.jpg',
+ tags: ['newrelic', 'proxy', 'nerdGraph'],
+ },
+ ]
+ */
+ }),
+ }),
+
+ ....
+
+];
+
+```
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/README.md b/plugins/github-actions/README.md
index 792d13280f..cb6867193c 100644
--- a/plugins/github-actions/README.md
+++ b/plugins/github-actions/README.md
@@ -11,7 +11,7 @@ TBD
### Generic Requirements
1. Provide OAuth credentials:
- 1. [Create an OAuth App](https://developer.github.com/apps/building-oauth-apps/creating-an-oauth-app/) in the GitHub organization with the callback URL set to `http://localhost:7007/api/auth/github`.
+ 1. [Create an OAuth App](https://developer.github.com/apps/building-oauth-apps/creating-an-oauth-app/) in the GitHub organization with the callback URL set to `http://localhost:7007/api/auth/github/handler/frame`.
2. Take the Client ID and Client Secret from the newly created app's settings page and put them into `AUTH_GITHUB_CLIENT_ID` and `AUTH_GITHUB_CLIENT_SECRET` environment variables.
2. Annotate your component with a correct GitHub Actions repository and owner:
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-actions/src/components/Cards/RecentWorkflowRunsCard.tsx b/plugins/github-actions/src/components/Cards/RecentWorkflowRunsCard.tsx
index 89fd40da33..59d64af9c9 100644
--- a/plugins/github-actions/src/components/Cards/RecentWorkflowRunsCard.tsx
+++ b/plugins/github-actions/src/components/Cards/RecentWorkflowRunsCard.tsx
@@ -29,6 +29,7 @@ import {
useRouteRef,
} from '@backstage/core-plugin-api';
import {
+ ErrorPanel,
InfoCard,
InfoCardVariants,
Link,
@@ -76,6 +77,11 @@ export const RecentWorkflowRunsCard = (props: {
const githubHost = hostname || 'github.com';
const routeLink = useRouteRef(buildRouteRef);
+
+ if (error) {
+ return ;
+ }
+
return (
();
+
+
+
++
+
+
+```
+
+The `GroupListPicker` comes with three props:
+
+- `groupTypes`: gives the user the option which group types the component should load. If no value is provided all group types will be loaded in;
+- `placeholder`: the placeholder that the select box in the component should display. This might be helpful in informing your users what the functionality of the component is.
+- `onChange`: a prop to help the user to give access to the selected group
diff --git a/plugins/org-react/api-report.md b/plugins/org-react/api-report.md
new file mode 100644
index 0000000000..60cd6944d0
--- /dev/null
+++ b/plugins/org-react/api-report.md
@@ -0,0 +1,21 @@
+## API Report File for "@backstage/plugin-org-react"
+
+> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
+
+```ts
+///
+
+import { GroupEntity } from '@backstage/catalog-model';
+
+// @public (undocumented)
+export const GroupListPicker: (props: GroupListPickerProps) => JSX.Element;
+
+// @public
+export type GroupListPickerProps = {
+ placeholder?: string;
+ groupTypes?: Array;
+ onChange: (value: GroupEntity | undefined) => void;
+};
+
+// (No @packageDocumentation comment for this package)
+```
diff --git a/plugins/org-react/package.json b/plugins/org-react/package.json
new file mode 100644
index 0000000000..bc2b7f426d
--- /dev/null
+++ b/plugins/org-react/package.json
@@ -0,0 +1,62 @@
+{
+ "name": "@backstage/plugin-org-react",
+ "version": "0.1.0-next.0",
+ "main": "src/index.ts",
+ "types": "src/index.ts",
+ "license": "Apache-2.0",
+ "publishConfig": {
+ "access": "public",
+ "main": "dist/index.esm.js",
+ "types": "dist/index.d.ts"
+ },
+ "backstage": {
+ "role": "web-library"
+ },
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/backstage/backstage",
+ "directory": "plugins/org-react"
+ },
+ "keywords": [
+ "backstage"
+ ],
+ "scripts": {
+ "start": "backstage-cli package start",
+ "build": "backstage-cli package build",
+ "lint": "backstage-cli package lint",
+ "test": "backstage-cli package test",
+ "clean": "backstage-cli package clean",
+ "prepack": "backstage-cli package prepack",
+ "postpack": "backstage-cli package postpack"
+ },
+ "dependencies": {
+ "@backstage/catalog-client": "workspace:^",
+ "@backstage/catalog-model": "workspace:^",
+ "@backstage/core-components": "workspace:^",
+ "@backstage/core-plugin-api": "workspace:^",
+ "@backstage/plugin-catalog-react": "workspace:^",
+ "@backstage/theme": "workspace:^",
+ "@material-ui/core": "^4.9.13",
+ "@material-ui/icons": "^4.9.1",
+ "@material-ui/lab": "^4.0.0-alpha.57",
+ "react-use": "^17.2.4"
+ },
+ "peerDependencies": {
+ "react": "^16.13.1 || ^17.0.0"
+ },
+ "devDependencies": {
+ "@backstage/cli": "workspace:^",
+ "@backstage/core-app-api": "workspace:^",
+ "@backstage/dev-utils": "workspace:^",
+ "@backstage/test-utils": "workspace:^",
+ "@testing-library/jest-dom": "^5.10.1",
+ "@testing-library/react": "^12.1.3",
+ "@testing-library/user-event": "^14.0.0",
+ "@types/node": "*",
+ "cross-fetch": "^3.1.5",
+ "msw": "^0.48.0"
+ },
+ "files": [
+ "dist"
+ ]
+}
diff --git a/plugins/org-react/src/components/GroupListPicker/GroupListPicker.test.tsx b/plugins/org-react/src/components/GroupListPicker/GroupListPicker.test.tsx
new file mode 100644
index 0000000000..b8a499b8fe
--- /dev/null
+++ b/plugins/org-react/src/components/GroupListPicker/GroupListPicker.test.tsx
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2022 The Backstage Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import React from 'react';
+import { fireEvent, render, waitFor } from '@testing-library/react';
+import { ApiProvider } from '@backstage/core-app-api';
+import { catalogApiRef } from '@backstage/plugin-catalog-react';
+import { CatalogApi } from '@backstage/catalog-client';
+import { GroupListPicker } from '../GroupListPicker';
+import { GroupEntity } from '@backstage/catalog-model';
+import { TestApiRegistry } from '@backstage/test-utils';
+
+const mockGroups: GroupEntity[] = [
+ {
+ apiVersion: 'backstage.io/v1alpha1',
+ kind: 'Group',
+ metadata: {
+ namespace: 'default',
+ name: 'group-a',
+ },
+ spec: {
+ type: 'org',
+ profile: {
+ displayName: 'Group A',
+ },
+ children: [],
+ },
+ },
+ {
+ apiVersion: 'backstage.io/v1alpha1',
+ kind: 'Group',
+ metadata: {
+ namespace: 'default',
+ name: 'group-b',
+ },
+ spec: {
+ type: 'department',
+ profile: {
+ displayName: 'Group B',
+ },
+ children: [],
+ },
+ },
+];
+
+const mockCatalogApi = {
+ getEntities: () => Promise.resolve({ items: mockGroups }),
+} as Partial;
+
+const apis = TestApiRegistry.from([catalogApiRef, mockCatalogApi]);
+
+describe(' ', () => {
+ it('can choose a group', async () => {
+ const { getByText, getByTestId } = render(
+
+ {}}
+ />
+ ,
+ );
+
+ fireEvent.click(getByTestId('group-list-picker-button'));
+ const input = getByTestId('group-list-picker-input').querySelector('input');
+ fireEvent.change(input as HTMLElement, { target: { value: 'GR' } });
+
+ await waitFor(async () => {
+ expect(getByText('Group A')).toBeInTheDocument();
+ fireEvent.click(getByText('Group A'));
+ expect(getByText('Group A')).toBeInTheDocument();
+ });
+ });
+});
diff --git a/plugins/org-react/src/components/GroupListPicker/GroupListPicker.tsx b/plugins/org-react/src/components/GroupListPicker/GroupListPicker.tsx
new file mode 100644
index 0000000000..1296c520c3
--- /dev/null
+++ b/plugins/org-react/src/components/GroupListPicker/GroupListPicker.tsx
@@ -0,0 +1,120 @@
+/*
+ * 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 } from 'react';
+import {
+ catalogApiRef,
+ humanizeEntityRef,
+} from '@backstage/plugin-catalog-react';
+import TextField from '@material-ui/core/TextField';
+import Autocomplete from '@material-ui/lab/Autocomplete';
+import useAsync from 'react-use/lib/useAsync';
+import Popover from '@material-ui/core/Popover';
+import { useApi } from '@backstage/core-plugin-api';
+import { ResponseErrorPanel } from '@backstage/core-components';
+import { Entity, GroupEntity } from '@backstage/catalog-model';
+import { GroupListPickerButton } from './GroupListPickerButton';
+
+/**
+ * Props for {@link GroupListPicker}.
+ *
+ * @public
+ */
+export type GroupListPickerProps = {
+ placeholder?: string;
+ groupTypes?: Array;
+ onChange: (value: GroupEntity | undefined) => void;
+};
+
+/** @public */
+export const GroupListPicker = (props: GroupListPickerProps) => {
+ const catalogApi = useApi(catalogApiRef);
+
+ const { onChange, groupTypes, placeholder = '' } = props;
+ const [anchorEl, setAnchorEl] = React.useState(null);
+ const [inputValue, setInputValue] = React.useState('');
+
+ const handleClick = (event: React.MouseEvent) => {
+ setAnchorEl(event.currentTarget);
+ };
+
+ const handleClose = () => {
+ setAnchorEl(null);
+ };
+
+ const open = Boolean(anchorEl);
+
+ const {
+ loading,
+ error,
+ value: groups,
+ } = useAsync(async () => {
+ const groupsList = await catalogApi.getEntities({
+ filter: {
+ kind: 'Group',
+ 'spec.type': groupTypes || [],
+ },
+ });
+
+ return groupsList.items as GroupEntity[];
+ }, [catalogApi, groupTypes]);
+
+ const handleChange = useCallback(
+ (_, v: GroupEntity | null) => {
+ onChange(v ?? undefined);
+ },
+ [onChange],
+ );
+
+ if (error) {
+ return ;
+ }
+
+ const getHumanEntityRef = (entity: Entity) => humanizeEntityRef(entity);
+
+ return (
+ <>
+
+ option.spec.type}
+ getOptionLabel={option =>
+ option.spec.profile?.displayName ?? getHumanEntityRef(option)
+ }
+ inputValue={inputValue}
+ onInputChange={(_, value) => setInputValue(value)}
+ onChange={handleChange}
+ style={{ width: '300px' }}
+ renderInput={params => (
+
+ )}
+ />
+
+
+ >
+ );
+};
diff --git a/plugins/org-react/src/components/GroupListPicker/GroupListPickerButton.tsx b/plugins/org-react/src/components/GroupListPicker/GroupListPickerButton.tsx
new file mode 100644
index 0000000000..149bf778b1
--- /dev/null
+++ b/plugins/org-react/src/components/GroupListPicker/GroupListPickerButton.tsx
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2022 The Backstage Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import React from 'react';
+import { BackstageTheme } from '@backstage/theme';
+import { makeStyles, Typography, Button } from '@material-ui/core';
+import KeyboardArrowDownIcon from '@material-ui/icons/KeyboardArrowDown';
+import PeopleIcon from '@material-ui/icons/People';
+
+const useStyles = makeStyles((theme: BackstageTheme) => ({
+ btn: {
+ margin: 0,
+ padding: 10,
+ width: '100%',
+ cursor: 'pointer',
+ justifyContent: 'space-between',
+ },
+ title: {
+ fontSize: '1.5rem',
+ fontStyle: 'normal',
+ fontWeight: theme.typography.fontWeightBold,
+ letterSpacing: '-0.25px',
+ lineHeight: '32px',
+ marginBottom: 0,
+ textTransform: 'none',
+ },
+ icon: {
+ transform: 'scale(1.5)',
+ },
+}));
+
+type GroupListPickerButtonProps = {
+ handleClick: (event: React.MouseEvent) => void;
+ group: string | undefined;
+};
+
+/** @public */
+export const GroupListPickerButton = (props: GroupListPickerButtonProps) => {
+ const { handleClick, group } = props;
+ const classes = useStyles();
+
+ return (
+ }
+ className={classes.btn}
+ size="large"
+ endIcon={ }
+ >
+ {group}
+
+ );
+};
diff --git a/plugins/org-react/src/components/GroupListPicker/index.ts b/plugins/org-react/src/components/GroupListPicker/index.ts
new file mode 100644
index 0000000000..fe1ba8e1ee
--- /dev/null
+++ b/plugins/org-react/src/components/GroupListPicker/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 { GroupListPicker } from './GroupListPicker';
+export type { GroupListPickerProps } from './GroupListPicker';
diff --git a/plugins/org-react/src/index.ts b/plugins/org-react/src/index.ts
new file mode 100644
index 0000000000..c3393bee48
--- /dev/null
+++ b/plugins/org-react/src/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 { GroupListPicker } from './components/GroupListPicker';
+export type { GroupListPickerProps } from './components/GroupListPicker';
diff --git a/plugins/org-react/src/setupTests.ts b/plugins/org-react/src/setupTests.ts
new file mode 100644
index 0000000000..9bb3e72355
--- /dev/null
+++ b/plugins/org-react/src/setupTests.ts
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2022 The Backstage Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import '@testing-library/jest-dom';
+import 'cross-fetch/polyfill';
diff --git a/plugins/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/Group/GroupProfile/GroupProfileCard.stories.tsx b/plugins/org/src/components/Cards/Group/GroupProfile/GroupProfileCard.stories.tsx
index fc45d9a8fe..cfb3d847a4 100644
--- a/plugins/org/src/components/Cards/Group/GroupProfile/GroupProfileCard.stories.tsx
+++ b/plugins/org/src/components/Cards/Group/GroupProfile/GroupProfileCard.stories.tsx
@@ -87,3 +87,44 @@ export default {
),
],
};
+
+const extraDetailsEntity: GroupEntity = {
+ apiVersion: 'backstage.io/v1alpha1',
+ kind: 'Group',
+ metadata: {
+ name: 'team-a',
+ description: 'Team A',
+ links: [
+ {
+ url: 'slack://user?team=T00000000&id=U00000000',
+ title: 'Slack',
+ icon: 'chat',
+ },
+ {
+ url: 'https://www.google.com',
+ title: 'Google',
+ },
+ ],
+ },
+ spec: {
+ profile: {
+ displayName: 'Team A',
+ email: 'team-a@example.com',
+ picture:
+ 'https://avatars.dicebear.com/api/identicon/team-a@example.com.svg?background=%23fff&margin=25',
+ },
+ type: 'group',
+ children: [],
+ },
+ relations: [dummyDepartment],
+};
+
+export const ExtraDetails = () => (
+
+
+
+
+
+
+
+);
diff --git a/plugins/org/src/components/Cards/Group/GroupProfile/GroupProfileCard.tsx b/plugins/org/src/components/Cards/Group/GroupProfile/GroupProfileCard.tsx
index dfdb566b20..3a6b7c238d 100644
--- a/plugins/org/src/components/Cards/Group/GroupProfile/GroupProfileCard.tsx
+++ b/plugins/org/src/components/Cards/Group/GroupProfile/GroupProfileCard.tsx
@@ -52,6 +52,7 @@ import {
Link,
} from '@backstage/core-components';
import { alertApiRef, useApi } from '@backstage/core-plugin-api';
+import { LinksGroup } from '../../Meta';
const CardTitle = (props: { title: string }) => (
@@ -76,7 +77,7 @@ export const GroupProfileCard = (props: { variant?: InfoCardVariants }) => {
}
const {
- metadata: { name, description, annotations },
+ metadata: { name, description, annotations, links },
spec: { profile },
} = group;
@@ -190,6 +191,7 @@ export const GroupProfileCard = (props: { variant?: InfoCardVariants }) => {
secondary="Child Groups"
/>
+
diff --git a/plugins/org/src/components/Cards/Meta/LinksGroup.tsx b/plugins/org/src/components/Cards/Meta/LinksGroup.tsx
new file mode 100644
index 0000000000..eeade18411
--- /dev/null
+++ b/plugins/org/src/components/Cards/Meta/LinksGroup.tsx
@@ -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 { EntityLink } from '@backstage/catalog-model';
+import { IconComponent, useApp } from '@backstage/core-plugin-api';
+import LanguageIcon from '@material-ui/icons/Language';
+import {
+ ListItem,
+ ListItemIcon,
+ ListItemText,
+ Divider,
+} from '@material-ui/core';
+import React from 'react';
+
+const WebLink = ({
+ href,
+ Icon,
+ text,
+}: {
+ href: string;
+ text?: string;
+ Icon?: IconComponent;
+}) => (
+
+ {Icon ? : }
+ {text}
+
+);
+
+export const LinksGroup = ({ links }: { links?: EntityLink[] }) => {
+ const app = useApp();
+ const iconResolver = (key?: string): IconComponent =>
+ key ? app.getSystemIcon(key) ?? LanguageIcon : LanguageIcon;
+
+ if (links === undefined) {
+ return null;
+ }
+
+ return (
+ <>
+
+ {links.map(link => {
+ return (
+
+ );
+ })}
+ >
+ );
+};
diff --git a/plugins/org/src/components/Cards/Meta/index.ts b/plugins/org/src/components/Cards/Meta/index.ts
new file mode 100644
index 0000000000..076af49bf9
--- /dev/null
+++ b/plugins/org/src/components/Cards/Meta/index.ts
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2022 The Backstage Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+export * from './LinksGroup';
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/org/src/components/Cards/User/UserProfileCard/UserProfileCard.stories.tsx b/plugins/org/src/components/Cards/User/UserProfileCard/UserProfileCard.stories.tsx
index eb7b8fadda..a27be7857b 100644
--- a/plugins/org/src/components/Cards/User/UserProfileCard/UserProfileCard.stories.tsx
+++ b/plugins/org/src/components/Cards/User/UserProfileCard/UserProfileCard.stories.tsx
@@ -102,3 +102,43 @@ export default {
}),
],
};
+
+const extraDetailsEntity: UserEntity = {
+ apiVersion: 'backstage.io/v1alpha1',
+ kind: 'User',
+ metadata: {
+ name: 'guest',
+ description: 'Description for guest',
+ links: [
+ {
+ url: 'slack://user?team=T00000000&id=U00000000',
+ title: 'Slack',
+ icon: 'chat',
+ },
+ {
+ url: 'https://www.google.com',
+ title: 'Google',
+ },
+ ],
+ },
+ spec: {
+ profile: {
+ displayName: 'Guest User',
+ email: 'guest@example.com',
+ picture:
+ 'https://avatars.dicebear.com/api/avataaars/guest@example.com.svg?background=%23fff',
+ },
+ memberOf: ['team-a'],
+ },
+ relations: [dummyGroup],
+};
+
+export const ExtraDetails = () => (
+
+
+
+
+
+
+
+);
diff --git a/plugins/org/src/components/Cards/User/UserProfileCard/UserProfileCard.test.tsx b/plugins/org/src/components/Cards/User/UserProfileCard/UserProfileCard.test.tsx
index f339a5828c..fb0df3d25f 100644
--- a/plugins/org/src/components/Cards/User/UserProfileCard/UserProfileCard.test.tsx
+++ b/plugins/org/src/components/Cards/User/UserProfileCard/UserProfileCard.test.tsx
@@ -155,4 +155,58 @@ describe('Edit Button', () => {
);
expect(rendered.getByRole('button')).toBeInTheDocument();
});
+
+ it('Should show the extra fields if either links or extra profile are filled', async () => {
+ const annotations: Record = {
+ 'backstage.io/edit-url': 'https://example.com/user.yaml',
+ };
+ const userEntity: UserEntity = {
+ apiVersion: 'backstage.io/v1alpha1',
+ kind: 'User',
+ metadata: {
+ name: 'calum.leavy',
+ description: 'Super awesome human',
+ annotations,
+ links: [
+ {
+ url: 'slack://user?team=T00000000&id=U00000000',
+ title: 'Slack',
+ icon: 'message',
+ },
+ {
+ url: 'https://www.google.com',
+ title: 'Google',
+ },
+ ],
+ },
+ spec: {
+ profile: {
+ displayName: 'Calum Leavy',
+ email: 'calum-leavy@example.com',
+ },
+ memberOf: ['ExampleGroup'],
+ },
+ relations: [
+ {
+ type: 'memberOf',
+ targetRef: 'group:default/examplegroup',
+ },
+ ],
+ };
+
+ const rendered = await renderWithEffects(
+ wrapInTestApp(
+
+
+ ,
+ {
+ mountedRoutes: {
+ '/catalog/:namespace/:kind/:name': entityRouteRef,
+ },
+ },
+ ),
+ );
+ expect(rendered.getByText('Slack')).toBeInTheDocument();
+ expect(rendered.getByText('Google')).toBeInTheDocument();
+ });
});
diff --git a/plugins/org/src/components/Cards/User/UserProfileCard/UserProfileCard.tsx b/plugins/org/src/components/Cards/User/UserProfileCard/UserProfileCard.tsx
index dd75578687..a35c1c057b 100644
--- a/plugins/org/src/components/Cards/User/UserProfileCard/UserProfileCard.tsx
+++ b/plugins/org/src/components/Cards/User/UserProfileCard/UserProfileCard.tsx
@@ -46,6 +46,7 @@ import {
InfoCardVariants,
Link,
} from '@backstage/core-components';
+import { LinksGroup } from '../../Meta';
const CardTitle = (props: { title?: string }) =>
props.title ? (
@@ -66,7 +67,7 @@ export const UserProfileCard = (props: { variant?: InfoCardVariants }) => {
user.metadata.annotations?.[ANNOTATION_EDIT_URL];
const {
- metadata: { name: metaName, description },
+ metadata: { name: metaName, description, links },
spec: { profile },
} = user;
const displayName = profile?.displayName ?? metaName;
@@ -128,6 +129,8 @@ export const UserProfileCard = (props: { variant?: InfoCardVariants }) => {
/>
+
+
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 afb6a2867f..a892d6a8dc 100644
--- a/plugins/playlist-backend/CHANGELOG.md
+++ b/plugins/playlist-backend/CHANGELOG.md
@@ -1,5 +1,30 @@
# @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
+
+- 605f269f0d: Updated Playlist plugin docs:
+
+ - Updated `playlist` plugin README to include note about installing backend plugin and added images for the various features
+ - Updated `playlist-backend` plugin README to remove `IdentityClient` import in example as it is not used and made minor change to headings
+
## 0.2.1-next.0
### Patch Changes
diff --git a/plugins/playlist-backend/README.md b/plugins/playlist-backend/README.md
index 14a39ca741..c0055ebdf7 100644
--- a/plugins/playlist-backend/README.md
+++ b/plugins/playlist-backend/README.md
@@ -2,21 +2,20 @@
Welcome to the playlist backend plugin!
-# Installation
+## Installation
-## Install the package
+### Install the package
```bash
# From your Backstage root directory
yarn add --cwd packages/backend @backstage/plugin-playlist-backend
```
-## Adding the plugin to your `packages/backend`
+### Adding the plugin to your `packages/backend`
You'll need to add the plugin to the router in your `backend` package. You can do this by creating a file called `packages/backend/src/plugins/playlist.ts`
```tsx
-import { IdentityClient } from '@backstage/plugin-auth-node';
import { createRouter } from '@backstage/plugin-playlist-backend';
import { Router } from 'express';
import { PluginEnvironment } from '../types';
diff --git a/plugins/playlist-backend/package.json b/plugins/playlist-backend/package.json
index 6bb557d8a3..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.0",
+ "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 b064b2e5b6..f49f0c6301 100644
--- a/plugins/playlist/CHANGELOG.md
+++ b/plugins/playlist/CHANGELOG.md
@@ -1,5 +1,31 @@
# @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
+
+- 605f269f0d: Updated Playlist plugin docs:
+
+ - Updated `playlist` plugin README to include note about installing backend plugin and added images for the various features
+ - Updated `playlist-backend` plugin README to remove `IdentityClient` import in example as it is not used and made minor change to headings
+
## 0.1.2-next.0
### Patch Changes
diff --git a/plugins/playlist/README.md b/plugins/playlist/README.md
index 7c814d302b..6ae3fb84ac 100644
--- a/plugins/playlist/README.md
+++ b/plugins/playlist/README.md
@@ -6,6 +6,14 @@ This plugin allows you to create, share, and follow custom collections of entiti
## Setup
+The following sections will help you get the Playlist plugin setup and running
+
+### Backend
+
+You need to setup the [Playlist backend plugin](https://github.com/backstage/backstage/tree/master/plugins/playlist-backend) before you move forward with any of these steps if you haven't already
+
+### Installation
+
Install this plugin:
```bash
@@ -123,6 +131,28 @@ const defaultEntityPage = (
Note: the above only shows an example for the `defaultEntityPage` for a full example of this you can look at [this EntityPage](../../packages/app/src/components/catalog/EntityPage.tsx)
+## Features
+
+### View All Playlists
+
+
+
+### View Playlist
+
+
+
+### Create New Playlist
+
+
+
+### Add Entities to Playlist
+
+
+
+### Add to Playlist from Entity
+
+
+
## Links
- [playlist-backend](../playlist-backend) provides the backend API for this frontend.
diff --git a/plugins/playlist/docs/playlist-add-entities.png b/plugins/playlist/docs/playlist-add-entities.png
new file mode 100644
index 0000000000..a53de49880
Binary files /dev/null and b/plugins/playlist/docs/playlist-add-entities.png differ
diff --git a/plugins/playlist/docs/playlist-add-from-entity.png b/plugins/playlist/docs/playlist-add-from-entity.png
new file mode 100644
index 0000000000..d41135064a
Binary files /dev/null and b/plugins/playlist/docs/playlist-add-from-entity.png differ
diff --git a/plugins/playlist/docs/playlist-create-new.png b/plugins/playlist/docs/playlist-create-new.png
new file mode 100644
index 0000000000..cc369e26fa
Binary files /dev/null and b/plugins/playlist/docs/playlist-create-new.png differ
diff --git a/plugins/playlist/docs/playlist-view-all.png b/plugins/playlist/docs/playlist-view-all.png
new file mode 100644
index 0000000000..1b65eb1af2
Binary files /dev/null and b/plugins/playlist/docs/playlist-view-all.png differ
diff --git a/plugins/playlist/docs/playlist-view-single.png b/plugins/playlist/docs/playlist-view-single.png
new file mode 100644
index 0000000000..0890c5013b
Binary files /dev/null and b/plugins/playlist/docs/playlist-view-single.png differ
diff --git a/plugins/playlist/package.json b/plugins/playlist/package.json
index df620fc97a..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.0",
+ "version": "0.1.2-next.2",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -12,6 +12,11 @@
"backstage": {
"role": "frontend-plugin"
},
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/backstage/backstage",
+ "directory": "plugins/playlist"
+ },
"scripts": {
"start": "backstage-cli package start",
"build": "backstage-cli package build",
@@ -57,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 1a73a7fc41..35f52ccfaf 100644
--- a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md
+++ b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md
@@ -1,5 +1,24 @@
# @backstage/plugin-scaffolder-backend-module-cookiecutter
+## 0.2.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
+
+- Updated dependencies
+ - @backstage/plugin-scaffolder-backend@1.8.0-next.1
+
## 0.2.13-next.0
### Patch Changes
diff --git a/plugins/scaffolder-backend-module-cookiecutter/package.json b/plugins/scaffolder-backend-module-cookiecutter/package.json
index a42bfdcf60..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.0",
+ "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 388ad285f1..7917e73068 100644
--- a/plugins/scaffolder-backend-module-rails/CHANGELOG.md
+++ b/plugins/scaffolder-backend-module-rails/CHANGELOG.md
@@ -1,5 +1,24 @@
# @backstage/plugin-scaffolder-backend-module-rails
+## 0.4.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
+
+- Updated dependencies
+ - @backstage/plugin-scaffolder-backend@1.8.0-next.1
+
## 0.4.6-next.0
### Patch Changes
diff --git a/plugins/scaffolder-backend-module-rails/package.json b/plugins/scaffolder-backend-module-rails/package.json
index 6a08271e80..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.0",
+ "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 52654ecc2a..2019b9a0a4 100644
--- a/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md
+++ b/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md
@@ -1,5 +1,21 @@
# @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
+
+- Updated dependencies
+ - @backstage/plugin-scaffolder-backend@1.8.0-next.1
+
## 0.2.11-next.0
### Patch Changes
diff --git a/plugins/scaffolder-backend-module-yeoman/package.json b/plugins/scaffolder-backend-module-yeoman/package.json
index d617fec38e..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.0",
+ "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 caf413992b..1a0135f5f6 100644
--- a/plugins/scaffolder-backend/CHANGELOG.md
+++ b/plugins/scaffolder-backend/CHANGELOG.md
@@ -1,5 +1,36 @@
# @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
+
+- 5921b5ce49: - The GitLab Project ID for the `publish:gitlab:merge-request` action is now passed through the query parameter `project` in the `repoUrl`. It still allows people to not use the `projectid` and use the `repoUrl` with the `owner` and `repo` query parameters instead. This makes it easier to publish to repositories instead of writing the full path to the project.
+
## 1.8.0-next.0
### 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 37565a8d7a..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.0",
+ "version": "1.8.0-next.2",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -90,10 +90,10 @@
"@types/nunjucks": "^3.1.4",
"@types/supertest": "^2.0.8",
"@types/zen-observable": "^0.8.0",
- "esbuild": "^0.14.1",
+ "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/scripts/build-nunjucks.js b/plugins/scaffolder-backend/scripts/build-nunjucks.js
index b195f96159..8b98ac4305 100755
--- a/plugins/scaffolder-backend/scripts/build-nunjucks.js
+++ b/plugins/scaffolder-backend/scripts/build-nunjucks.js
@@ -58,7 +58,7 @@ require('esbuild')
bundle: true,
format: 'cjs',
platform: 'node',
- target: 'node14',
+ target: 'node16',
banner: { js: NUNJUCKS_LICENSE },
external: ['fsevents'],
outfile: path.resolve(__dirname, '../assets/nunjucks.js.txt'),
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-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts
index 64761f0871..2a71c9f748 100644
--- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts
+++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts
@@ -42,7 +42,7 @@ export const createPublishGitlabMergeRequestAction = (options: {
targetPath?: string;
token?: string;
commitAction?: 'create' | 'delete' | 'update';
- /** @deprecated Use projectPath instead */
+ /** @deprecated projectID passed as query parameters in the repoUrl */
projectid?: string;
removeSourceBranch?: boolean;
assignee?: string;
@@ -58,7 +58,7 @@ export const createPublishGitlabMergeRequestAction = (options: {
title: 'Repository Location',
description: `Accepts the format 'gitlab.com/group_name/project_name' where 'project_name' is the repository name and 'group_name' is a group or username`,
},
- /** @deprecated Use projectPath instead */
+ /** @deprecated projectID is passed as query parameters in the repoUrl */
projectid: {
type: 'string',
title: 'projectid',
@@ -146,14 +146,12 @@ export const createPublishGitlabMergeRequestAction = (options: {
title,
token: providedToken,
} = ctx.input;
- const { host, owner, repo } = parseRepoUrl(repoUrl, integrations);
- const projectPath = `${owner}/${repo}`;
- if (ctx.input.projectid) {
- const deprecationWarning = `Property "projectid" is deprecated and no longer to needed to create a MR`;
- ctx.logger.warn(deprecationWarning);
- console.warn(deprecationWarning);
- }
+ const { host, owner, repo, project } = parseRepoUrl(
+ repoUrl,
+ integrations,
+ );
+ const repoID = project ? project : `${owner}/${repo}`;
const integrationConfig = integrations.gitlab.byHost(host);
@@ -211,22 +209,19 @@ export const createPublishGitlabMergeRequestAction = (options: {
content: file.content.toString('base64'),
execute_filemode: file.executable,
}));
- const projects = await api.Projects.show(projectPath);
+
+ const projects = await api.Projects.show(repoID);
const { default_branch: defaultBranch } = projects;
try {
- await api.Branches.create(
- projectPath,
- branchName,
- String(defaultBranch),
- );
+ await api.Branches.create(repoID, branchName, String(defaultBranch));
} catch (e) {
throw new InputError(`The branch creation failed ${e}`);
}
try {
- await api.Commits.create(projectPath, branchName, title, actions);
+ await api.Commits.create(repoID, branchName, ctx.input.title, actions);
} catch (e) {
throw new InputError(
`Committing the changes to ${branchName} failed ${e}`,
@@ -235,7 +230,7 @@ export const createPublishGitlabMergeRequestAction = (options: {
try {
const mergeRequestUrl = await api.MergeRequests.create(
- projectPath,
+ repoID,
branchName,
String(defaultBranch),
title,
@@ -247,9 +242,8 @@ export const createPublishGitlabMergeRequestAction = (options: {
).then((mergeRequest: { web_url: string }) => {
return mergeRequest.web_url;
});
- /** @deprecated */
- ctx.output('projectid', projectPath);
- ctx.output('projectPath', projectPath);
+ ctx.output('projectid', repoID);
+ ctx.output('projectPath', repoID);
ctx.output('mergeRequestUrl', mergeRequestUrl);
} catch (e) {
throw new InputError(`Merge request creation failed${e}`);
diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/util.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/util.test.ts
index cc879d4f55..5446109056 100644
--- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/util.test.ts
+++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/util.test.ts
@@ -15,7 +15,9 @@
*/
import path from 'path';
-import { getRepoSourceDirectory, isExecutable } from './util';
+import { getRepoSourceDirectory, isExecutable, parseRepoUrl } from './util';
+import { ScmIntegrations } from '@backstage/integration';
+import { ConfigReader } from '@backstage/config';
describe('getRepoSourceDirectory', () => {
it('should return workspace root if no sub folder is given', () => {
@@ -85,3 +87,95 @@ describe('isExecutable', () => {
expect(isExecutable(0o100640)).toBe(false);
});
});
+
+describe('parseRepoUrl', () => {
+ const config = new ConfigReader({
+ integrations: {
+ gitlab: [
+ {
+ host: 'www.gitlab.com',
+ token: 'token',
+ apiBaseUrl: 'https://api.gitlab.com',
+ },
+ ],
+ bitbucket: [
+ {
+ host: 'www.bitbucket.net',
+ apiBaseUrl: 'https://api.hosted.bitbucket.net',
+ },
+ {
+ host: 'www.bitbucket.org',
+ username: 'username',
+ appPassword: 'password',
+ apiBaseUrl: 'https://api.hosted.bitbucket.org',
+ },
+ ],
+ },
+ });
+ const integrations = ScmIntegrations.fromConfig(config);
+ it('should throw an exception if no parameters are passed (gitlab)', () => {
+ expect(() => parseRepoUrl('www.gitlab.com', integrations)).toThrow(
+ 'Invalid repo URL passed to publisher: https://www.gitlab.com/, missing owner',
+ );
+ });
+ it('should return the project ID in the `project` parameter (gitlab)', () => {
+ expect(
+ parseRepoUrl('www.gitlab.com?project=234', integrations),
+ ).toStrictEqual({
+ host: 'www.gitlab.com',
+ organization: undefined,
+ owner: undefined,
+ project: '234',
+ repo: null,
+ workspace: undefined,
+ });
+ });
+ it('should throw an exception if the repo parameter is missing, but owner parameter is set', () => {
+ expect(() =>
+ parseRepoUrl('www.gitlab.com?owner=owner', integrations),
+ ).toThrow(
+ 'Invalid repo URL passed to publisher: https://www.gitlab.com/?owner=owner, missing repo',
+ );
+ });
+ it('should throw an exception if the owner parameter is missing, but repo parameter is set (gitlab)', () => {
+ expect(() =>
+ parseRepoUrl('www.gitlab.com?repo=repo', integrations),
+ ).toThrow(
+ 'Invalid repo URL passed to publisher: https://www.gitlab.com/?repo=repo, missing owner',
+ );
+ });
+ it('should return the workspace, project and repo (bitbucket.org)', () => {
+ expect(
+ parseRepoUrl(
+ 'www.bitbucket.org?project=project&workspace=workspace&repo=repo',
+ integrations,
+ ),
+ ).toStrictEqual({
+ host: 'www.bitbucket.org',
+ organization: undefined,
+ owner: undefined,
+ project: 'project',
+ repo: 'repo',
+ workspace: 'workspace',
+ });
+ });
+ it('should return the project and repo (another bitbucket instance)', () => {
+ expect(
+ parseRepoUrl('www.bitbucket.net?project=project&repo=repo', integrations),
+ ).toStrictEqual({
+ host: 'www.bitbucket.net',
+ organization: undefined,
+ owner: undefined,
+ project: 'project',
+ repo: 'repo',
+ workspace: undefined,
+ });
+ });
+ it('should throw an exception if the workspace parameter is missing for bitbucket.org instance (bitbucket.org)', () => {
+ expect(() =>
+ parseRepoUrl('www.bitbucket.org?project=project&repo=repo', integrations),
+ ).toThrow(
+ 'Invalid repo URL passed to publisher: https://www.bitbucket.org/?project=project&repo=repo, missing workspace',
+ );
+ });
+});
diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/util.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/util.ts
index fff3213cb7..61bd704a0b 100644
--- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/util.ts
+++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/util.ts
@@ -71,32 +71,30 @@ export const parseRepoUrl = (
);
}
- if (type === 'bitbucket') {
- if (host === 'bitbucket.org') {
- if (!workspace) {
- throw new InputError(
- `Invalid repo URL passed to publisher: ${repoUrl}, missing workspace`,
- );
+ const repo: string = parsed.searchParams.get('repo')!;
+ switch (type) {
+ case 'bitbucket': {
+ if (host === 'www.bitbucket.org') {
+ checkRequiredParams(parsed, 'workspace');
}
+ checkRequiredParams(parsed, 'project', 'repo');
+ break;
}
- if (!project) {
- throw new InputError(
- `Invalid repo URL passed to publisher: ${repoUrl}, missing project`,
- );
+ case 'gitlab': {
+ // project is the projectID, and if defined, owner and repo won't be needed.
+ if (!project) {
+ checkRequiredParams(parsed, 'owner', 'repo');
+ }
+ break;
}
- } else {
- if (!owner && type !== 'gerrit') {
- throw new InputError(
- `Invalid repo URL passed to publisher: ${repoUrl}, missing owner`,
- );
+ case 'gerrit': {
+ checkRequiredParams(parsed, 'repo');
+ break;
+ }
+ default: {
+ checkRequiredParams(parsed, 'repo', 'owner');
+ break;
}
- }
-
- const repo = parsed.searchParams.get('repo');
- if (!repo) {
- throw new InputError(
- `Invalid repo URL passed to publisher: ${repoUrl}, missing repo`,
- );
}
return { host, owner, repo, organization, workspace, project };
@@ -106,3 +104,26 @@ export const isExecutable = (fileMode: number) => {
const res = fileMode & executeBitMask;
return res > 0;
};
+
+/**
+ * This function checks if the required parameters (given as the `params` argument) are present in the URL
+ *
+ * @param repoUrl - the URL for the repository
+ * @param params - a variadic list of URL query parameter names
+ *
+ * @throws
+ * An InputError exception is thrown if any of the required parameters is not in the URL.
+ *
+ * @public
+ */
+function checkRequiredParams(repoUrl: URL, ...params: string[]) {
+ for (let i = 0; i < params.length; i++) {
+ if (!repoUrl.searchParams.get(params[i])) {
+ throw new InputError(
+ `Invalid repo URL passed to publisher: ${repoUrl.toString()}, missing ${
+ params[i]
+ }`,
+ );
+ }
+ }
+}
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 2d06042a90..f0962db097 100644
--- a/plugins/scaffolder/api-report.md
+++ b/plugins/scaffolder/api-report.md
@@ -43,7 +43,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 511b020c3c..75f92916df 100644
--- a/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/Stepper.tsx
+++ b/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/Stepper.tsx
@@ -13,8 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import { useApiHolder } from '@backstage/core-plugin-api';
-import { JsonObject, JsonValue } from '@backstage/types';
+import {
+ useAnalytics,
+ useApiHolder,
+ useRouteRefParams,
+} from '@backstage/core-plugin-api';
+import { JsonValue } from '@backstage/types';
import {
Stepper as MuiStepper,
Step as MuiStep,
@@ -31,6 +35,7 @@ import { createAsyncValidators } from './createAsyncValidators';
import { useTemplateSchema } from './useTemplateSchema';
import { ReviewState } from './ReviewState';
import validator from '@rjsf/validator-ajv8';
+import { selectedTemplateRouteRef } from '../../../routes';
const useStyles = makeStyles(theme => ({
backButton: {
@@ -59,10 +64,12 @@ export interface StepperProps {
const Form = withTheme(require('@rjsf/material-ui-v5').Theme);
export const Stepper = (props: StepperProps) => {
+ const { templateName } = useRouteRefParams(selectedTemplateRouteRef);
+ const analytics = useAnalytics();
const { steps } = useTemplateSchema(props.manifest);
const apiHolder = useApiHolder();
const [activeStep, setActiveStep] = useState(0);
- const [formState, setFormState] = useState({});
+ const [formState, setFormState] = useState>({});
const [errors, setErrors] = useState<
undefined | Record
>();
@@ -90,7 +97,11 @@ export const Stepper = (props: StepperProps) => {
setActiveStep(prevActiveStep => prevActiveStep - 1);
};
- const handleNext = async ({ formData }: { formData: JsonObject }) => {
+ const handleNext = async ({
+ formData,
+ }: {
+ formData: Record;
+ }) => {
// TODO(blam): What do we do about loading states, does each field extension get a chance
// to display it's own loading? Or should we grey out the entire form.
setErrors(undefined);
@@ -105,7 +116,11 @@ export const Stepper = (props: StepperProps) => {
setErrors(returnedValidation);
} else {
setErrors(undefined);
- setActiveStep(prevActiveStep => prevActiveStep + 1);
+ setActiveStep(prevActiveStep => {
+ const stepNum = prevActiveStep + 1;
+ analytics.captureEvent('click', `Next Step (${stepNum})`);
+ return stepNum;
+ });
}
setFormState(current => ({ ...current, ...formData }));
};
@@ -128,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}
@@ -160,7 +176,17 @@ export const Stepper = (props: StepperProps) => {
props.onComplete(formState)}
+ onClick={() => {
+ props.onComplete(formState);
+ const name =
+ typeof formState.name === 'string'
+ ? formState.name
+ : undefined;
+ analytics.captureEvent(
+ 'create',
+ name || `new ${templateName}`,
+ );
+ }}
>
Create
diff --git a/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.test.tsx b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.test.tsx
new file mode 100644
index 0000000000..f36fae9aa3
--- /dev/null
+++ b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.test.tsx
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2022 The Backstage Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { ApiProvider } from '@backstage/core-app-api';
+import { analyticsApiRef } from '@backstage/core-plugin-api';
+import {
+ MockAnalyticsApi,
+ renderInTestApp,
+ TestApiRegistry,
+} from '@backstage/test-utils';
+import { act, fireEvent } from '@testing-library/react';
+import React from 'react';
+import { scaffolderApiRef } from '../../api';
+import { nextRouteRef, rootRouteRef } from '../../routes';
+import { ScaffolderApi } from '../../types';
+import { TemplateWizardPage } from './TemplateWizardPage';
+
+jest.mock('react-router-dom', () => {
+ return {
+ ...(jest.requireActual('react-router-dom') as any),
+ useParams: () => ({
+ templateName: 'test',
+ }),
+ };
+});
+
+const scaffolderApiMock: jest.Mocked = {
+ scaffold: jest.fn(),
+ getTemplateParameterSchema: jest.fn(),
+ getIntegrationsList: jest.fn(),
+ getTask: jest.fn(),
+ streamLogs: jest.fn(),
+ listActions: jest.fn(),
+ listTasks: jest.fn(),
+};
+
+const analyticsMock = new MockAnalyticsApi();
+const apis = TestApiRegistry.from(
+ [scaffolderApiRef, scaffolderApiMock],
+ [analyticsApiRef, analyticsMock],
+);
+
+describe('TemplateWizardPage', () => {
+ it('captures expected analytics events', async () => {
+ scaffolderApiMock.scaffold.mockResolvedValue({ taskId: 'xyz' });
+ scaffolderApiMock.getTemplateParameterSchema.mockResolvedValue({
+ steps: [
+ {
+ title: 'Step 1',
+ schema: {
+ properties: {
+ name: {
+ type: 'string',
+ },
+ },
+ },
+ },
+ ],
+ title: 'React JSON Schema Form Test',
+ });
+
+ const { findByRole, getByRole } = await renderInTestApp(
+
+ ,
+ ,
+ {
+ mountedRoutes: {
+ '/create': nextRouteRef,
+ '/create-legacy': rootRouteRef,
+ },
+ },
+ );
+
+ // Fill out the name field
+ fireEvent.change(getByRole('textbox', { name: 'name' }), {
+ target: { value: 'expected-name' },
+ });
+
+ // Go to the final page
+ await act(async () => {
+ fireEvent.click(await findByRole('button', { name: 'Review' }));
+ });
+
+ // Create the software
+ await act(async () => {
+ fireEvent.click(await findByRole('button', { name: 'Create' }));
+ });
+
+ // The "Next Step" button should have fired an event
+ expect(analyticsMock.getEvents()[0]).toMatchObject({
+ action: 'click',
+ subject: 'Next Step (1)',
+ context: { entityRef: 'template:default/test' },
+ });
+
+ // And the "Create" button should have fired an event
+ expect(analyticsMock.getEvents()[1]).toMatchObject({
+ action: 'create',
+ subject: 'expected-name',
+ context: { entityRef: 'template:default/test' },
+ });
+ });
+});
diff --git a/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx
index b650e4a676..28dc806214 100644
--- a/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx
+++ b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx
@@ -26,6 +26,7 @@ import { NextFieldExtensionOptions } from '../../extensions';
import { Navigate, useNavigate } from 'react-router';
import { stringifyEntityRef } from '@backstage/catalog-model';
import {
+ AnalyticsContext,
errorApiRef,
useApi,
useRouteRef,
@@ -111,34 +112,36 @@ export const TemplateWizardPage = (props: TemplateWizardPageProps) => {
}
return (
-
-
-
- {loading && }
- {manifest && (
-
+
+
+
+ {loading && }
+ {manifest && (
+
+ }
+ noPadding
+ titleTypographyProps={{ component: 'h2' }}
+ >
+
- }
- noPadding
- titleTypographyProps={{ component: 'h2' }}
- >
-
-
- )}
-
-
+
+ )}
+
+
+
);
};
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/splunk-on-call/src/components/EntitySplunkOnCallCard.test.tsx b/plugins/splunk-on-call/src/components/EntitySplunkOnCallCard.test.tsx
index 0688fb8237..051d9de030 100644
--- a/plugins/splunk-on-call/src/components/EntitySplunkOnCallCard.test.tsx
+++ b/plugins/splunk-on-call/src/components/EntitySplunkOnCallCard.test.tsx
@@ -13,11 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import React from 'react';
-import { act, fireEvent, render, waitFor } from '@testing-library/react';
import { Entity } from '@backstage/catalog-model';
+import { ApiProvider, ConfigReader } from '@backstage/core-app-api';
+import {
+ alertApiRef,
+ ConfigApi,
+ configApiRef,
+} from '@backstage/core-plugin-api';
import { EntityProvider } from '@backstage/plugin-catalog-react';
import { TestApiRegistry, wrapInTestApp } from '@backstage/test-utils';
+import { act, fireEvent, render, waitFor } from '@testing-library/react';
+import React from 'react';
import {
splunkOnCallApiRef,
SplunkOnCallClient,
@@ -33,13 +39,7 @@ import {
MOCK_TEAM_NO_INCIDENTS,
} from '../api/mocks';
import { EntitySplunkOnCallCard } from './EntitySplunkOnCallCard';
-
-import {
- alertApiRef,
- ConfigApi,
- configApiRef,
-} from '@backstage/core-plugin-api';
-import { ApiProvider, ConfigReader } from '@backstage/core-app-api';
+import { expectTriggeredIncident } from './TriggerDialog/testUtils';
const mockSplunkOnCallApi: Partial = {
getUsers: async () => [],
@@ -167,8 +167,10 @@ describe('SplunkOnCallCard', () => {
mockSplunkOnCallApi.getTeams = jest
.fn()
.mockImplementation(async () => [MOCK_TEAM]);
+ const mockTriggerAlarmFn = jest.fn();
+ mockSplunkOnCallApi.incidentAction = mockTriggerAlarmFn;
- const { getByText, queryByTestId } = render(
+ const { getByRole, getByTestId, getByText, queryByTestId } = render(
wrapInTestApp(
@@ -179,10 +181,23 @@ describe('SplunkOnCallCard', () => {
);
await waitFor(() => !queryByTestId('progress'));
expect(getByText(`Team: ${MOCK_TEAM.name}`)).toBeInTheDocument();
+ expect(getByText('Create Incident')).toBeInTheDocument();
await waitFor(
() => expect(getByText('test-incident')).toBeInTheDocument(),
{ timeout: 2000 },
);
+
+ const createIncidentButton = await getByText('Create Incident');
+ await act(async () => {
+ fireEvent.click(createIncidentButton);
+ });
+ expect(getByRole('dialog')).toBeInTheDocument();
+
+ await expectTriggeredIncident(
+ 'test-routing-key',
+ getByTestId,
+ mockTriggerAlarmFn,
+ );
});
it('Handles custom error for missing token', async () => {
diff --git a/plugins/splunk-on-call/src/components/EntitySplunkOnCallCard.tsx b/plugins/splunk-on-call/src/components/EntitySplunkOnCallCard.tsx
index d635f7328f..26521ea9ee 100644
--- a/plugins/splunk-on-call/src/components/EntitySplunkOnCallCard.tsx
+++ b/plugins/splunk-on-call/src/components/EntitySplunkOnCallCard.tsx
@@ -29,11 +29,11 @@ import AlarmAddIcon from '@material-ui/icons/AlarmAdd';
import WebIcon from '@material-ui/icons/Web';
import { Alert } from '@material-ui/lab';
import { splunkOnCallApiRef, UnauthorizedError } from '../api';
-import { MissingApiKeyOrApiIdError } from './Errors/MissingApiKeyOrApiIdError';
+import { MissingApiKeyOrApiIdError } from './Errors';
import { EscalationPolicy } from './Escalation';
import { Incidents } from './Incident';
import { TriggerDialog } from './TriggerDialog';
-import { Team, User } from './types';
+import { RoutingKey, Team, User } from './types';
import { configApiRef, useApi } from '@backstage/core-plugin-api';
import {
@@ -143,7 +143,7 @@ export const EntitySplunkOnCallCard = (props: EntitySplunkOnCallCardProps) => {
}, []);
const {
- value: usersAndTeams,
+ value: entityData,
loading,
error,
} = useAsync(async () => {
@@ -162,11 +162,15 @@ export const EntitySplunkOnCallCard = (props: EntitySplunkOnCallCardProps) => {
teams.find(teamValue => teamValue.name === teamAnnotation),
].filter(team => team !== undefined);
- if (!foundTeams.length && routingKeyAnnotation) {
+ let foundRoutingKey: RoutingKey | undefined;
+ if (routingKeyAnnotation) {
const routingKeys = await api.getRoutingKeys();
- const foundRoutingKey = routingKeys.find(
+ foundRoutingKey = routingKeys.find(
key => key.routingKey === routingKeyAnnotation,
);
+ }
+
+ if (!foundTeams.length) {
foundTeams = foundRoutingKey
? foundRoutingKey.targets
.map(target => {
@@ -179,7 +183,7 @@ export const EntitySplunkOnCallCard = (props: EntitySplunkOnCallCardProps) => {
: [];
}
- return { usersHashMap, foundTeams };
+ return { usersHashMap, foundTeams, foundRoutingKey };
});
if (!teamAnnotation && !routingKeyAnnotation) {
@@ -206,7 +210,7 @@ export const EntitySplunkOnCallCard = (props: EntitySplunkOnCallCardProps) => {
return ;
}
- if (!usersAndTeams?.foundTeams || !usersAndTeams?.foundTeams.length) {
+ if (!entityData?.foundTeams || !entityData?.foundTeams.length) {
return (
{
const Content = ({
team,
+ routingKey,
usersHashMap,
}: {
team: Team | undefined;
+ routingKey: RoutingKey | undefined;
usersHashMap: any;
}) => {
const teamName = team?.name ?? '';
@@ -235,7 +241,7 @@ export const EntitySplunkOnCallCard = (props: EntitySplunkOnCallCardProps) => {
)}
{
icon: ,
};
- const teams = usersAndTeams?.foundTeams || [];
+ const teams = entityData?.foundTeams || [];
return (
<>
@@ -277,7 +283,11 @@ export const EntitySplunkOnCallCard = (props: EntitySplunkOnCallCardProps) => {
/>
-
+
))}
diff --git a/plugins/splunk-on-call/src/components/TriggerDialog/TriggerDialog.test.tsx b/plugins/splunk-on-call/src/components/TriggerDialog/TriggerDialog.test.tsx
index 0b64a137af..3bfbddb0e4 100644
--- a/plugins/splunk-on-call/src/components/TriggerDialog/TriggerDialog.test.tsx
+++ b/plugins/splunk-on-call/src/components/TriggerDialog/TriggerDialog.test.tsx
@@ -13,14 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import React from 'react';
-import { render, fireEvent, act } from '@testing-library/react';
-import { TestApiRegistry, wrapInTestApp } from '@backstage/test-utils';
-import { splunkOnCallApiRef } from '../../api';
-import { TriggerDialog } from './TriggerDialog';
-
import { ApiProvider } from '@backstage/core-app-api';
import { alertApiRef } from '@backstage/core-plugin-api';
+import { TestApiRegistry, wrapInTestApp } from '@backstage/test-utils';
+import { render } from '@testing-library/react';
+import React from 'react';
+import { splunkOnCallApiRef } from '../../api';
+import { TriggerDialog } from './TriggerDialog';
+import { expectTriggeredIncident } from './testUtils';
describe('TriggerDialog', () => {
const mockTriggerAlarmFn = jest.fn();
@@ -38,7 +38,7 @@ describe('TriggerDialog', () => {
wrapInTestApp(
{}}
onIncidentCreated={() => {}}
@@ -53,34 +53,6 @@ describe('TriggerDialog', () => {
exact: false,
}),
).toBeInTheDocument();
- const incidentType = getByTestId('trigger-incident-type');
- const incidentId = getByTestId('trigger-incident-id');
- const incidentDisplayName = getByTestId('trigger-incident-displayName');
- const incidentMessage = getByTestId('trigger-incident-message');
-
- await act(async () => {
- fireEvent.change(incidentType, { target: { value: 'CRITICAL' } });
- fireEvent.change(incidentId, { target: { value: 'incident-id' } });
- fireEvent.change(incidentDisplayName, {
- target: { value: 'incident-display-name' },
- });
- fireEvent.change(incidentMessage, {
- target: { value: 'incident-message' },
- });
- });
-
- // Trigger incident creation button
- const triggerButton = getByTestId('trigger-button');
- await act(async () => {
- fireEvent.click(triggerButton);
- });
- expect(mockTriggerAlarmFn).toHaveBeenCalled();
- expect(mockTriggerAlarmFn).toHaveBeenCalledWith({
- incidentType: 'CRITICAL',
- incidentId: 'incident-id',
- routingKey: 'Example',
- incidentDisplayName: 'incident-display-name',
- incidentMessage: 'incident-message',
- });
+ await expectTriggeredIncident('Example', getByTestId, mockTriggerAlarmFn);
});
});
diff --git a/plugins/splunk-on-call/src/components/TriggerDialog/TriggerDialog.tsx b/plugins/splunk-on-call/src/components/TriggerDialog/TriggerDialog.tsx
index 82dd2da74d..dd8f0b1909 100644
--- a/plugins/splunk-on-call/src/components/TriggerDialog/TriggerDialog.tsx
+++ b/plugins/splunk-on-call/src/components/TriggerDialog/TriggerDialog.tsx
@@ -35,11 +35,11 @@ import {
import useAsyncFn from 'react-use/lib/useAsyncFn';
import { splunkOnCallApiRef } from '../../api';
import { Alert } from '@material-ui/lab';
-import { TriggerAlarmRequest } from '../../api/types';
+import { TriggerAlarmRequest } from '../../api';
import { useApi, alertApiRef } from '@backstage/core-plugin-api';
type Props = {
- team: string;
+ routingKey: string;
showDialog: boolean;
handleDialog: () => void;
onIncidentCreated: () => void;
@@ -76,7 +76,7 @@ const useStyles = makeStyles((theme: Theme) =>
);
export const TriggerDialog = ({
- team,
+ routingKey,
showDialog,
handleDialog,
onIncidentCreated: onIncidentCreated,
@@ -221,7 +221,7 @@ export const TriggerDialog = ({
id="details"
multiline
fullWidth
- rows="2"
+ minRows="2"
margin="normal"
label="Incident message"
variant="outlined"
@@ -242,7 +242,7 @@ export const TriggerDialog = ({
variant="contained"
onClick={() =>
handleTriggerAlarm({
- routingKey: team,
+ routingKey,
incidentType,
incidentDisplayName,
incidentMessage,
diff --git a/plugins/splunk-on-call/src/components/TriggerDialog/testUtils.ts b/plugins/splunk-on-call/src/components/TriggerDialog/testUtils.ts
new file mode 100644
index 0000000000..764ac94e2c
--- /dev/null
+++ b/plugins/splunk-on-call/src/components/TriggerDialog/testUtils.ts
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2022 The Backstage Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// eslint-disable-next-line import/no-extraneous-dependencies
+import {
+ act,
+ fireEvent,
+ Matcher,
+ MatcherOptions,
+} from '@testing-library/react';
+
+export async function expectTriggeredIncident(
+ routingKey: string,
+ getByTestId: (
+ id: Matcher,
+ options?: MatcherOptions | undefined,
+ ) => HTMLElement,
+ mockTriggerAlarmFn: any,
+): Promise {
+ const incidentType = getByTestId('trigger-incident-type');
+ const incidentId = getByTestId('trigger-incident-id');
+ const incidentDisplayName = getByTestId('trigger-incident-displayName');
+ const incidentMessage = getByTestId('trigger-incident-message');
+
+ await act(async () => {
+ fireEvent.change(incidentType, { target: { value: 'CRITICAL' } });
+ fireEvent.change(incidentId, { target: { value: 'incident-id' } });
+ fireEvent.change(incidentDisplayName, {
+ target: { value: 'incident-display-name' },
+ });
+ fireEvent.change(incidentMessage, {
+ target: { value: 'incident-message' },
+ });
+ });
+
+ // Trigger incident creation button
+ const triggerButton = getByTestId('trigger-button');
+ await act(async () => {
+ fireEvent.click(triggerButton);
+ });
+
+ expect(mockTriggerAlarmFn).toHaveBeenCalled();
+ expect(mockTriggerAlarmFn).toHaveBeenCalledWith({
+ incidentType: 'CRITICAL',
+ incidentId: 'incident-id',
+ routingKey: routingKey,
+ incidentDisplayName: 'incident-display-name',
+ incidentMessage: 'incident-message',
+ });
+}
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/README.md b/plugins/stack-overflow-backend/README.md
index acff784cc6..a35a6678cb 100644
--- a/plugins/stack-overflow-backend/README.md
+++ b/plugins/stack-overflow-backend/README.md
@@ -41,7 +41,7 @@ When you have your `packages/backend/src/plugins/search.ts` file ready to make m
```ts
indexBuilder.addCollator({
- defaultRefreshIntervalSeconds: 600,
+ schedule,
factory: StackOverflowQuestionsCollatorFactory.fromConfig(env.config, {
logger: env.logger,
requestParams: {
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 baea1ab42f..4e9bedff96 100644
--- a/plugins/techdocs-addons-test-utils/CHANGELOG.md
+++ b/plugins/techdocs-addons-test-utils/CHANGELOG.md
@@ -1,5 +1,28 @@
# @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
+
+- Updated dependencies
+ - @backstage/plugin-techdocs@1.4.0-next.1
+
## 1.0.6-next.0
### Patch Changes
diff --git a/plugins/techdocs-addons-test-utils/package.json b/plugins/techdocs-addons-test-utils/package.json
index a3da234606..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.0",
+ "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 9a6c681a82..3ed95372a4 100644
--- a/plugins/techdocs/CHANGELOG.md
+++ b/plugins/techdocs/CHANGELOG.md
@@ -1,5 +1,30 @@
# @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
+
+- 9e4d8e6198: Fix logic bug that broke techdocs-cli-embedded-app
+
## 1.4.0-next.0
### Minor Changes
diff --git a/plugins/techdocs/package.json b/plugins/techdocs/package.json
index 05b841fd0c..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.0",
+ "version": "1.4.0-next.2",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -76,9 +76,9 @@
"@types/dompurify": "^2.2.2",
"@types/event-source-polyfill": "^1.0.0",
"@types/node": "^16.11.26",
- "canvas": "^2.6.1",
+ "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-backend/src/service/VaultBuilder.ts b/plugins/vault-backend/src/service/VaultBuilder.ts
index 67260f45ca..b82a5802bb 100644
--- a/plugins/vault-backend/src/service/VaultBuilder.ts
+++ b/plugins/vault-backend/src/service/VaultBuilder.ts
@@ -20,6 +20,7 @@ import { Logger } from 'winston';
import express, { Router } from 'express';
import { VaultClient } from './vaultApi';
import { TaskRunner, PluginTaskScheduler } from '@backstage/backend-tasks';
+import { errorHandler } from '@backstage/backend-common';
/**
* Environment values needed by the VaultBuilder
@@ -145,6 +146,7 @@ export class VaultBuilder {
res.json({ items: secrets });
});
+ router.use(errorHandler());
return router;
}
}
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/check-type-dependencies.js b/scripts/check-type-dependencies.js
index ba362bd5ff..ebad9b6dfc 100755
--- a/scripts/check-type-dependencies.js
+++ b/scripts/check-type-dependencies.js
@@ -136,10 +136,21 @@ function findTypesPackage(dep, pkg) {
return undefined;
} catch {
try {
- // Finally check if it's just a .d.ts file
+ // Check if it's just a .d.ts file
require.resolve(`${dep}.d.ts`, { paths: [pkg.dir] });
return undefined;
} catch {
+ // And finally a naive lookup of the file directly, in case `require.resolve` fails us due to "exports"
+ if (fs.existsSync(resolvePath(pkg.dir, `node_modules/${dep}.d.ts`))) {
+ return undefined;
+ }
+ if (
+ fs.existsSync(
+ resolvePath(pkg.dir, `../../node_modules/${dep}.d.ts`),
+ )
+ ) {
+ return undefined;
+ }
throw mkErr('MissingDepError', `No types for ${dep}`, { dep });
}
}
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 be9a98e42a..b0789605a4 100644
--- a/storybook/yarn.lock
+++ b/storybook/yarn.lock
@@ -3107,137 +3107,95 @@ __metadata:
languageName: node
linkType: hard
-"@swc/core-android-arm-eabi@npm:1.3.9":
- version: 1.3.9
- resolution: "@swc/core-android-arm-eabi@npm:1.3.9"
- dependencies:
- "@swc/wasm": 1.2.122
- conditions: os=android & cpu=arm
- languageName: node
- linkType: hard
-
-"@swc/core-android-arm64@npm:1.3.9":
- version: 1.3.9
- resolution: "@swc/core-android-arm64@npm:1.3.9"
- dependencies:
- "@swc/wasm": 1.2.130
- conditions: os=android & cpu=arm64
- languageName: node
- linkType: hard
-
-"@swc/core-darwin-arm64@npm:1.3.9":
- version: 1.3.9
- resolution: "@swc/core-darwin-arm64@npm:1.3.9"
+"@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.9":
- version: 1.3.9
- resolution: "@swc/core-darwin-x64@npm:1.3.9"
+"@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-freebsd-x64@npm:1.3.9":
- version: 1.3.9
- resolution: "@swc/core-freebsd-x64@npm:1.3.9"
- dependencies:
- "@swc/wasm": 1.2.130
- conditions: os=freebsd & cpu=x64
- languageName: node
- linkType: hard
-
-"@swc/core-linux-arm-gnueabihf@npm:1.3.9":
- version: 1.3.9
- resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.9"
- dependencies:
- "@swc/wasm": 1.2.130
+"@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.9":
- version: 1.3.9
- resolution: "@swc/core-linux-arm64-gnu@npm:1.3.9"
+"@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.9":
- version: 1.3.9
- resolution: "@swc/core-linux-arm64-musl@npm:1.3.9"
+"@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.9":
- version: 1.3.9
- resolution: "@swc/core-linux-x64-gnu@npm:1.3.9"
+"@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.9":
- version: 1.3.9
- resolution: "@swc/core-linux-x64-musl@npm:1.3.9"
+"@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.9":
- version: 1.3.9
- resolution: "@swc/core-win32-arm64-msvc@npm:1.3.9"
- dependencies:
- "@swc/wasm": 1.2.130
+"@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.9":
- version: 1.3.9
- resolution: "@swc/core-win32-ia32-msvc@npm:1.3.9"
- dependencies:
- "@swc/wasm": 1.2.130
+"@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.9":
- version: 1.3.9
- resolution: "@swc/core-win32-x64-msvc@npm:1.3.9"
+"@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.9
- resolution: "@swc/core@npm:1.3.9"
+ version: 1.3.16
+ resolution: "@swc/core@npm:1.3.16"
dependencies:
- "@swc/core-android-arm-eabi": 1.3.9
- "@swc/core-android-arm64": 1.3.9
- "@swc/core-darwin-arm64": 1.3.9
- "@swc/core-darwin-x64": 1.3.9
- "@swc/core-freebsd-x64": 1.3.9
- "@swc/core-linux-arm-gnueabihf": 1.3.9
- "@swc/core-linux-arm64-gnu": 1.3.9
- "@swc/core-linux-arm64-musl": 1.3.9
- "@swc/core-linux-x64-gnu": 1.3.9
- "@swc/core-linux-x64-musl": 1.3.9
- "@swc/core-win32-arm64-msvc": 1.3.9
- "@swc/core-win32-ia32-msvc": 1.3.9
- "@swc/core-win32-x64-msvc": 1.3.9
+ "@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-android-arm-eabi":
- optional: true
- "@swc/core-android-arm64":
- optional: true
"@swc/core-darwin-arm64":
optional: true
"@swc/core-darwin-x64":
optional: true
- "@swc/core-freebsd-x64":
- optional: true
"@swc/core-linux-arm-gnueabihf":
optional: true
"@swc/core-linux-arm64-gnu":
@@ -3256,21 +3214,7 @@ __metadata:
optional: true
bin:
swcx: run_swcx.js
- checksum: 761918f1bca5d494eaaafd49720717e3b3071df5bc6ef8b298a778ba4e4d20bc5a78c939a0b1c98623f9fe23e535a16a359179b72390cd1f5cbc891ea53c22fa
- languageName: node
- linkType: hard
-
-"@swc/wasm@npm:1.2.122":
- version: 1.2.122
- resolution: "@swc/wasm@npm:1.2.122"
- checksum: 563345370c5ad18373d3b403590ab880fe52dcd8fc8c8601be263fcd9886520b28a7f4e46236cf49ca2b136c79d4ef50c960bc34b7cdc2068118b0d84dfca1f4
- languageName: node
- linkType: hard
-
-"@swc/wasm@npm:1.2.130":
- version: 1.2.130
- resolution: "@swc/wasm@npm:1.2.130"
- checksum: 02203bfef3e382c64cbbd63c138c8fdf61865e74d923b317e9d9e9f33f5a3f0a9533b5fdbc9505e76d78e864be04a82fc847eb987a1e47ccac5850146c858292
+ checksum: 4361252c928c487a02f526aecd8f3072b923244234c2701916944cf13c252b6d5ce2466caf3e0797d3e92e71a89d4a044f8577e51e8f7fe3af0fe30d94e94b13
languageName: node
linkType: hard
@@ -7930,14 +7874,14 @@ __metadata:
languageName: node
linkType: hard
-"loader-utils@npm:^1.1.0, loader-utils@npm:^1.2.3":
- version: 1.4.0
- resolution: "loader-utils@npm:1.4.0"
+"loader-utils@npm:^1.2.3":
+ 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
@@ -7952,6 +7896,17 @@ __metadata:
languageName: node
linkType: hard
+"loader-utils@npm:^2.0.3":
+ version: 2.0.4
+ resolution: "loader-utils@npm:2.0.4"
+ dependencies:
+ big.js: ^5.2.2
+ emojis-list: ^3.0.0
+ json5: ^2.1.2
+ checksum: a5281f5fff1eaa310ad5e1164095689443630f3411e927f95031ab4fb83b4a98f388185bb1fe949e8ab8d4247004336a625e9255c22122b815bb9a4c5d8fc3b7
+ languageName: node
+ linkType: hard
+
"locate-path@npm:^3.0.0":
version: 3.0.0
resolution: "locate-path@npm:3.0.0"
@@ -9812,25 +9767,25 @@ __metadata:
linkType: hard
"react-hot-loader@npm:^4.13.0":
- version: 4.13.0
- resolution: "react-hot-loader@npm:4.13.0"
+ version: 4.13.1
+ resolution: "react-hot-loader@npm:4.13.1"
dependencies:
fast-levenshtein: ^2.0.6
global: ^4.3.0
hoist-non-react-statics: ^3.3.0
- loader-utils: ^1.1.0
+ loader-utils: ^2.0.3
prop-types: ^15.6.1
react-lifecycles-compat: ^3.0.4
shallowequal: ^1.1.0
source-map: ^0.7.3
peerDependencies:
- "@types/react": "^15.0.0 || ^16.0.0 || ^17.0.0 "
- react: "^15.0.0 || ^16.0.0 || ^17.0.0 "
- react-dom: "^15.0.0 || ^16.0.0 || ^17.0.0 "
+ "@types/react": ^15.0.0 || ^16.0.0 || ^17.0.0
+ react: ^15.0.0 || ^16.0.0 || ^17.0.0
+ react-dom: ^15.0.0 || ^16.0.0 || ^17.0.0
peerDependenciesMeta:
"@types/react":
optional: true
- checksum: effdbf4644ce912ae20ad94be62083970c74b26a59fe24ed0024cf73190a5b3edf59650cb693bdd7b70791df8ab8530de273d73b895c4831a91da8a76683e3a3
+ checksum: f90890d5160dcb2bfae4022cba065d8e5c26b86f34c4604cbbdd39f5e4dfd82c05c317bb05ef3d4da2aa0be7e8e205c905daea1af40d3a7ef0d07c3d289da11c
languageName: node
linkType: hard
diff --git a/yarn.lock b/yarn.lock
index c42aac2eec..420a8e87c6 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,8 +3931,9 @@ __metadata:
"@backstage/integration": "workspace:^"
"@backstage/types": "workspace:^"
"@google-cloud/storage": ^6.0.0
- "@keyv/redis": ^2.2.3
- "@kubernetes/client-node": ^0.17.0
+ "@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
"@types/archiver": ^5.1.0
@@ -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
@@ -3209,7 +3993,7 @@ __metadata:
selfsigned: ^2.0.0
stoppable: ^1.1.0
supertest: ^6.1.3
- tar: ^6.1.2
+ tar: ^6.1.12
uuid: ^8.3.2
winston: ^3.2.1
yauzl: ^2.10.0
@@ -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
@@ -3422,7 +4206,7 @@ __metadata:
css-loader: ^6.5.1
del: ^6.0.0
diff: ^5.0.0
- esbuild: ^0.14.10
+ esbuild: ^0.15.0
esbuild-loader: ^2.18.0
eslint: ^8.6.0
eslint-config-prettier: ^8.3.0
@@ -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
@@ -3474,7 +4258,7 @@ __metadata:
style-loader: ^3.3.1
sucrase: ^3.20.2
swc-loader: ^0.2.3
- tar: ^6.1.2
+ tar: ^6.1.12
terser-webpack-plugin: ^5.1.3
ts-node: ^10.0.0
type-fest: ^2.0.0
@@ -3506,7 +4290,7 @@ __metadata:
"@types/node": ^16.11.26
chalk: ^4.0.0
commander: ^9.1.0
- jscodeshift: ^0.13.0
+ jscodeshift: ^0.14.0
jscodeshift-add-imports: ^1.0.10
ts-node: ^10.0.0
bin:
@@ -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,10 +5077,10 @@ __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.1.3
+ openid-client: ^5.2.1
passport: ^0.6.0
passport-auth0: ^1.4.3
passport-bitbucket-oauth2: ^0.1.2
@@ -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:^"
@@ -5485,12 +6275,12 @@ __metadata:
"@types/recharts": ^1.8.14
"@types/regression": ^2.0.0
"@types/yup": ^0.29.13
- canvas: ^2.6.1
+ canvas: ^2.10.2
classnames: ^2.2.6
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
@@ -6220,7 +7139,7 @@ __metadata:
"@backstage/plugin-auth-node": "workspace:^"
"@backstage/plugin-kubernetes-common": "workspace:^"
"@google-cloud/container": ^4.0.0
- "@kubernetes/client-node": ^0.17.0
+ "@kubernetes/client-node": 0.17.0
"@types/aws4": ^1.5.1
"@types/express": ^4.17.6
"@types/luxon": ^3.0.0
@@ -6249,7 +7168,7 @@ __metadata:
dependencies:
"@backstage/catalog-model": "workspace:^"
"@backstage/cli": "workspace:^"
- "@kubernetes/client-node": ^0.17.0
+ "@kubernetes/client-node": 0.17.0
languageName: unknown
linkType: soft
@@ -6268,7 +7187,7 @@ __metadata:
"@backstage/plugin-kubernetes-common": "workspace:^"
"@backstage/test-utils": "workspace:^"
"@backstage/theme": "workspace:^"
- "@kubernetes/client-node": ^0.17.0
+ "@kubernetes/client-node": 0.17.0
"@material-ui/core": ^4.12.2
"@material-ui/icons": ^4.9.1
"@material-ui/lab": 4.0.0-alpha.57
@@ -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,36 @@ __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
+ languageName: unknown
+ linkType: soft
+
+"@backstage/plugin-org-react@workspace:plugins/org-react":
+ version: 0.0.0-use.local
+ resolution: "@backstage/plugin-org-react@workspace:plugins/org-react"
+ dependencies:
+ "@backstage/catalog-client": "workspace:^"
+ "@backstage/catalog-model": "workspace:^"
+ "@backstage/cli": "workspace:^"
+ "@backstage/core-app-api": "workspace:^"
+ "@backstage/core-components": "workspace:^"
+ "@backstage/core-plugin-api": "workspace:^"
+ "@backstage/dev-utils": "workspace:^"
+ "@backstage/plugin-catalog-react": "workspace:^"
+ "@backstage/test-utils": "workspace:^"
+ "@backstage/theme": "workspace:^"
+ "@material-ui/core": ^4.9.13
+ "@material-ui/icons": ^4.9.1
+ "@material-ui/lab": ^4.0.0-alpha.57
+ "@testing-library/jest-dom": ^5.10.1
+ "@testing-library/react": ^12.1.3
+ "@testing-library/user-event": ^14.0.0
+ "@types/node": "*"
+ cross-fetch: ^3.1.5
+ msw: ^0.48.0
react-use: ^17.2.4
peerDependencies:
react: ^16.13.1 || ^17.0.0
@@ -6394,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
@@ -6430,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
@@ -6450,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
@@ -6482,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
@@ -6508,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
@@ -6540,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
@@ -6561,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
@@ -6627,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
@@ -6675,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
@@ -6703,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
@@ -6731,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
@@ -6763,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:
@@ -6790,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
@@ -6866,7 +7814,7 @@ __metadata:
command-exists: ^1.2.9
compression: ^1.7.4
cors: ^2.8.5
- esbuild: ^0.14.1
+ esbuild: ^0.15.0
express: ^4.17.1
express-promise-router: ^4.1.0
fs-extra: 10.1.0
@@ -6881,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
@@ -6939,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
@@ -6962,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
@@ -7142,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:
@@ -7178,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:
@@ -7208,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
@@ -7232,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
@@ -7262,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:
@@ -7294,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
@@ -7361,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:
@@ -7472,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:
@@ -7506,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:
@@ -7538,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:
@@ -7574,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
@@ -7608,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
@@ -7712,14 +8660,14 @@ __metadata:
"@types/dompurify": ^2.2.2
"@types/event-source-polyfill": ^1.0.0
"@types/node": ^16.11.26
- canvas: ^2.6.1
+ canvas: ^2.10.2
cross-fetch: ^3.1.5
dompurify: ^2.2.9
event-source-polyfill: 1.0.25
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:
@@ -7747,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
@@ -7776,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
@@ -7828,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:
@@ -7855,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
@@ -7886,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
@@ -7916,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:
@@ -7932,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
@@ -7955,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
@@ -8028,9 +8976,9 @@ __metadata:
languageName: node
linkType: hard
-"@changesets/apply-release-plan@npm:^6.1.1":
- version: 6.1.1
- resolution: "@changesets/apply-release-plan@npm:6.1.1"
+"@changesets/apply-release-plan@npm:^6.1.2":
+ version: 6.1.2
+ resolution: "@changesets/apply-release-plan@npm:6.1.2"
dependencies:
"@babel/runtime": ^7.10.4
"@changesets/config": ^2.2.0
@@ -8045,7 +8993,7 @@ __metadata:
prettier: ^2.7.1
resolve-from: ^5.0.0
semver: ^5.4.1
- checksum: 34da2d52eced00bc5f51c8e8ce16c0e487743219f057da2b3e6c6597bb2d50498f3996c779e4fc29b19d357c9b700d82310d723395ba09350b9a139c9e0e0d23
+ checksum: efe2cdc493cb2182140b73ff76e34ee7c90887bfa2f42b4ec07db0107ec94b9c0e95519912dafcf9eb530ad2414487fbd61ca6e6d5f853fe383db93856d0d362
languageName: node
linkType: hard
@@ -8073,11 +9021,11 @@ __metadata:
linkType: hard
"@changesets/cli@npm:^2.14.0":
- version: 2.25.0
- resolution: "@changesets/cli@npm:2.25.0"
+ version: 2.25.2
+ resolution: "@changesets/cli@npm:2.25.2"
dependencies:
"@babel/runtime": ^7.10.4
- "@changesets/apply-release-plan": ^6.1.1
+ "@changesets/apply-release-plan": ^6.1.2
"@changesets/assemble-release-plan": ^5.2.2
"@changesets/changelog-git": ^0.1.13
"@changesets/config": ^2.2.0
@@ -8089,7 +9037,7 @@ __metadata:
"@changesets/pre": ^1.0.13
"@changesets/read": ^0.5.8
"@changesets/types": ^5.2.0
- "@changesets/write": ^0.2.1
+ "@changesets/write": ^0.2.2
"@manypkg/get-packages": ^1.1.3
"@types/is-ci": ^3.0.0
"@types/semver": ^6.0.0
@@ -8111,7 +9059,7 @@ __metadata:
tty-table: ^4.1.5
bin:
changeset: bin.js
- checksum: 54439bdfa7ca115964482f6323e9475b5917d68c2e0752a272ed133b863fce51eeba86366d8740a275dc0b891af8e272602da69d04144f40e4bf3531f48fe8fb
+ checksum: 815c69cb6cee75ede88361582581d94a860d96335e7bab179481cd5e2bb1e60cc39662dccd2b2b87818e9c63a84ff9eb469ed27f13b6adf4401a699e49beb79c
languageName: node
linkType: hard
@@ -8250,16 +9198,16 @@ __metadata:
languageName: node
linkType: hard
-"@changesets/write@npm:^0.2.1":
- version: 0.2.1
- resolution: "@changesets/write@npm:0.2.1"
+"@changesets/write@npm:^0.2.2":
+ version: 0.2.2
+ resolution: "@changesets/write@npm:0.2.2"
dependencies:
"@babel/runtime": ^7.10.4
"@changesets/types": ^5.2.0
fs-extra: ^7.0.1
human-id: ^1.0.2
prettier: ^2.7.1
- checksum: 98b4d9c12fe13177860407557979d475361076a596103895440f52b2724f7004d6c98af39105fda0eaa52ceca8c0dc0ec9c8ab10eec7a0cb9bf83301f2ca48b3
+ checksum: e23fb4a88e12af32db59d2f1866380ec4a50e7fa55cb55d860619f0735c5078ed170f832125672bb007b7a0cced67d9304a1b81260a7224af6afe0e3957dc999
languageName: node
linkType: hard
@@ -8293,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
@@ -8302,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
@@ -8357,13 +9305,13 @@ __metadata:
linkType: hard
"@codemirror/view@npm:^6.0.0":
- version: 6.4.0
- resolution: "@codemirror/view@npm:6.4.0"
+ 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: 57ed7d9d51907f1ea549a2a158872fb7affa6cdff72e29e214f8437b7142ea2a2431ac3c780cbc0187dfff7cb5fd1055a45a887ea9b8c2a09d8430c60ebe9083
+ checksum: c79982563ad90adf1d7504b28bb1304a73f669c69634a1630b51521e4023b3630c15601daf2857683b34a86cac4ca24dc5b538a9d944616617f99c1a7da7faa6
languageName: node
linkType: hard
@@ -8538,6 +9486,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/android-arm@npm:0.15.13":
+ version: 0.15.13
+ resolution: "@esbuild/android-arm@npm:0.15.13"
+ conditions: os=android & cpu=arm
+ languageName: node
+ linkType: hard
+
"@esbuild/android-arm@npm:0.15.8":
version: 0.15.8
resolution: "@esbuild/android-arm@npm:0.15.8"
@@ -8547,9 +9502,9 @@ __metadata:
languageName: node
linkType: hard
-"@esbuild/linux-loong64@npm:0.14.54":
- version: 0.14.54
- resolution: "@esbuild/linux-loong64@npm:0.14.54"
+"@esbuild/linux-loong64@npm:0.15.13":
+ version: 0.15.13
+ resolution: "@esbuild/linux-loong64@npm:0.15.13"
conditions: os=linux & cpu=loong64
languageName: node
linkType: hard
@@ -8561,9 +9516,9 @@ __metadata:
languageName: node
linkType: hard
-"@eslint/eslintrc@npm:^1.3.2":
- version: 1.3.2
- resolution: "@eslint/eslintrc@npm:1.3.2"
+"@eslint/eslintrc@npm:^1.3.3":
+ version: 1.3.3
+ resolution: "@eslint/eslintrc@npm:1.3.3"
dependencies:
ajv: ^6.12.4
debug: ^4.3.2
@@ -8574,7 +9529,7 @@ __metadata:
js-yaml: ^4.1.0
minimatch: ^3.1.2
strip-json-comments: ^3.1.1
- checksum: 2074dca47d7e1c5c6323ff353f690f4b25d3ab53fe7d27337e2592d37a894cf60ca0e85ca66b50ff2db0bc7e630cc1e9c7347d65bb185b61416565584c38999c
+ checksum: f03e9d6727efd3e0719da2051ea80c0c73d20e28c171121527dbb868cd34232ca9c1d0525a66e517a404afea26624b1e47895b6a92474678418c2f50c9566694
languageName: node
linkType: hard
@@ -8697,8 +9652,8 @@ __metadata:
linkType: hard
"@google-cloud/storage@npm:^6.0.0":
- version: 6.5.3
- resolution: "@google-cloud/storage@npm:6.5.3"
+ version: 6.7.0
+ resolution: "@google-cloud/storage@npm:6.7.0"
dependencies:
"@google-cloud/paginator": ^3.0.7
"@google-cloud/projectify": ^3.0.0
@@ -8717,7 +9672,7 @@ __metadata:
retry-request: ^5.0.0
teeny-request: ^8.0.0
uuid: ^8.0.0
- checksum: 9b88a5bff4e8401dbd18223fe570882df632cbb0e515e7f3eca33dbea16568168b2c0397b02ad8030e6d114b6d73109283d17a49762f1833f077424bf90a676d
+ checksum: 269224b965eb6a4c0c47b5df7cc21a6110ded2596c649ea94737ad622410b10a91fc0a1b765667c7bb64e44a98dad35abc5d342173b13b10f174ab0ce211f434
languageName: node
linkType: hard
@@ -8755,21 +9710,21 @@ __metadata:
linkType: hard
"@graphql-codegen/cli@npm:^2.3.1":
- version: 2.13.7
- resolution: "@graphql-codegen/cli@npm:2.13.7"
+ 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.2
- "@graphql-codegen/plugin-helpers": ^2.6.2
+ "@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
"@graphql-tools/git-loader": ^7.2.1
"@graphql-tools/github-loader": ^7.3.6
"@graphql-tools/graphql-file-loader": ^7.5.0
"@graphql-tools/json-file-loader": ^7.4.1
- "@graphql-tools/load": ^7.7.1
+ "@graphql-tools/load": 7.8.0
"@graphql-tools/prisma-loader": ^7.2.7
"@graphql-tools/url-loader": ^7.13.2
"@graphql-tools/utils": ^8.9.0
@@ -8801,37 +9756,37 @@ __metadata:
graphql-code-generator: cjs/bin.js
graphql-codegen: cjs/bin.js
graphql-codegen-esm: esm/bin.js
- checksum: c025e311c072c1d992451f27625c863eef1236e5f01e2aeb6f00e67a60e99c7812a13481481a8fc6ea2967fffd77433d582f10365244d677608fdc7aa13bbe29
+ checksum: 367d4687e1d4bf44f0a7f3cb4e71656774f006512883a51ceae905495b2e76819e6b49dfe63e3effe59abb990a4c17bb985878a4592bf2ff959dc822723c1370
languageName: node
linkType: hard
-"@graphql-codegen/core@npm:2.6.2":
- version: 2.6.2
- resolution: "@graphql-codegen/core@npm:2.6.2"
+"@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.6.2
+ "@graphql-codegen/plugin-helpers": ^2.7.2
"@graphql-tools/schema": ^9.0.0
- "@graphql-tools/utils": ^8.8.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: 3d078e9caa11baf7ceaa4d67b29a6be32f50a183c1fa6f228a3ade62902b9b91cdea2c94d99adbadf10ec38a7f2df9f16cd366dc7b4febf95336e3b4a7eb9160
+ checksum: 4a506dfb7dad577510b0358444ad5c5080459c00e1740099212d28c08fc4f02824014602172b95a61c6092cc97b3838fafd02b3e2eadf99dd9b6fa390464935a
languageName: node
linkType: hard
"@graphql-codegen/graphql-modules-preset@npm:^2.3.2":
- version: 2.5.4
- resolution: "@graphql-codegen/graphql-modules-preset@npm:2.5.4"
+ version: 2.5.5
+ resolution: "@graphql-codegen/graphql-modules-preset@npm:2.5.5"
dependencies:
- "@graphql-codegen/plugin-helpers": ^2.6.2
- "@graphql-codegen/visitor-plugin-common": 2.13.0
+ "@graphql-codegen/plugin-helpers": ^2.7.2
+ "@graphql-codegen/visitor-plugin-common": 2.13.1
"@graphql-tools/utils": ^8.8.0
change-case-all: 1.0.14
parse-filepath: ^1.0.2
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: d3e9b90c475c1a093149038b0dea448ebbb25bf9cf853d1947427bed741d739f140daca8f3861da63bfee6f6958c25f1b1081ce4365c7db1efe6527bb9b9c1dc
+ checksum: d499001af49d0a829c6adcbc211d252e8d5a42ba1635c32265ad99d187666425150c99815d48e591ca66e811a2b09860a5f59ba02484a3a3f0dcf4dcba8a6fb8
languageName: node
linkType: hard
@@ -8851,6 +9806,22 @@ __metadata:
languageName: node
linkType: hard
+"@graphql-codegen/plugin-helpers@npm:^2.7.2":
+ version: 2.7.2
+ resolution: "@graphql-codegen/plugin-helpers@npm:2.7.2"
+ dependencies:
+ "@graphql-tools/utils": ^8.8.0
+ change-case-all: 1.0.14
+ common-tags: 1.8.2
+ import-from: 4.0.0
+ lodash: ~4.17.0
+ 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: 66e0d507ad5db60b67092ebf7632d464d56ab446ac8fd87c293e00d9016944912d8cf9199e3e026b0a9247a50f50c4118a44f49e13675db64211652cd6259b05
+ languageName: node
+ linkType: hard
+
"@graphql-codegen/schema-ast@npm:^2.5.1":
version: 2.5.1
resolution: "@graphql-codegen/schema-ast@npm:2.5.1"
@@ -8865,56 +9836,41 @@ __metadata:
linkType: hard
"@graphql-codegen/typescript-resolvers@npm:^2.4.3":
- version: 2.7.5
- resolution: "@graphql-codegen/typescript-resolvers@npm:2.7.5"
+ version: 2.7.6
+ resolution: "@graphql-codegen/typescript-resolvers@npm:2.7.6"
dependencies:
- "@graphql-codegen/plugin-helpers": ^2.6.2
- "@graphql-codegen/typescript": ^2.7.5
- "@graphql-codegen/visitor-plugin-common": 2.13.0
+ "@graphql-codegen/plugin-helpers": ^2.7.2
+ "@graphql-codegen/typescript": ^2.8.1
+ "@graphql-codegen/visitor-plugin-common": 2.13.1
"@graphql-tools/utils": ^8.8.0
auto-bind: ~4.0.0
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: 7384bbb42bdf43157b6133812c2e84bb162ab5b52add05bed86a4f3c149bf3ab1f178bb5a7d51c661ba354296b2fa9e4983ee42b373c3815fdc6ee391a9e5307
+ checksum: f552f74aa264c0f9024834d6d1c126f9f1a69dccf7278525c7609ad1820daf87607447f30351506fe3728a855690928ba7775edbbbff0fee610a2ce02913a98e
languageName: node
linkType: hard
-"@graphql-codegen/typescript@npm:^2.4.2":
- version: 2.8.0
- resolution: "@graphql-codegen/typescript@npm:2.8.0"
+"@graphql-codegen/typescript@npm:^2.4.2, @graphql-codegen/typescript@npm:^2.8.1":
+ version: 2.8.1
+ resolution: "@graphql-codegen/typescript@npm:2.8.1"
dependencies:
- "@graphql-codegen/plugin-helpers": ^2.6.2
+ "@graphql-codegen/plugin-helpers": ^2.7.2
"@graphql-codegen/schema-ast": ^2.5.1
- "@graphql-codegen/visitor-plugin-common": 2.13.0
+ "@graphql-codegen/visitor-plugin-common": 2.13.1
auto-bind: ~4.0.0
tslib: ~2.4.0
peerDependencies:
graphql: ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0
- checksum: 45550613384c930d046f1ca8bfd73c25e1219fc45315b1885017e08577a517547d5af86908162f61eee0670689df5c926b5e394b318d5c3d94ee5eef5ac1bc52
+ checksum: 2b5466190e385c557eed6210b861fb9e632fb61b90bd0f97ff983f359c0ad8106228667c9ff2201842100417a07cfaffa91794ef03058a151df256d733363fa2
languageName: node
linkType: hard
-"@graphql-codegen/typescript@npm:^2.7.5":
- version: 2.7.5
- resolution: "@graphql-codegen/typescript@npm:2.7.5"
+"@graphql-codegen/visitor-plugin-common@npm:2.13.1":
+ version: 2.13.1
+ resolution: "@graphql-codegen/visitor-plugin-common@npm:2.13.1"
dependencies:
- "@graphql-codegen/plugin-helpers": ^2.6.2
- "@graphql-codegen/schema-ast": ^2.5.1
- "@graphql-codegen/visitor-plugin-common": 2.13.0
- auto-bind: ~4.0.0
- tslib: ~2.4.0
- peerDependencies:
- graphql: ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0
- checksum: 0eb51d2bb826284cfed29fdaee0fc57694932627f0146394711d3f012377bccb19592270f6c04f775ec06ec87e1a05a0c85064ca186ea0e50a306ec058674fad
- languageName: node
- linkType: hard
-
-"@graphql-codegen/visitor-plugin-common@npm:2.13.0":
- version: 2.13.0
- resolution: "@graphql-codegen/visitor-plugin-common@npm:2.13.0"
- dependencies:
- "@graphql-codegen/plugin-helpers": ^2.6.2
+ "@graphql-codegen/plugin-helpers": ^2.7.2
"@graphql-tools/optimize": ^1.3.0
"@graphql-tools/relay-operation-optimizer": ^6.5.0
"@graphql-tools/utils": ^8.8.0
@@ -8926,7 +9882,7 @@ __metadata:
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: 1d7491d626059529faca2eda5466aa8b05bf2cc9a768175043461d0ec4793b4cbda2fb762ef44e6c8d094f951960569f2adf177af74156f4a74f33c6d5ae77bf
+ checksum: 0c329aa6e435602f2f6c1569ec2091b7850f58cc5dca7ac763c38c82588545ec1110c1de587f5f3949b11ff96f94401d1e63e329607d78424583b276fd08f1ae
languageName: node
linkType: hard
@@ -9180,6 +10136,20 @@ __metadata:
languageName: node
linkType: hard
+"@graphql-tools/load@npm:7.8.0":
+ version: 7.8.0
+ resolution: "@graphql-tools/load@npm:7.8.0"
+ dependencies:
+ "@graphql-tools/schema": 9.0.4
+ "@graphql-tools/utils": 8.12.0
+ p-limit: 3.1.0
+ tslib: ^2.4.0
+ peerDependencies:
+ graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
+ checksum: 24ade442e13429d087ceac905cef4e6a14d0961e2b231adf91180a4d674de08ac6de66e6103c3e118b6ccf24065492bb69f5c99cb336e71a579ab382c8574791
+ languageName: node
+ linkType: hard
+
"@graphql-tools/load@npm:^7.5.5":
version: 7.7.0
resolution: "@graphql-tools/load@npm:7.7.0"
@@ -9194,20 +10164,6 @@ __metadata:
languageName: node
linkType: hard
-"@graphql-tools/load@npm:^7.7.1":
- version: 7.7.1
- resolution: "@graphql-tools/load@npm:7.7.1"
- dependencies:
- "@graphql-tools/schema": 8.5.1
- "@graphql-tools/utils": 8.9.0
- p-limit: 3.1.0
- tslib: ^2.4.0
- peerDependencies:
- graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
- checksum: 4abaab346dab9547f547fe619476e5de54698121174f579f3473f2d5678891c249482a3e56f9b748400d5062c9bd3b5d5d5e56885555e5a3422cafa2afd6022e
- languageName: node
- linkType: hard
-
"@graphql-tools/merge@npm:8.2.10":
version: 8.2.10
resolution: "@graphql-tools/merge@npm:8.2.10"
@@ -9244,6 +10200,18 @@ __metadata:
languageName: node
linkType: hard
+"@graphql-tools/merge@npm:8.3.11":
+ version: 8.3.11
+ resolution: "@graphql-tools/merge@npm:8.3.11"
+ dependencies:
+ "@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: 3cd16577f1ea1bcc389d232fa620adc0fefc91a6b42b48e7bb5e7bb67b67d206d409a9a8d60cac4d8cd5f0f1c5353369f7c5eb4054b44ce2277545e1fd1de17f
+ languageName: node
+ linkType: hard
+
"@graphql-tools/merge@npm:8.3.6":
version: 8.3.6
resolution: "@graphql-tools/merge@npm:8.3.6"
@@ -9365,7 +10333,7 @@ __metadata:
languageName: node
linkType: hard
-"@graphql-tools/schema@npm:^9.0.0":
+"@graphql-tools/schema@npm:9.0.4":
version: 9.0.4
resolution: "@graphql-tools/schema@npm:9.0.4"
dependencies:
@@ -9379,6 +10347,20 @@ __metadata:
languageName: node
linkType: hard
+"@graphql-tools/schema@npm:^9.0.0":
+ version: 9.0.9
+ resolution: "@graphql-tools/schema@npm:9.0.9"
+ dependencies:
+ "@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: 23620a993eff57723302315100d947b81664d6a1e00010ff293b3649f51ab423946d73920cce0ce822b7f7f42b99ea23240902ff47df3d252639613c0df7b971
+ languageName: node
+ linkType: hard
+
"@graphql-tools/url-loader@npm:7.13.2, @graphql-tools/url-loader@npm:^7.13.2":
version: 7.13.2
resolution: "@graphql-tools/url-loader@npm:7.13.2"
@@ -9473,6 +10455,28 @@ __metadata:
languageName: node
linkType: hard
+"@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: dcf08df3bd1715e25e3b80bf2dd332376239ebcd2a9b93f4d6b72a7bd3feffe2207b9683bb8fcaed9d0d1286f701d0686fe99ac803b91c0df54509b869c0554d
+ languageName: node
+ linkType: hard
+
+"@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: 5a5120417c00b0f8a834b69dca9b7496022f8b1ed3719c2cf7de8253ff639ecc0f4a8e2bcaf0193ce44bd59431098180e94bdd96406e9f260e058b16c0e26975
+ languageName: node
+ linkType: hard
+
"@graphql-tools/wrap@npm:8.5.0":
version: 8.5.0
resolution: "@graphql-tools/wrap@npm:8.5.0"
@@ -9593,21 +10597,14 @@ __metadata:
languageName: node
linkType: hard
-"@humanwhocodes/config-array@npm:^0.10.4":
- version: 0.10.4
- resolution: "@humanwhocodes/config-array@npm:0.10.4"
+"@humanwhocodes/config-array@npm:^0.11.6":
+ version: 0.11.7
+ resolution: "@humanwhocodes/config-array@npm:0.11.7"
dependencies:
"@humanwhocodes/object-schema": ^1.2.1
debug: ^4.1.1
- minimatch: ^3.0.4
- checksum: d480e5d57e6d787565b6cff78e27c3d1b380692d4ffb0ada7d7f5957a56c9032f034da05a3e443065dbd0671ebf4d859036ced34e96b325bbc1badbae3c05300
- languageName: node
- linkType: hard
-
-"@humanwhocodes/gitignore-to-minimatch@npm:^1.0.2":
- version: 1.0.2
- resolution: "@humanwhocodes/gitignore-to-minimatch@npm:1.0.2"
- checksum: aba5c40c9e3770ed73a558b0bfb53323842abfc2ce58c91d7e8b1073995598e6374456d38767be24ab6176915f0a8d8b23eaae5c85e2b488c0dccca6d795e2ad
+ minimatch: ^3.0.5
+ checksum: cf506dc45d9488af7fbf108ea6ac2151ba1a25e6d2b94b9b4fc36d2c1e4099b89ff560296dbfa13947e44604d4ca4a90d97a4fb167370bf8dd01a6ca2b6d83ac
languageName: node
linkType: hard
@@ -9680,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
@@ -9699,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
@@ -9721,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
@@ -10584,16 +11581,26 @@ __metadata:
languageName: node
linkType: hard
-"@keyv/redis@npm:^2.2.3":
- version: 2.5.2
- resolution: "@keyv/redis@npm:2.5.2"
+"@keyv/memcache@npm:^1.3.5":
+ version: 1.3.5
+ resolution: "@keyv/memcache@npm:1.3.5"
dependencies:
- ioredis: ^5.2.3
- checksum: 2439e5097c6d4bf14e316b7a19d532287d43c5860f0614569f125a3c0a0a8c322610ed26b86b941b9aa9243ebf1e265c1d3f99a43da42d2150d02fc8fd2d94dd
+ json-buffer: ^3.0.1
+ memjs: ^1.3.0
+ checksum: c457863aeff1c5886c273eafa5fd79a4287cae1d9d3721b6ce5aa699033428ec8930db044224a6ab63d951cdac2408850737d0adc65f0a502bf04cd7dbe0d15e
languageName: node
linkType: hard
-"@kubernetes/client-node@npm:^0.17.0":
+"@keyv/redis@npm:^2.5.3":
+ version: 2.5.3
+ resolution: "@keyv/redis@npm:2.5.3"
+ dependencies:
+ ioredis: ^5.2.4
+ checksum: db6be54624320f5d03856985fee5151601fa278d63ef98feac12f89188fbf86b972e7f5ca3ece0d6137c81038b1eb3c42805beaf51c4c963cca35c2b7d68be92
+ languageName: node
+ linkType: hard
+
+"@kubernetes/client-node@npm:0.17.0":
version: 0.17.0
resolution: "@kubernetes/client-node@npm:0.17.0"
dependencies:
@@ -11161,6 +12168,16 @@ __metadata:
languageName: node
linkType: hard
+"@nodelib/fs.scandir@npm:2.1.5":
+ version: 2.1.5
+ resolution: "@nodelib/fs.scandir@npm:2.1.5"
+ dependencies:
+ "@nodelib/fs.stat": 2.0.5
+ run-parallel: ^1.1.9
+ checksum: a970d595bd23c66c880e0ef1817791432dbb7acbb8d44b7e7d0e7a22f4521260d4a83f7f9fd61d44fda4610105577f8f58a60718105fb38352baed612fd79e59
+ languageName: node
+ linkType: hard
+
"@nodelib/fs.stat@npm:2.0.3, @nodelib/fs.stat@npm:^2.0.2":
version: 2.0.3
resolution: "@nodelib/fs.stat@npm:2.0.3"
@@ -11168,6 +12185,13 @@ __metadata:
languageName: node
linkType: hard
+"@nodelib/fs.stat@npm:2.0.5":
+ version: 2.0.5
+ resolution: "@nodelib/fs.stat@npm:2.0.5"
+ checksum: 012480b5ca9d97bff9261571dbbec7bbc6033f69cc92908bc1ecfad0792361a5a1994bc48674b9ef76419d056a03efadfce5a6cf6dbc0a36559571a7a483f6f0
+ languageName: node
+ linkType: hard
+
"@nodelib/fs.walk@npm:^1.2.3":
version: 1.2.4
resolution: "@nodelib/fs.walk@npm:1.2.4"
@@ -11178,6 +12202,16 @@ __metadata:
languageName: node
linkType: hard
+"@nodelib/fs.walk@npm:^1.2.8":
+ version: 1.2.8
+ resolution: "@nodelib/fs.walk@npm:1.2.8"
+ dependencies:
+ "@nodelib/fs.scandir": 2.1.5
+ fastq: ^1.6.0
+ checksum: 190c643f156d8f8f277bf2a6078af1ffde1fd43f498f187c2db24d35b4b4b5785c02c7dc52e356497b9a1b65b13edc996de08de0b961c32844364da02986dc53
+ languageName: node
+ linkType: hard
+
"@npmcli/arborist@npm:^4.0.4":
version: 4.3.1
resolution: "@npmcli/arborist@npm:4.3.1"
@@ -11570,13 +12604,13 @@ __metadata:
linkType: hard
"@octokit/graphql@npm:^5.0.0":
- version: 5.0.1
- resolution: "@octokit/graphql@npm:5.0.1"
+ version: 5.0.4
+ resolution: "@octokit/graphql@npm:5.0.4"
dependencies:
"@octokit/request": ^6.0.0
- "@octokit/types": ^7.0.0
+ "@octokit/types": ^8.0.0
universal-user-agent: ^6.0.0
- checksum: 310549c2d7966adb46428e943cd99cb766519819bd4945d8349d3ec0642e4ee39d9194e1b0a87a5404951c04c247fafb4a8456ed4c839c64bfb4042aa4a6812c
+ checksum: 8cf65cf7e6608cf3cbc96a2fa902172b4d5dc30e88ee0bae3711bf467a25b828b10cce1aaabb7f82a7580bfbcf7028b91d1dd1a894940945e38ca2deb6509754
languageName: node
linkType: hard
@@ -11970,14 +13004,15 @@ __metadata:
linkType: hard
"@opensearch-project/opensearch@npm:^2.0.0":
- version: 2.0.0
- resolution: "@opensearch-project/opensearch@npm:2.0.0"
+ version: 2.1.0
+ resolution: "@opensearch-project/opensearch@npm:2.1.0"
dependencies:
+ aws4: ^1.11.0
debug: ^4.3.1
hpagent: ^0.1.1
ms: ^2.1.3
secure-json-parse: ^2.4.0
- checksum: 7e0e7ae6ac8b6789f7fac59d66ef8afb960cdff46a5d201d9fb447270b808a5e0fd725b75e5fc647974b1b86e5a048e1e9d79aed04b11a424e14ec30079f2e44
+ checksum: 900b90f35d5b960fe60979168e21e9e5b6089a8e3dd9341b5d86c7f7aa7671cbfd937fbec311a6cfe195c113db755e699d3678ee0cbf454e9a9de1189d8cc935
languageName: node
linkType: hard
@@ -12046,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
@@ -12055,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:
@@ -12080,7 +13115,7 @@ __metadata:
optional: true
webpack-plugin-serve:
optional: true
- checksum: 48d8b2813dfba7d482e58a2b0161b79e3a5d608603f1a3c34d709ecc2e6e08f8b14f79934c57849d06f153eb327f18e3d8e1539f978e40ca91539c342f27b8ae
+ checksum: 446c0add9ecf17ed9911bf310bf22ab64f4b3d0ce334e68a3fcac5efee782ef4d7b6260997efaf720c7a2ea39086db89629e4aa07fb18558387d8dc8f0f31da2
languageName: node
linkType: hard
@@ -12180,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
@@ -12191,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
@@ -12214,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
@@ -12239,9 +13274,9 @@ __metadata:
languageName: node
linkType: hard
-"@rjsf/utils@npm:^5.0.0-beta.10":
- version: 5.0.0-beta.11
- resolution: "@rjsf/utils@npm:5.0.0-beta.11"
+"@rjsf/utils@npm:^5.0.0-beta.12":
+ version: 5.0.0-beta.12
+ resolution: "@rjsf/utils@npm:5.0.0-beta.12"
dependencies:
json-schema-merge-allof: ^0.8.1
jsonpointer: ^5.0.1
@@ -12250,13 +13285,13 @@ __metadata:
react-is: ^18.2.0
peerDependencies:
react: ^16.14.0 || >=17
- checksum: 4e77616023b5cf193e1631a4d5fb8d54122d9f48e30ce2fcb1b22f057e2dcf37aae174f25f1afddb664b0114e461f9d738fa282995b07e9e3eb30f7469d77145
+ checksum: b9698a2238dd5d3c79c13b84d92587825005938cd449680204903463b6fc6f63165fb715ea1e50a94e6764aa405be2b2ac2e6aad8bc68cd50623f065fd6f979a
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
@@ -12264,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
@@ -12293,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
@@ -12316,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
@@ -12445,17 +13480,7 @@ __metadata:
languageName: node
linkType: hard
-"@rollup/pluginutils@npm:^4.1.1":
- version: 4.1.1
- resolution: "@rollup/pluginutils@npm:4.1.1"
- dependencies:
- estree-walker: ^2.0.1
- picomatch: ^2.2.2
- checksum: 405f681c7d32661980aa3caa928ff22e1c06f0e081db1550e6ab9c179dc9d3d8d63c05dcc7338fe65ab3f856a56c465696a51300b83e98171956fcb141106e39
- 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:
@@ -12570,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:
@@ -12822,137 +13856,95 @@ __metadata:
languageName: node
linkType: hard
-"@swc/core-android-arm-eabi@npm:1.3.9":
- version: 1.3.9
- resolution: "@swc/core-android-arm-eabi@npm:1.3.9"
- dependencies:
- "@swc/wasm": 1.2.122
- conditions: os=android & cpu=arm
- languageName: node
- linkType: hard
-
-"@swc/core-android-arm64@npm:1.3.9":
- version: 1.3.9
- resolution: "@swc/core-android-arm64@npm:1.3.9"
- dependencies:
- "@swc/wasm": 1.2.130
- conditions: os=android & cpu=arm64
- languageName: node
- linkType: hard
-
-"@swc/core-darwin-arm64@npm:1.3.9":
- version: 1.3.9
- resolution: "@swc/core-darwin-arm64@npm:1.3.9"
+"@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.9":
- version: 1.3.9
- resolution: "@swc/core-darwin-x64@npm:1.3.9"
+"@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-freebsd-x64@npm:1.3.9":
- version: 1.3.9
- resolution: "@swc/core-freebsd-x64@npm:1.3.9"
- dependencies:
- "@swc/wasm": 1.2.130
- conditions: os=freebsd & cpu=x64
- languageName: node
- linkType: hard
-
-"@swc/core-linux-arm-gnueabihf@npm:1.3.9":
- version: 1.3.9
- resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.9"
- dependencies:
- "@swc/wasm": 1.2.130
+"@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.9":
- version: 1.3.9
- resolution: "@swc/core-linux-arm64-gnu@npm:1.3.9"
+"@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.9":
- version: 1.3.9
- resolution: "@swc/core-linux-arm64-musl@npm:1.3.9"
+"@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.9":
- version: 1.3.9
- resolution: "@swc/core-linux-x64-gnu@npm:1.3.9"
+"@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.9":
- version: 1.3.9
- resolution: "@swc/core-linux-x64-musl@npm:1.3.9"
+"@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.9":
- version: 1.3.9
- resolution: "@swc/core-win32-arm64-msvc@npm:1.3.9"
- dependencies:
- "@swc/wasm": 1.2.130
+"@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.9":
- version: 1.3.9
- resolution: "@swc/core-win32-ia32-msvc@npm:1.3.9"
- dependencies:
- "@swc/wasm": 1.2.130
+"@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.9":
- version: 1.3.9
- resolution: "@swc/core-win32-x64-msvc@npm:1.3.9"
+"@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.9
- resolution: "@swc/core@npm:1.3.9"
+ version: 1.3.16
+ resolution: "@swc/core@npm:1.3.16"
dependencies:
- "@swc/core-android-arm-eabi": 1.3.9
- "@swc/core-android-arm64": 1.3.9
- "@swc/core-darwin-arm64": 1.3.9
- "@swc/core-darwin-x64": 1.3.9
- "@swc/core-freebsd-x64": 1.3.9
- "@swc/core-linux-arm-gnueabihf": 1.3.9
- "@swc/core-linux-arm64-gnu": 1.3.9
- "@swc/core-linux-arm64-musl": 1.3.9
- "@swc/core-linux-x64-gnu": 1.3.9
- "@swc/core-linux-x64-musl": 1.3.9
- "@swc/core-win32-arm64-msvc": 1.3.9
- "@swc/core-win32-ia32-msvc": 1.3.9
- "@swc/core-win32-x64-msvc": 1.3.9
+ "@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-android-arm-eabi":
- optional: true
- "@swc/core-android-arm64":
- optional: true
"@swc/core-darwin-arm64":
optional: true
"@swc/core-darwin-x64":
optional: true
- "@swc/core-freebsd-x64":
- optional: true
"@swc/core-linux-arm-gnueabihf":
optional: true
"@swc/core-linux-arm64-gnu":
@@ -12971,7 +13963,7 @@ __metadata:
optional: true
bin:
swcx: run_swcx.js
- checksum: 761918f1bca5d494eaaafd49720717e3b3071df5bc6ef8b298a778ba4e4d20bc5a78c939a0b1c98623f9fe23e535a16a359179b72390cd1f5cbc891ea53c22fa
+ checksum: 4361252c928c487a02f526aecd8f3072b923244234c2701916944cf13c252b6d5ce2466caf3e0797d3e92e71a89d4a044f8577e51e8f7fe3af0fe30d94e94b13
languageName: node
linkType: hard
@@ -12996,20 +13988,6 @@ __metadata:
languageName: node
linkType: hard
-"@swc/wasm@npm:1.2.122":
- version: 1.2.122
- resolution: "@swc/wasm@npm:1.2.122"
- checksum: 563345370c5ad18373d3b403590ab880fe52dcd8fc8c8601be263fcd9886520b28a7f4e46236cf49ca2b136c79d4ef50c960bc34b7cdc2068118b0d84dfca1f4
- languageName: node
- linkType: hard
-
-"@swc/wasm@npm:1.2.130":
- version: 1.2.130
- resolution: "@swc/wasm@npm:1.2.130"
- checksum: 02203bfef3e382c64cbbd63c138c8fdf61865e74d923b317e9d9e9f33f5a3f0a9533b5fdbc9505e76d78e864be04a82fc847eb987a1e47ccac5850146c858292
- languageName: node
- linkType: hard
-
"@szmarczak/http-timer@npm:^4.0.5":
version: 4.0.5
resolution: "@szmarczak/http-timer@npm:4.0.5"
@@ -13019,18 +13997,18 @@ __metadata:
languageName: node
linkType: hard
-"@tanstack/query-core@npm:4.13.0":
- version: 4.13.0
- resolution: "@tanstack/query-core@npm:4.13.0"
- checksum: 11cb95be4dc6e1ba3f0f4eb04c255eab7fa5eca3441d6e698e2c6d03c84c03efaf34d475594e259593d76f584af0c0e830c7d868a682d6dc0f61d1a439728d12
+"@tanstack/query-core@npm:4.14.5":
+ version: 4.14.5
+ resolution: "@tanstack/query-core@npm:4.14.5"
+ checksum: 25af0f4999668cd66a4a54c2d2d64dd7002f4852fb901d1d1d64908da4ea43d63e53e512b536987a789039713ffc6ae4ffa2d41cfab676b01704f4937be18a04
languageName: node
linkType: hard
"@tanstack/react-query@npm:^4.1.3":
- version: 4.13.0
- resolution: "@tanstack/react-query@npm:4.13.0"
+ version: 4.14.6
+ resolution: "@tanstack/react-query@npm:4.14.6"
dependencies:
- "@tanstack/query-core": 4.13.0
+ "@tanstack/query-core": 4.14.5
use-sync-external-store: ^1.2.0
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0
@@ -13041,7 +14019,7 @@ __metadata:
optional: true
react-native:
optional: true
- checksum: e538b585e4c2b4a8ff84c17509f4ce226e18e3e862553b6a9ca90e29c200db4ec7ab4f400f19ef4846a76c51babe0db120c54779054805fbecdcd29b369caf0e
+ checksum: 38e293616aa04ccfe2fec47315c5b98f0b157ee6548b4dbb6a8ca01c90de113e437f5effbc82884f2d860bde54eeb07335e9ed4e233543c7039f717d9855ab9e
languageName: node
linkType: hard
@@ -13699,12 +14677,12 @@ __metadata:
linkType: hard
"@types/dockerode@npm:^3.3.0":
- version: 3.3.10
- resolution: "@types/dockerode@npm:3.3.10"
+ version: 3.3.13
+ resolution: "@types/dockerode@npm:3.3.13"
dependencies:
"@types/docker-modem": "*"
"@types/node": "*"
- checksum: ef2231adebbdc1876a00fd16a51963ed2ea05a2305031467420c753f77a27a6f2a47617e2f4a42702be84c88046a5a5f6dfd471e3579f11f21166f539a3d2373
+ checksum: dbcf3e33f5d8b731a1540d8b72c91d12583eb87d47adf8defb71f8bc1b328a26a035c66068255929ef99a7906da53ac6e4be76099e8fa7e9720c134b1ab3e153
languageName: node
linkType: hard
@@ -13954,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
@@ -14143,11 +15121,11 @@ __metadata:
linkType: hard
"@types/ldapjs@npm:^2.2.0":
- version: 2.2.4
- resolution: "@types/ldapjs@npm:2.2.4"
+ version: 2.2.5
+ resolution: "@types/ldapjs@npm:2.2.5"
dependencies:
"@types/node": "*"
- checksum: 3f240809927e1292380e5977579d7edffb6e5e41b35510c7091b51da19e7387d4ebff0f254c0b145f3cf5d5485b6bb39c77335d857d092e6f4e9ce5a6682a872
+ checksum: 779e462f118f8a6643b7f49d35646e4dae339ff1c6290198950327a736a79bc03beca882e1356ede4c8d54f6dc19bf544f0d23b09279558d69222a93bacd459c
languageName: node
linkType: hard
@@ -14194,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
@@ -14269,11 +15247,11 @@ __metadata:
linkType: hard
"@types/minipass@npm:*":
- version: 3.3.5
- resolution: "@types/minipass@npm:3.3.5"
+ version: 3.1.2
+ resolution: "@types/minipass@npm:3.1.2"
dependencies:
- minipass: "*"
- checksum: 160f4ae5416697c947e0c0ee1225fe25973acf73a30d01bdf202447f12bd32ba3ea33d2fc4f2517a038dc408022a5aff5f7a1d92da0157a9b04276d1b0209550
+ "@types/node": "*"
+ checksum: 0d01e11b5b959625385a482ad29ea16352be42506b459555b0f77fd82235e9c540946cc9c05a73fed1ae30b132914baaa4ccf257ed2cad20bc9773f0a06f4bac
languageName: node
linkType: hard
@@ -14332,9 +15310,9 @@ __metadata:
linkType: hard
"@types/node@npm:*, @types/node@npm:>=12.12.47, @types/node@npm:>=13.7.0":
- version: 17.0.25
- resolution: "@types/node@npm:17.0.25"
- checksum: 6a820bd624e69ea772f52a6cdb326484eff5829443dc981939373929ade109f58c21698b9f0a831bd6ceea799e722a75dc49c5fa7a6bc32a81e1cbdfc6507b64
+ version: 18.11.9
+ resolution: "@types/node@npm:18.11.9"
+ checksum: cc0aae109e9b7adefc32eecb838d6fad931663bb06484b5e9cbbbf74865c721b03d16fd8d74ad90e31dbe093d956a7c2c306ba5429ba0c00f3f7505103d7a496
languageName: node
linkType: hard
@@ -14360,16 +15338,16 @@ __metadata:
linkType: hard
"@types/node@npm:^12.7.1":
- version: 12.20.48
- resolution: "@types/node@npm:12.20.48"
- checksum: 48bd705bda1af2332c50fb24819bba7b0eac791b07c24c098c39b10940170a53bd3c4755aedc3409c7114c539f1f86ea657aa6838d164fd135e3b89b9f9aa772
+ version: 12.20.55
+ resolution: "@types/node@npm:12.20.55"
+ checksum: e4f86785f4092706e0d3b0edff8dca5a13b45627e4b36700acd8dfe6ad53db71928c8dee914d4276c7fd3b6ccd829aa919811c9eb708a2c8e4c6eb3701178c37
languageName: node
linkType: hard
"@types/node@npm:^14.14.31":
- version: 14.18.16
- resolution: "@types/node@npm:14.18.16"
- checksum: 1999799309dc8620a2adf9a5d5e48416af87321bae4c950b4aa8018fcef2c3b6c1fcf98c39eae06f6492c03a643a5a44e2bb3750cd2574d9cf7eac33bac50e24
+ version: 14.18.33
+ resolution: "@types/node@npm:14.18.33"
+ checksum: 4e23f95186d8ae1d38c999bc6b46fe94e790da88744b0a3bfeedcbd0d9ffe2cb0ff39e85f43014f6739e5270292c1a1f6f97a1fc606fd573a0c17fda9a1d42de
languageName: node
linkType: hard
@@ -14381,9 +15359,9 @@ __metadata:
linkType: hard
"@types/node@npm:^16.0.0, @types/node@npm:^16.11.26, @types/node@npm:^16.9.2":
- version: 16.11.56
- resolution: "@types/node@npm:16.11.56"
- checksum: b4efade16eb08a39810921c54a1637e69c8f3184a20d87e8fe74d557d9bda73f0829ac318e2a30a32b1903e4b099812defd1dfe438be70b98dbfbea5b0d99a53
+ version: 16.18.3
+ resolution: "@types/node@npm:16.18.3"
+ checksum: 6b8ba2ea5d842f7986e366cb9184c54d273d492784dc62e08fd5afeae938d9b61aec6e4222d2541cd18f9b1412ba361bbcb3f4204fb003608af80a2a6af959f9
languageName: node
linkType: hard
@@ -14661,13 +15639,13 @@ __metadata:
linkType: hard
"@types/react@npm:^17":
- version: 17.0.45
- resolution: "@types/react@npm:17.0.45"
+ version: 17.0.52
+ resolution: "@types/react@npm:17.0.52"
dependencies:
"@types/prop-types": "*"
"@types/scheduler": "*"
csstype: ^3.0.2
- checksum: 3cc13a02824c13f6fa4807a83abd065ac1d9943359e76bd995cc7cd2b4148c1176ebd54a30a9f4eb8a0f141ff359d712876f256c4fee707e4290607ef8410b3e
+ checksum: a51b98dd87838d161278fdf9dd78e6a4ff8c018f406d6647f77963e144fb52a8beee40c89fd0e7e840eaeaa8bd9fe2f34519410540b1a52d43a6f8b4d2fbce33
languageName: node
linkType: hard
@@ -14698,14 +15676,14 @@ __metadata:
linkType: hard
"@types/request@npm:^2.47.1":
- version: 2.48.5
- resolution: "@types/request@npm:2.48.5"
+ version: 2.48.8
+ resolution: "@types/request@npm:2.48.8"
dependencies:
"@types/caseless": "*"
"@types/node": "*"
"@types/tough-cookie": "*"
form-data: ^2.5.0
- checksum: 02572a0558b9a95ae1a2fa3912b45c4c12f587e25773b2d9bdbf5dfa6f2da5e3787d22256ee0dc4836250f39cf2dcb39fc4ded5bf554c0f948a623c8772e8bd3
+ checksum: 0b7754941e08205dce51635d894ec524df276d2b83ca13b9aab723f9281acecf1108841e9554494cb1cb60f6d6ddbb47ebea97392bcf2bf607f035b3a9b4af45
languageName: node
linkType: hard
@@ -14837,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"
@@ -14896,11 +15890,11 @@ __metadata:
linkType: hard
"@types/stream-buffers@npm:^3.0.3":
- version: 3.0.3
- resolution: "@types/stream-buffers@npm:3.0.3"
+ version: 3.0.4
+ resolution: "@types/stream-buffers@npm:3.0.4"
dependencies:
"@types/node": "*"
- checksum: c3456fa2a18f89d31c54fe169621d8288a9735fb7e92aba45786642659d93be26fa0b4caa5c1043b21f4cfaeeefc24d247fa833586a8a0f3aecedf03adb7b5ac
+ checksum: 5b432b2bf963d612747b79ac317562888236d6a9ea14414fb055c24e7be9643b5e3c7b7470841fa82802aa1c1c0d752a4ba935bbc0cfb12de6b89f7e1dadee92
languageName: node
linkType: hard
@@ -15030,9 +16024,9 @@ __metadata:
linkType: hard
"@types/underscore@npm:^1.8.9":
- version: 1.10.23
- resolution: "@types/underscore@npm:1.10.23"
- checksum: 5e9458888e8c09a0f61f93f5958d4ce57e02e317b21444319f7e4a11796445e58a78d6c743dad17365aa8fb9c31fa23d5f4d30a9047fa2df30d446ccc5e42023
+ version: 1.11.4
+ resolution: "@types/underscore@npm:1.11.4"
+ checksum: db9f8486bc851b732259e51f42d62aad1ae2158be5724612dc125ece5f5d61c51447f9dea28284c2a0f79cb95e788d01cb5ce97709880019213e69fab0dd1696
languageName: node
linkType: hard
@@ -15416,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
@@ -15435,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"
@@ -15457,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
@@ -15726,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
@@ -15941,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:
@@ -15953,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"
@@ -16113,9 +17119,9 @@ __metadata:
languageName: node
linkType: hard
-"apollo-server-core@npm:^3.10.3":
- version: 3.10.3
- resolution: "apollo-server-core@npm:3.10.3"
+"apollo-server-core@npm:^3.11.1":
+ version: 3.11.1
+ resolution: "apollo-server-core@npm:3.11.1"
dependencies:
"@apollo/utils.keyvaluecache": ^1.0.1
"@apollo/utils.logger": ^1.0.0
@@ -16129,19 +17135,20 @@ __metadata:
apollo-reporting-protobuf: ^3.3.3
apollo-server-env: ^4.2.1
apollo-server-errors: ^3.3.1
- apollo-server-plugin-base: ^3.6.3
- apollo-server-types: ^3.6.3
+ apollo-server-plugin-base: ^3.7.1
+ apollo-server-types: ^3.7.1
async-retry: ^1.2.1
fast-json-stable-stringify: ^2.1.0
graphql-tag: ^2.11.0
loglevel: ^1.6.8
lru-cache: ^6.0.0
+ node-abort-controller: ^3.0.1
sha.js: ^2.4.11
uuid: ^9.0.0
whatwg-mimetype: ^3.0.0
peerDependencies:
graphql: ^15.3.0 || ^16.0.0
- checksum: 1a9c3ca29c1e664970737e83d76999d43ceb938e39026a329682fcc80fa17a564a69cb7b38110b1928d3d512ae77eeeb8ed6e160043521052c0360b0b00f0ada
+ checksum: a5cb7cff331680c2a926c64e88f744425b724bcfae46aeb02ae636d0b6f57a605e561eb284e765618bd0b2b5f8c556c92183f69852f2e4f5889368fee6aa38dc
languageName: node
linkType: hard
@@ -16163,9 +17170,9 @@ __metadata:
languageName: node
linkType: hard
-"apollo-server-express@npm:^3.0.0, apollo-server-express@npm:^3.10.3":
- version: 3.10.3
- resolution: "apollo-server-express@npm:3.10.3"
+"apollo-server-express@npm:^3.0.0, apollo-server-express@npm:^3.11.1":
+ version: 3.11.1
+ resolution: "apollo-server-express@npm:3.11.1"
dependencies:
"@types/accepts": ^1.3.5
"@types/body-parser": 1.19.2
@@ -16173,32 +17180,32 @@ __metadata:
"@types/express": 4.17.14
"@types/express-serve-static-core": 4.17.31
accepts: ^1.3.5
- apollo-server-core: ^3.10.3
- apollo-server-types: ^3.6.3
+ apollo-server-core: ^3.11.1
+ apollo-server-types: ^3.7.1
body-parser: ^1.19.0
cors: ^2.8.5
parseurl: ^1.3.3
peerDependencies:
express: ^4.17.1
graphql: ^15.3.0 || ^16.0.0
- checksum: c6dcfd8b61a558bd479d93d1c9cc4f436145b31e7f5e53d6c655d919c79f0b4b785788f0d16fc1d94c1929b85b034ae84a7332ce4e20603b67e0a4709e48b3a6
+ checksum: 1db1a77aaa2f760c885233ded249b632e467bb4895d1c3f797df6e197a9ca7021c5b65dd8829e88fd6dbf32d925c7dcf62b48b949a518e2e31072c490302fa60
languageName: node
linkType: hard
-"apollo-server-plugin-base@npm:^3.6.3":
- version: 3.6.3
- resolution: "apollo-server-plugin-base@npm:3.6.3"
+"apollo-server-plugin-base@npm:^3.7.1":
+ version: 3.7.1
+ resolution: "apollo-server-plugin-base@npm:3.7.1"
dependencies:
- apollo-server-types: ^3.6.3
+ apollo-server-types: ^3.7.1
peerDependencies:
graphql: ^15.3.0 || ^16.0.0
- checksum: 50e690cf4c5047957c4546676f11d82f8c0bee2c0340573322f23188af27175ac49859d463c6123ebef500b3c32a0932e3e3f9fa8671e2d1a410d2e89c8608e3
+ checksum: db8c5f658da8c51c067bd6659b31ec2436d4961437b6f6f6b1b2a109d26764bc52a4dbe1bdafcb3c712b0e2f13ca10ed787e90423505685d2043a77363bdfc0b
languageName: node
linkType: hard
-"apollo-server-types@npm:^3.6.3":
- version: 3.6.3
- resolution: "apollo-server-types@npm:3.6.3"
+"apollo-server-types@npm:^3.7.1":
+ version: 3.7.1
+ resolution: "apollo-server-types@npm:3.7.1"
dependencies:
"@apollo/utils.keyvaluecache": ^1.0.1
"@apollo/utils.logger": ^1.0.0
@@ -16206,21 +17213,21 @@ __metadata:
apollo-server-env: ^4.2.1
peerDependencies:
graphql: ^15.3.0 || ^16.0.0
- checksum: ebd218e6fa8b756bb2d6954b454676907d99b8f140923b439cc1bbb200251f9df7228a9d83c5c91bb571a448cc80c2d86bc0a0eae491a4ce028e86a724cde68a
+ checksum: fe9a0847d0b8ab70dbe407b4ba1f5e506d351ff1f728193f4b308806e73b958f50537478a71edeefdd66fcf3dbf32ec732b6ffe6542860d5b683b1d657a019a2
languageName: node
linkType: hard
"apollo-server@npm:^3.0.0":
- version: 3.10.3
- resolution: "apollo-server@npm:3.10.3"
+ version: 3.11.1
+ resolution: "apollo-server@npm:3.11.1"
dependencies:
"@types/express": 4.17.14
- apollo-server-core: ^3.10.3
- apollo-server-express: ^3.10.3
+ apollo-server-core: ^3.11.1
+ apollo-server-express: ^3.11.1
express: ^4.17.1
peerDependencies:
graphql: ^15.3.0 || ^16.0.0
- checksum: eec2423bbd30256683c0e7873cd1e3f616ff2a3c90cf7bba241880027f5e1374d20d13bf7ce4b09543b16753d0d7a4627f77d64de77b5b241c410f0f246bdbd7
+ checksum: 6d4e981682e3b60313dddfe999c408c683f7e4cdeed5c14b6d6245b708808b94cb14df67ebe1b9df38df6b5193a9291089c41e287d014f2a9f94b2f3ecc9b376
languageName: node
linkType: hard
@@ -16360,27 +17367,6 @@ __metadata:
languageName: node
linkType: hard
-"arr-diff@npm:^4.0.0":
- version: 4.0.0
- resolution: "arr-diff@npm:4.0.0"
- checksum: ea7c8834842ad3869297f7915689bef3494fd5b102ac678c13ffccab672d3d1f35802b79e90c4cfec2f424af3392e44112d1ccf65da34562ed75e049597276a0
- languageName: node
- linkType: hard
-
-"arr-flatten@npm:^1.1.0":
- version: 1.1.0
- resolution: "arr-flatten@npm:1.1.0"
- checksum: 963fe12564fca2f72c055f3f6c206b9e031f7c433a0c66ca9858b484821f248c5b1e5d53c8e4989d80d764cd776cf6d9b160ad05f47bdc63022bfd63b5455e22
- languageName: node
- linkType: hard
-
-"arr-union@npm:^3.1.0":
- version: 3.1.0
- resolution: "arr-union@npm:3.1.0"
- checksum: b5b0408c6eb7591143c394f3be082fee690ddd21f0fdde0a0a01106799e847f67fcae1b7e56b0a0c173290e29c6aca9562e82b300708a268bc8f88f3d6613cb9
- languageName: node
- linkType: hard
-
"array-differ@npm:^3.0.0":
version: 3.0.0
resolution: "array-differ@npm:3.0.0"
@@ -16458,13 +17444,6 @@ __metadata:
languageName: node
linkType: hard
-"array-unique@npm:^0.3.2":
- version: 0.3.2
- resolution: "array-unique@npm:0.3.2"
- checksum: da344b89cfa6b0a5c221f965c21638bfb76b57b45184a01135382186924f55973cd9b171d4dad6bf606c6d9d36b0d721d091afdc9791535ead97ccbe78f8a888
- languageName: node
- linkType: hard
-
"array.prototype.flat@npm:^1.2.3":
version: 1.3.0
resolution: "array.prototype.flat@npm:1.3.0"
@@ -16576,13 +17555,6 @@ __metadata:
languageName: node
linkType: hard
-"assign-symbols@npm:^1.0.0":
- version: 1.0.0
- resolution: "assign-symbols@npm:1.0.0"
- checksum: c0eb895911d05b6b2d245154f70461c5e42c107457972e5ebba38d48967870dee53bcdf6c7047990586daa80fab8dab3cc6300800fbd47b454247fdedd859a2c
- languageName: node
- linkType: hard
-
"ast-types-flow@npm:^0.0.7":
version: 0.0.7
resolution: "ast-types-flow@npm:0.0.7"
@@ -16599,6 +17571,15 @@ __metadata:
languageName: node
linkType: hard
+"ast-types@npm:0.15.2":
+ version: 0.15.2
+ resolution: "ast-types@npm:0.15.2"
+ dependencies:
+ tslib: ^2.0.1
+ checksum: 24f0d86bf9e4c8dae16fa24b13c1776f2c2677040bcfbd4eb4f27911db49020be4876885e45e6cfcc548ed4dfea3a0742d77e3346b84fae47379cb0b89e9daa0
+ languageName: node
+ linkType: hard
+
"astral-regex@npm:^2.0.0":
version: 2.0.0
resolution: "astral-regex@npm:2.0.0"
@@ -16643,15 +17624,6 @@ __metadata:
languageName: node
linkType: hard
-"atob@npm:^2.1.2":
- version: 2.1.2
- resolution: "atob@npm:2.1.2"
- bin:
- atob: bin/atob.js
- checksum: dfeeeb70090c5ebea7be4b9f787f866686c645d9f39a0d184c817252d0cf08455ed25267d79c03254d3be1f03ac399992a792edcd5ffb9c91e097ab5ef42833a
- languageName: node
- linkType: hard
-
"atomic-sleep@npm:^1.0.0":
version: 1.0.0
resolution: "atomic-sleep@npm:1.0.0"
@@ -16710,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"
@@ -17113,21 +18096,6 @@ __metadata:
languageName: node
linkType: hard
-"base@npm:^0.11.1":
- version: 0.11.2
- resolution: "base@npm:0.11.2"
- dependencies:
- cache-base: ^1.0.1
- class-utils: ^0.3.5
- component-emitter: ^1.2.1
- define-property: ^1.0.0
- isobject: ^3.0.1
- mixin-deep: ^1.2.0
- pascalcase: ^0.1.1
- checksum: a4a146b912e27eea8f66d09cb0c9eab666f32ce27859a7dfd50f38cd069a2557b39f16dba1bc2aecb3b44bf096738dd207b7970d99b0318423285ab1b1994edd
- languageName: node
- linkType: hard
-
"basic-auth@npm:~2.0.1":
version: 2.0.1
resolution: "basic-auth@npm:2.0.1"
@@ -17381,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"
@@ -17400,24 +18375,6 @@ __metadata:
languageName: node
linkType: hard
-"braces@npm:^2.3.1":
- version: 2.3.2
- resolution: "braces@npm:2.3.2"
- dependencies:
- arr-flatten: ^1.1.0
- array-unique: ^0.3.2
- extend-shallow: ^2.0.1
- fill-range: ^4.0.0
- isobject: ^3.0.1
- repeat-element: ^1.1.2
- snapdragon: ^0.8.1
- snapdragon-node: ^2.0.1
- split-string: ^3.0.2
- to-regex: ^3.0.1
- checksum: e30dcb6aaf4a31c8df17d848aa283a65699782f75ad61ae93ec25c9729c66cf58e66f0000a9fec84e4add1135bb7da40f7cb9601b36bebcfa9ca58e8d5c07de0
- languageName: node
- linkType: hard
-
"braces@npm:^3.0.2, braces@npm:~3.0.2":
version: 3.0.2
resolution: "braces@npm:3.0.2"
@@ -17763,23 +18720,6 @@ __metadata:
languageName: node
linkType: hard
-"cache-base@npm:^1.0.1":
- version: 1.0.1
- resolution: "cache-base@npm:1.0.1"
- dependencies:
- collection-visit: ^1.0.0
- component-emitter: ^1.2.1
- get-value: ^2.0.6
- has-value: ^1.0.0
- isobject: ^3.0.1
- set-value: ^2.0.0
- to-object-path: ^0.3.0
- union-value: ^1.0.0
- unset-value: ^1.0.0
- checksum: 9114b8654fe2366eedc390bad0bcf534e2f01b239a888894e2928cb58cdc1e6ea23a73c6f3450dcfd2058aa73a8a981e723cd1e7c670c047bf11afdc65880107
- languageName: node
- linkType: hard
-
"cacheable-lookup@npm:^5.0.3":
version: 5.0.3
resolution: "cacheable-lookup@npm:5.0.3"
@@ -17927,15 +18867,15 @@ __metadata:
languageName: node
linkType: hard
-"canvas@npm:^2.6.1":
- version: 2.10.1
- resolution: "canvas@npm:2.10.1"
+"canvas@npm:^2.10.2":
+ version: 2.10.2
+ resolution: "canvas@npm:2.10.2"
dependencies:
"@mapbox/node-pre-gyp": ^1.0.0
- nan: ^2.15.0
+ nan: ^2.17.0
node-gyp: latest
simple-get: ^3.0.3
- checksum: 29b162a59df8c63e5591cae62711ab3cc3b0a078f260b39b4594b51c5bcb9baa597eff40b52f25bd788aceb81756a41097c2dd0c01cbc17ae4a15e873da44cdf
+ checksum: b2e3eb4c3635fa2f67857619621c3d314f935a9e51904536dadf4908ab580dff4f5bcbaafe6eb0255247fa027ca494d5cd97c33376a49a0f994997263fa9944b
languageName: node
linkType: hard
@@ -18173,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"
@@ -18206,18 +19153,6 @@ __metadata:
languageName: node
linkType: hard
-"class-utils@npm:^0.3.5":
- version: 0.3.6
- resolution: "class-utils@npm:0.3.6"
- dependencies:
- arr-union: ^3.1.0
- define-property: ^0.2.5
- isobject: ^3.0.0
- static-extend: ^0.1.1
- checksum: be108900801e639e50f96a7e4bfa8867c753a7750a7603879f3981f8b0a89cba657497a2d5f40cd4ea557ff15d535a100818bb486baf6e26fe5d7872e75f1078
- languageName: node
- linkType: hard
-
"classnames@npm:*, classnames@npm:^2.2.5, classnames@npm:^2.2.6, classnames@npm:^2.3.1":
version: 2.3.1
resolution: "classnames@npm:2.3.1"
@@ -18512,16 +19447,6 @@ __metadata:
languageName: node
linkType: hard
-"collection-visit@npm:^1.0.0":
- version: 1.0.0
- resolution: "collection-visit@npm:1.0.0"
- dependencies:
- map-visit: ^1.0.0
- object-visit: ^1.0.0
- checksum: 15d9658fe6eb23594728346adad5433b86bb7a04fd51bbab337755158722f9313a5376ef479de5b35fbc54140764d0d39de89c339f5d25b959ed221466981da9
- languageName: node
- linkType: hard
-
"color-convert@npm:^0.5.2":
version: 0.5.3
resolution: "color-convert@npm:0.5.3"
@@ -18794,7 +19719,7 @@ __metadata:
languageName: node
linkType: hard
-"component-emitter@npm:^1.2.1, component-emitter@npm:^1.3.0, component-emitter@npm:~1.3.0":
+"component-emitter@npm:^1.3.0, component-emitter@npm:~1.3.0":
version: 1.3.0
resolution: "component-emitter@npm:1.3.0"
checksum: b3c46de38ffd35c57d1c02488355be9f218e582aec72d72d1b8bbec95a3ac1b38c96cd6e03ff015577e68f550fbb361a3bfdbd9bb248be9390b7b3745691be6b
@@ -18914,8 +19839,8 @@ __metadata:
linkType: hard
"concurrently@npm:^7.0.0":
- version: 7.4.0
- resolution: "concurrently@npm:7.4.0"
+ version: 7.5.0
+ resolution: "concurrently@npm:7.5.0"
dependencies:
chalk: ^4.1.0
date-fns: ^2.29.1
@@ -18929,7 +19854,7 @@ __metadata:
bin:
conc: dist/bin/concurrently.js
concurrently: dist/bin/concurrently.js
- checksum: cc547866ad8d009d184ca3a7115d6636052a5f56f5429d123092d651286043d7233f6429257e30e50f509894cd12798ea831896ac18092d8135f67ffcc8ac3ea
+ checksum: 7886e1c8559d2699ae1b62be8aca5d56c226966e252a2b9dd6077b3c1fd5397e98ef537c040fffa1de50418bd2616746eb9dd589a31ffb9056d4758b850a865b
languageName: node
linkType: hard
@@ -19065,14 +19990,7 @@ __metadata:
languageName: node
linkType: hard
-"copy-descriptor@npm:^0.1.0":
- version: 0.1.1
- resolution: "copy-descriptor@npm:0.1.1"
- checksum: d4b7b57b14f1d256bb9aa0b479241048afd7f5bcf22035fc7b94e8af757adeae247ea23c1a774fe44869fd5694efba4a969b88d966766c5245fdee59837fe45b
- 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:
@@ -19127,9 +20045,9 @@ __metadata:
linkType: hard
"core-js@npm:^3.6.5":
- version: 3.25.5
- resolution: "core-js@npm:3.25.5"
- checksum: 208b308c49bc022f90d4349d4c99802a73c9d55053976b3c529f10014c1e37845926defad8c519f2c7f71ea0acf18d2b323ab6aaee34dc85b4c4b3ced0623f3f
+ version: 3.26.1
+ resolution: "core-js@npm:3.26.1"
+ checksum: 0a01149f51ff1e9f41d1ea49cc4c9222047949ea597189ede7c4cf8cde3b097766b9c7615acc77c86fe65b4002f20b638a133dfba7b41dba830d707aeeed45ad
languageName: node
linkType: hard
@@ -19340,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"
@@ -19706,8 +20637,8 @@ __metadata:
linkType: hard
"cypress@npm:^10.0.0":
- version: 10.10.0
- resolution: "cypress@npm:10.10.0"
+ version: 10.11.0
+ resolution: "cypress@npm:10.11.0"
dependencies:
"@cypress/request": ^2.88.10
"@cypress/xvfb": ^1.2.4
@@ -19753,7 +20684,7 @@ __metadata:
yauzl: ^2.10.0
bin:
cypress: bin/cypress
- checksum: 668a32534a527dba79754abbf98af176b80c539a12ec00058932ba2a19c794c7888323e59e738c30f726ad740c5451c31d02548a0cb7c1b1c8ad01c55a984ca2
+ checksum: 938cc6a20f7eeace5c8e850d234904ee1651cbb36d94666fe600cf17ce964e73d4f7d8d944aab677491702a57364e6aceeb4fe8bcbd96147ff5e2b575a956fb2
languageName: node
linkType: hard
@@ -20056,7 +20987,7 @@ __metadata:
languageName: node
linkType: hard
-"debug@npm:2.6.9, debug@npm:^2.2.0, debug@npm:^2.3.3, debug@npm:^2.6.0, debug@npm:^2.6.9":
+"debug@npm:2.6.9, debug@npm:^2.6.0, debug@npm:^2.6.9":
version: 2.6.9
resolution: "debug@npm:2.6.9"
dependencies:
@@ -20265,34 +21196,6 @@ __metadata:
languageName: node
linkType: hard
-"define-property@npm:^0.2.5":
- version: 0.2.5
- resolution: "define-property@npm:0.2.5"
- dependencies:
- is-descriptor: ^0.1.0
- checksum: 85af107072b04973b13f9e4128ab74ddfda48ec7ad2e54b193c0ffb57067c4ce5b7786a7b4ae1f24bd03e87c5d18766b094571810b314d7540f86d4354dbd394
- languageName: node
- linkType: hard
-
-"define-property@npm:^1.0.0":
- version: 1.0.0
- resolution: "define-property@npm:1.0.0"
- dependencies:
- is-descriptor: ^1.0.0
- checksum: 5fbed11dace44dd22914035ba9ae83ad06008532ca814d7936a53a09e897838acdad5b108dd0688cc8d2a7cf0681acbe00ee4136cf36743f680d10517379350a
- languageName: node
- linkType: hard
-
-"define-property@npm:^2.0.2":
- version: 2.0.2
- resolution: "define-property@npm:2.0.2"
- dependencies:
- is-descriptor: ^1.0.2
- isobject: ^3.0.1
- checksum: 3217ed53fc9eed06ba8da6f4d33e28c68a82e2f2a8ab4d562c4920d8169a166fe7271453675e6c69301466f36a65d7f47edf0cf7f474b9aa52a5ead9c1b13c99
- languageName: node
- linkType: hard
-
"del@npm:^6.0.0":
version: 6.1.1
resolution: "del@npm:6.1.1"
@@ -20706,13 +21609,20 @@ __metadata:
languageName: node
linkType: hard
-"dompurify@npm:=2.3.10, dompurify@npm:^2.2.7, dompurify@npm:^2.2.9, dompurify@npm:^2.3.6":
+"dompurify@npm:=2.3.10":
version: 2.3.10
resolution: "dompurify@npm:2.3.10"
checksum: ee343876b4c065e82d194818c66af76a6d2290264c7db583ad71761c11781fd626f0245f9f4670175d5707c4b8fcfb89adae80bed0418a9426a47ee7f36b0ffc
languageName: node
linkType: hard
+"dompurify@npm:^2.2.7, dompurify@npm:^2.2.9, dompurify@npm:^2.3.6":
+ version: 2.4.0
+ resolution: "dompurify@npm:2.4.0"
+ checksum: c93ea73cf8e3ba044588450198563e56ce6902e36d0e16e3699df2fa59e82c4fdd11d4ad04ef5024569ce96a35b46f29d0bbea522516add33cd39a7f56a8a675
+ languageName: node
+ linkType: hard
+
"domutils@npm:^2.5.2, domutils@npm:^2.6.0":
version: 2.8.0
resolution: "domutils@npm:2.8.0"
@@ -21056,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"
@@ -21216,9 +22133,9 @@ __metadata:
languageName: node
linkType: hard
-"esbuild-android-64@npm:0.14.54":
- version: 0.14.54
- resolution: "esbuild-android-64@npm:0.14.54"
+"esbuild-android-64@npm:0.15.13":
+ version: 0.15.13
+ resolution: "esbuild-android-64@npm:0.15.13"
conditions: os=android & cpu=x64
languageName: node
linkType: hard
@@ -21232,9 +22149,9 @@ __metadata:
languageName: node
linkType: hard
-"esbuild-android-arm64@npm:0.14.54":
- version: 0.14.54
- resolution: "esbuild-android-arm64@npm:0.14.54"
+"esbuild-android-arm64@npm:0.15.13":
+ version: 0.15.13
+ resolution: "esbuild-android-arm64@npm:0.15.13"
conditions: os=android & cpu=arm64
languageName: node
linkType: hard
@@ -21246,9 +22163,9 @@ __metadata:
languageName: node
linkType: hard
-"esbuild-darwin-64@npm:0.14.54":
- version: 0.14.54
- resolution: "esbuild-darwin-64@npm:0.14.54"
+"esbuild-darwin-64@npm:0.15.13":
+ version: 0.15.13
+ resolution: "esbuild-darwin-64@npm:0.15.13"
conditions: os=darwin & cpu=x64
languageName: node
linkType: hard
@@ -21260,9 +22177,9 @@ __metadata:
languageName: node
linkType: hard
-"esbuild-darwin-arm64@npm:0.14.54":
- version: 0.14.54
- resolution: "esbuild-darwin-arm64@npm:0.14.54"
+"esbuild-darwin-arm64@npm:0.15.13":
+ version: 0.15.13
+ resolution: "esbuild-darwin-arm64@npm:0.15.13"
conditions: os=darwin & cpu=arm64
languageName: node
linkType: hard
@@ -21274,9 +22191,9 @@ __metadata:
languageName: node
linkType: hard
-"esbuild-freebsd-64@npm:0.14.54":
- version: 0.14.54
- resolution: "esbuild-freebsd-64@npm:0.14.54"
+"esbuild-freebsd-64@npm:0.15.13":
+ version: 0.15.13
+ resolution: "esbuild-freebsd-64@npm:0.15.13"
conditions: os=freebsd & cpu=x64
languageName: node
linkType: hard
@@ -21288,9 +22205,9 @@ __metadata:
languageName: node
linkType: hard
-"esbuild-freebsd-arm64@npm:0.14.54":
- version: 0.14.54
- resolution: "esbuild-freebsd-arm64@npm:0.14.54"
+"esbuild-freebsd-arm64@npm:0.15.13":
+ version: 0.15.13
+ resolution: "esbuild-freebsd-arm64@npm:0.15.13"
conditions: os=freebsd & cpu=arm64
languageName: node
linkType: hard
@@ -21302,9 +22219,9 @@ __metadata:
languageName: node
linkType: hard
-"esbuild-linux-32@npm:0.14.54":
- version: 0.14.54
- resolution: "esbuild-linux-32@npm:0.14.54"
+"esbuild-linux-32@npm:0.15.13":
+ version: 0.15.13
+ resolution: "esbuild-linux-32@npm:0.15.13"
conditions: os=linux & cpu=ia32
languageName: node
linkType: hard
@@ -21316,9 +22233,9 @@ __metadata:
languageName: node
linkType: hard
-"esbuild-linux-64@npm:0.14.54":
- version: 0.14.54
- resolution: "esbuild-linux-64@npm:0.14.54"
+"esbuild-linux-64@npm:0.15.13":
+ version: 0.15.13
+ resolution: "esbuild-linux-64@npm:0.15.13"
conditions: os=linux & cpu=x64
languageName: node
linkType: hard
@@ -21330,9 +22247,9 @@ __metadata:
languageName: node
linkType: hard
-"esbuild-linux-arm64@npm:0.14.54":
- version: 0.14.54
- resolution: "esbuild-linux-arm64@npm:0.14.54"
+"esbuild-linux-arm64@npm:0.15.13":
+ version: 0.15.13
+ resolution: "esbuild-linux-arm64@npm:0.15.13"
conditions: os=linux & cpu=arm64
languageName: node
linkType: hard
@@ -21344,9 +22261,9 @@ __metadata:
languageName: node
linkType: hard
-"esbuild-linux-arm@npm:0.14.54":
- version: 0.14.54
- resolution: "esbuild-linux-arm@npm:0.14.54"
+"esbuild-linux-arm@npm:0.15.13":
+ version: 0.15.13
+ resolution: "esbuild-linux-arm@npm:0.15.13"
conditions: os=linux & cpu=arm
languageName: node
linkType: hard
@@ -21358,9 +22275,9 @@ __metadata:
languageName: node
linkType: hard
-"esbuild-linux-mips64le@npm:0.14.54":
- version: 0.14.54
- resolution: "esbuild-linux-mips64le@npm:0.14.54"
+"esbuild-linux-mips64le@npm:0.15.13":
+ version: 0.15.13
+ resolution: "esbuild-linux-mips64le@npm:0.15.13"
conditions: os=linux & cpu=mips64el
languageName: node
linkType: hard
@@ -21372,9 +22289,9 @@ __metadata:
languageName: node
linkType: hard
-"esbuild-linux-ppc64le@npm:0.14.54":
- version: 0.14.54
- resolution: "esbuild-linux-ppc64le@npm:0.14.54"
+"esbuild-linux-ppc64le@npm:0.15.13":
+ version: 0.15.13
+ resolution: "esbuild-linux-ppc64le@npm:0.15.13"
conditions: os=linux & cpu=ppc64
languageName: node
linkType: hard
@@ -21386,9 +22303,9 @@ __metadata:
languageName: node
linkType: hard
-"esbuild-linux-riscv64@npm:0.14.54":
- version: 0.14.54
- resolution: "esbuild-linux-riscv64@npm:0.14.54"
+"esbuild-linux-riscv64@npm:0.15.13":
+ version: 0.15.13
+ resolution: "esbuild-linux-riscv64@npm:0.15.13"
conditions: os=linux & cpu=riscv64
languageName: node
linkType: hard
@@ -21400,9 +22317,9 @@ __metadata:
languageName: node
linkType: hard
-"esbuild-linux-s390x@npm:0.14.54":
- version: 0.14.54
- resolution: "esbuild-linux-s390x@npm:0.14.54"
+"esbuild-linux-s390x@npm:0.15.13":
+ version: 0.15.13
+ resolution: "esbuild-linux-s390x@npm:0.15.13"
conditions: os=linux & cpu=s390x
languageName: node
linkType: hard
@@ -21430,9 +22347,9 @@ __metadata:
languageName: node
linkType: hard
-"esbuild-netbsd-64@npm:0.14.54":
- version: 0.14.54
- resolution: "esbuild-netbsd-64@npm:0.14.54"
+"esbuild-netbsd-64@npm:0.15.13":
+ version: 0.15.13
+ resolution: "esbuild-netbsd-64@npm:0.15.13"
conditions: os=netbsd & cpu=x64
languageName: node
linkType: hard
@@ -21444,9 +22361,9 @@ __metadata:
languageName: node
linkType: hard
-"esbuild-openbsd-64@npm:0.14.54":
- version: 0.14.54
- resolution: "esbuild-openbsd-64@npm:0.14.54"
+"esbuild-openbsd-64@npm:0.15.13":
+ version: 0.15.13
+ resolution: "esbuild-openbsd-64@npm:0.15.13"
conditions: os=openbsd & cpu=x64
languageName: node
linkType: hard
@@ -21458,9 +22375,9 @@ __metadata:
languageName: node
linkType: hard
-"esbuild-sunos-64@npm:0.14.54":
- version: 0.14.54
- resolution: "esbuild-sunos-64@npm:0.14.54"
+"esbuild-sunos-64@npm:0.15.13":
+ version: 0.15.13
+ resolution: "esbuild-sunos-64@npm:0.15.13"
conditions: os=sunos & cpu=x64
languageName: node
linkType: hard
@@ -21481,9 +22398,9 @@ __metadata:
languageName: node
linkType: hard
-"esbuild-windows-32@npm:0.14.54":
- version: 0.14.54
- resolution: "esbuild-windows-32@npm:0.14.54"
+"esbuild-windows-32@npm:0.15.13":
+ version: 0.15.13
+ resolution: "esbuild-windows-32@npm:0.15.13"
conditions: os=win32 & cpu=ia32
languageName: node
linkType: hard
@@ -21495,9 +22412,9 @@ __metadata:
languageName: node
linkType: hard
-"esbuild-windows-64@npm:0.14.54":
- version: 0.14.54
- resolution: "esbuild-windows-64@npm:0.14.54"
+"esbuild-windows-64@npm:0.15.13":
+ version: 0.15.13
+ resolution: "esbuild-windows-64@npm:0.15.13"
conditions: os=win32 & cpu=x64
languageName: node
linkType: hard
@@ -21509,9 +22426,9 @@ __metadata:
languageName: node
linkType: hard
-"esbuild-windows-arm64@npm:0.14.54":
- version: 0.14.54
- resolution: "esbuild-windows-arm64@npm:0.14.54"
+"esbuild-windows-arm64@npm:0.15.13":
+ version: 0.15.13
+ resolution: "esbuild-windows-arm64@npm:0.15.13"
conditions: os=win32 & cpu=arm64
languageName: node
linkType: hard
@@ -21523,32 +22440,35 @@ __metadata:
languageName: node
linkType: hard
-"esbuild@npm:^0.14.1, esbuild@npm:^0.14.10":
- version: 0.14.54
- resolution: "esbuild@npm:0.14.54"
+"esbuild@npm:^0.15.0":
+ version: 0.15.13
+ resolution: "esbuild@npm:0.15.13"
dependencies:
- "@esbuild/linux-loong64": 0.14.54
- esbuild-android-64: 0.14.54
- esbuild-android-arm64: 0.14.54
- esbuild-darwin-64: 0.14.54
- esbuild-darwin-arm64: 0.14.54
- esbuild-freebsd-64: 0.14.54
- esbuild-freebsd-arm64: 0.14.54
- esbuild-linux-32: 0.14.54
- esbuild-linux-64: 0.14.54
- esbuild-linux-arm: 0.14.54
- esbuild-linux-arm64: 0.14.54
- esbuild-linux-mips64le: 0.14.54
- esbuild-linux-ppc64le: 0.14.54
- esbuild-linux-riscv64: 0.14.54
- esbuild-linux-s390x: 0.14.54
- esbuild-netbsd-64: 0.14.54
- esbuild-openbsd-64: 0.14.54
- esbuild-sunos-64: 0.14.54
- esbuild-windows-32: 0.14.54
- esbuild-windows-64: 0.14.54
- esbuild-windows-arm64: 0.14.54
+ "@esbuild/android-arm": 0.15.13
+ "@esbuild/linux-loong64": 0.15.13
+ esbuild-android-64: 0.15.13
+ esbuild-android-arm64: 0.15.13
+ esbuild-darwin-64: 0.15.13
+ esbuild-darwin-arm64: 0.15.13
+ esbuild-freebsd-64: 0.15.13
+ esbuild-freebsd-arm64: 0.15.13
+ esbuild-linux-32: 0.15.13
+ esbuild-linux-64: 0.15.13
+ esbuild-linux-arm: 0.15.13
+ esbuild-linux-arm64: 0.15.13
+ esbuild-linux-mips64le: 0.15.13
+ esbuild-linux-ppc64le: 0.15.13
+ esbuild-linux-riscv64: 0.15.13
+ esbuild-linux-s390x: 0.15.13
+ esbuild-netbsd-64: 0.15.13
+ esbuild-openbsd-64: 0.15.13
+ esbuild-sunos-64: 0.15.13
+ esbuild-windows-32: 0.15.13
+ esbuild-windows-64: 0.15.13
+ esbuild-windows-arm64: 0.15.13
dependenciesMeta:
+ "@esbuild/android-arm":
+ optional: true
"@esbuild/linux-loong64":
optional: true
esbuild-android-64:
@@ -21593,7 +22513,7 @@ __metadata:
optional: true
bin:
esbuild: bin/esbuild
- checksum: 49e360b1185c797f5ca3a7f5f0a75121494d97ddf691f65ed1796e6257d318f928342a97f559bb8eced6a90cf604dd22db4a30e0dbbf15edd9dbf22459b639af
+ checksum: ef5f339fae7e2abc4ec5484d4b301efdf40f580e043cbf8a66e19d6c91df82368a810abec61fd5e5db226f0c354f49c36616c9ea04c5412a142a050c10239bf7
languageName: node
linkType: hard
@@ -21810,8 +22730,8 @@ __metadata:
linkType: hard
"eslint-plugin-deprecation@npm:^1.3.2":
- version: 1.3.2
- resolution: "eslint-plugin-deprecation@npm:1.3.2"
+ version: 1.3.3
+ resolution: "eslint-plugin-deprecation@npm:1.3.3"
dependencies:
"@typescript-eslint/experimental-utils": ^5.0.0
tslib: ^2.3.1
@@ -21819,7 +22739,7 @@ __metadata:
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
typescript: ^3.7.5 || ^4.0.0
- checksum: 763776eec6af02ad442bf9ed7e73da198da6969b51418b43f79b3f0a27395e85e9988a3b182e61fab7812a35e17539ba72464d1123a87cc25b195288cbd0c31d
+ checksum: 5e14d7bc8245a14784623632d43a6210880a4aad4c029fd44686a5516c248287f32406ff230f6e9d238784854b24cd09da953ec8f73d9d19a7c4b3905884e432
languageName: node
linkType: hard
@@ -21847,8 +22767,8 @@ __metadata:
linkType: hard
"eslint-plugin-jest@npm:^27.0.0":
- version: 27.0.4
- resolution: "eslint-plugin-jest@npm:27.0.4"
+ version: 27.1.5
+ resolution: "eslint-plugin-jest@npm:27.1.5"
dependencies:
"@typescript-eslint/utils": ^5.10.0
peerDependencies:
@@ -21859,7 +22779,7 @@ __metadata:
optional: true
jest:
optional: true
- checksum: 8408d8a53bae946527ac4120865c29b3468cf58d8e5ff3b9c75c5303bb5aa451ac7e04329fc004cf6302f84431e6c6c1f2ba9009b0150d1718df58ea490ed3f5
+ checksum: 7c9de765793f7161afa0bdcdce67f4d072944152880fa638b25d228188dcee47a4b4aada26c57db72bc10193c96a1979e17afb8a7c3e400e961d8adfbf23ddbe
languageName: node
linkType: hard
@@ -22009,13 +22929,13 @@ __metadata:
linkType: hard
"eslint@npm:^8.6.0":
- version: 8.23.1
- resolution: "eslint@npm:8.23.1"
+ version: 8.27.0
+ resolution: "eslint@npm:8.27.0"
dependencies:
- "@eslint/eslintrc": ^1.3.2
- "@humanwhocodes/config-array": ^0.10.4
- "@humanwhocodes/gitignore-to-minimatch": ^1.0.2
+ "@eslint/eslintrc": ^1.3.3
+ "@humanwhocodes/config-array": ^0.11.6
"@humanwhocodes/module-importer": ^1.0.1
+ "@nodelib/fs.walk": ^1.2.8
ajv: ^6.10.0
chalk: ^4.0.0
cross-spawn: ^7.0.2
@@ -22031,14 +22951,14 @@ __metadata:
fast-deep-equal: ^3.1.3
file-entry-cache: ^6.0.1
find-up: ^5.0.0
- glob-parent: ^6.0.1
+ glob-parent: ^6.0.2
globals: ^13.15.0
- globby: ^11.1.0
grapheme-splitter: ^1.0.4
ignore: ^5.2.0
import-fresh: ^3.0.0
imurmurhash: ^0.1.4
is-glob: ^4.0.0
+ is-path-inside: ^3.0.3
js-sdsl: ^4.1.4
js-yaml: ^4.1.0
json-stable-stringify-without-jsonify: ^1.0.1
@@ -22053,7 +22973,7 @@ __metadata:
text-table: ^0.2.0
bin:
eslint: bin/eslint.js
- checksum: a727e15492786a03b438bcf021db49f715680679846a7b8d79b98ad34576f2a570404ffe882d3c3e26f6359bff7277ef11fae5614bfe8629adb653f20d018c71
+ checksum: 153b022d309e1b647a73b1bb0fa98912add699b06e279084155f23c6f2b5fc5abd05411fc1ba81608a24bbfaf044ca079544c16fffa6fc987b8f676c9960a2c4
languageName: node
linkType: hard
@@ -22372,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:^"
@@ -22514,21 +23437,6 @@ __metadata:
languageName: node
linkType: hard
-"expand-brackets@npm:^2.1.4":
- version: 2.1.4
- resolution: "expand-brackets@npm:2.1.4"
- dependencies:
- debug: ^2.3.3
- define-property: ^0.2.5
- extend-shallow: ^2.0.1
- posix-character-classes: ^0.1.0
- regex-not: ^1.0.0
- snapdragon: ^0.8.1
- to-regex: ^3.0.1
- checksum: 1781d422e7edfa20009e2abda673cadb040a6037f0bd30fcd7357304f4f0c284afd420d7622722ca4a016f39b6d091841ab57b401c1f7e2e5131ac65b9f14fa1
- languageName: node
- linkType: hard
-
"expand-template@npm:^2.0.3":
version: 2.0.3
resolution: "expand-template@npm:2.0.3"
@@ -22642,25 +23550,6 @@ __metadata:
languageName: node
linkType: hard
-"extend-shallow@npm:^2.0.1":
- version: 2.0.1
- resolution: "extend-shallow@npm:2.0.1"
- dependencies:
- is-extendable: ^0.1.0
- checksum: 8fb58d9d7a511f4baf78d383e637bd7d2e80843bd9cd0853649108ea835208fb614da502a553acc30208e1325240bb7cc4a68473021612496bb89725483656d8
- languageName: node
- linkType: hard
-
-"extend-shallow@npm:^3.0.0, extend-shallow@npm:^3.0.2":
- version: 3.0.2
- resolution: "extend-shallow@npm:3.0.2"
- dependencies:
- assign-symbols: ^1.0.0
- is-extendable: ^1.0.1
- checksum: a920b0cd5838a9995ace31dfd11ab5e79bf6e295aa566910ce53dff19f4b1c0fda2ef21f26b28586c7a2450ca2b42d97bd8c0f5cec9351a819222bf861e02461
- languageName: node
- linkType: hard
-
"extend@npm:3.0.2, extend@npm:^3.0.0, extend@npm:^3.0.2, extend@npm:~3.0.2":
version: 3.0.2
resolution: "extend@npm:3.0.2"
@@ -22686,22 +23575,6 @@ __metadata:
languageName: node
linkType: hard
-"extglob@npm:^2.0.4":
- version: 2.0.4
- resolution: "extglob@npm:2.0.4"
- dependencies:
- array-unique: ^0.3.2
- define-property: ^1.0.0
- expand-brackets: ^2.1.4
- extend-shallow: ^2.0.1
- fragment-cache: ^0.2.1
- regex-not: ^1.0.0
- snapdragon: ^0.8.1
- to-regex: ^3.0.1
- checksum: a41531b8934735b684cef5e8c5a01d0f298d7d384500ceca38793a9ce098125aab04ee73e2d75d5b2901bc5dddd2b64e1b5e3bf19139ea48bac52af4a92f1d00
- languageName: node
- linkType: hard
-
"extract-files@npm:^11.0.0":
version: 11.0.0
resolution: "extract-files@npm:11.0.0"
@@ -22846,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"
@@ -22986,18 +23868,6 @@ __metadata:
languageName: node
linkType: hard
-"fill-range@npm:^4.0.0":
- version: 4.0.0
- resolution: "fill-range@npm:4.0.0"
- dependencies:
- extend-shallow: ^2.0.1
- is-number: ^3.0.0
- repeat-string: ^1.6.1
- to-regex-range: ^2.1.0
- checksum: dbb5102467786ab42bc7a3ec7380ae5d6bfd1b5177b2216de89e4a541193f8ba599a6db84651bd2c58c8921db41b8cc3d699ea83b477342d3ce404020f73c298
- languageName: node
- linkType: hard
-
"fill-range@npm:^7.0.1":
version: 7.0.1
resolution: "fill-range@npm:7.0.1"
@@ -23130,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"
@@ -23207,13 +24086,6 @@ __metadata:
languageName: node
linkType: hard
-"for-in@npm:^1.0.2":
- version: 1.0.2
- resolution: "for-in@npm:1.0.2"
- checksum: 09f4ae93ce785d253ac963d94c7f3432d89398bf25ac7a24ed034ca393bf74380bdeccc40e0f2d721a895e54211b07c8fad7132e8157827f6f7f059b70b4043d
- languageName: node
- linkType: hard
-
"foreach@npm:^2.0.4, foreach@npm:^2.0.5":
version: 2.0.5
resolution: "foreach@npm:2.0.5"
@@ -23383,15 +24255,6 @@ __metadata:
languageName: node
linkType: hard
-"fragment-cache@npm:^0.2.1":
- version: 0.2.1
- resolution: "fragment-cache@npm:0.2.1"
- dependencies:
- map-cache: ^0.2.2
- checksum: 1cbbd0b0116b67d5790175de0038a11df23c1cd2e8dcdbade58ebba5594c2d641dade6b4f126d82a7b4a6ffc2ea12e3d387dbb64ea2ae97cf02847d436f60fdc
- languageName: node
- linkType: hard
-
"fresh@npm:0.5.2":
version: 0.5.2
resolution: "fresh@npm:0.5.2"
@@ -23770,13 +24633,6 @@ __metadata:
languageName: node
linkType: hard
-"get-value@npm:^2.0.3, get-value@npm:^2.0.6":
- version: 2.0.6
- resolution: "get-value@npm:2.0.6"
- checksum: 5c3b99cb5398ea8016bf46ff17afc5d1d286874d2ad38ca5edb6e87d75c0965b0094cb9a9dddef2c59c23d250702323539a7fbdd870620db38c7e7d7ec87c1eb
- languageName: node
- linkType: hard
-
"getopts@npm:2.3.0":
version: 2.3.0
resolution: "getopts@npm:2.3.0"
@@ -23837,7 +24693,7 @@ __metadata:
languageName: node
linkType: hard
-"glob-parent@npm:^6.0.1":
+"glob-parent@npm:^6.0.2":
version: 6.0.2
resolution: "glob-parent@npm:6.0.2"
dependencies:
@@ -24015,8 +24871,8 @@ __metadata:
linkType: hard
"google-auth-library@npm:^8.0.0":
- version: 8.5.2
- resolution: "google-auth-library@npm:8.5.2"
+ version: 8.7.0
+ resolution: "google-auth-library@npm:8.7.0"
dependencies:
arrify: ^2.0.0
base64-js: ^1.3.0
@@ -24027,7 +24883,7 @@ __metadata:
gtoken: ^6.1.0
jws: ^4.0.0
lru-cache: ^6.0.0
- checksum: 5ab2904f5da3c119a7c241a1d5a11640468a7da58dfcec8a9cad181cc2723e6662b3c65997906069852d9fa066ba3e4b7f14e11cbb80d541e320b66ead6777dc
+ checksum: 978d1c5f763aceddbc0218cd76fa578c8ba54a0653cefffaf61847bb8d246ebf26e7fcd276d8885b8a3354c17eef0a11cfae9e60e4df62c01cae4378d4eb78e4
languageName: node
linkType: hard
@@ -24515,45 +25371,6 @@ __metadata:
languageName: node
linkType: hard
-"has-value@npm:^0.3.1":
- version: 0.3.1
- resolution: "has-value@npm:0.3.1"
- dependencies:
- get-value: ^2.0.3
- has-values: ^0.1.4
- isobject: ^2.0.0
- checksum: 29e2a1e6571dad83451b769c7ce032fce6009f65bccace07c2962d3ad4d5530b6743d8f3229e4ecf3ea8e905d23a752c5f7089100c1f3162039fa6dc3976558f
- languageName: node
- linkType: hard
-
-"has-value@npm:^1.0.0":
- version: 1.0.0
- resolution: "has-value@npm:1.0.0"
- dependencies:
- get-value: ^2.0.6
- has-values: ^1.0.0
- isobject: ^3.0.0
- checksum: b9421d354e44f03d3272ac39fd49f804f19bc1e4fa3ceef7745df43d6b402053f828445c03226b21d7d934a21ac9cf4bc569396dc312f496ddff873197bbd847
- languageName: node
- linkType: hard
-
-"has-values@npm:^0.1.4":
- version: 0.1.4
- resolution: "has-values@npm:0.1.4"
- checksum: ab1c4bcaf811ccd1856c11cfe90e62fca9e2b026ebe474233a3d282d8d67e3b59ed85b622c7673bac3db198cb98bd1da2b39300a2f98e453729b115350af49bc
- languageName: node
- linkType: hard
-
-"has-values@npm:^1.0.0":
- version: 1.0.0
- resolution: "has-values@npm:1.0.0"
- dependencies:
- is-number: ^3.0.0
- kind-of: ^4.0.0
- checksum: 77e6693f732b5e4cf6c38dfe85fdcefad0fab011af74995c3e83863fabf5e3a836f406d83565816baa0bc0a523c9410db8b990fe977074d61aeb6d8f4fcffa11
- languageName: node
- linkType: hard
-
"has@npm:^1.0.3":
version: 1.0.3
resolution: "has@npm:1.0.3"
@@ -25034,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
@@ -25474,9 +26291,9 @@ __metadata:
languageName: node
linkType: hard
-"ioredis@npm:^5.2.3":
- version: 5.2.3
- resolution: "ioredis@npm:5.2.3"
+"ioredis@npm:^5.2.4":
+ version: 5.2.4
+ resolution: "ioredis@npm:5.2.4"
dependencies:
"@ioredis/commands": ^1.1.1
cluster-key-slot: ^1.1.0
@@ -25487,7 +26304,7 @@ __metadata:
redis-errors: ^1.2.0
redis-parser: ^3.0.0
standard-as-callback: ^2.1.0
- checksum: 2cb7f0f4217e6774accad3620af1b7114722721c1d1824be2c9f0c2a77ab9629f2e0848d18b1a7208bc37796ae1207cb3e0898fce61900cfe797da0382724ad1
+ checksum: c3a7df407a41ae516bede8b6db853c568198b13fe4a4785f66be5cd541087121b9d45fb9a6b1b6a5fb668c29ce52ab4685642b994803bdfa0a35f794ea8ef7ae
languageName: node
linkType: hard
@@ -25536,24 +26353,6 @@ __metadata:
languageName: node
linkType: hard
-"is-accessor-descriptor@npm:^0.1.6":
- version: 0.1.6
- resolution: "is-accessor-descriptor@npm:0.1.6"
- dependencies:
- kind-of: ^3.0.2
- checksum: 3d629a086a9585bc16a83a8e8a3416f400023301855cafb7ccc9a1d63145b7480f0ad28877dcc2cce09492c4ec1c39ef4c071996f24ee6ac626be4217b8ffc8a
- languageName: node
- linkType: hard
-
-"is-accessor-descriptor@npm:^1.0.0":
- version: 1.0.0
- resolution: "is-accessor-descriptor@npm:1.0.0"
- dependencies:
- kind-of: ^6.0.0
- checksum: 8e475968e9b22f9849343c25854fa24492dbe8ba0dea1a818978f9f1b887339190b022c9300d08c47fe36f1b913d70ce8cbaca00369c55a56705fdb7caed37fe
- languageName: node
- linkType: hard
-
"is-alphabetical@npm:^1.0.0":
version: 1.0.4
resolution: "is-alphabetical@npm:1.0.4"
@@ -25637,13 +26436,6 @@ __metadata:
languageName: node
linkType: hard
-"is-buffer@npm:^1.1.5":
- version: 1.1.6
- resolution: "is-buffer@npm:1.1.6"
- checksum: 4a186d995d8bbf9153b4bd9ff9fd04ae75068fe695d29025d25e592d9488911eeece84eefbd8fa41b8ddcc0711058a71d4c466dcf6f1f6e1d83830052d8ca707
- languageName: node
- linkType: hard
-
"is-buffer@npm:^2.0.0":
version: 2.0.4
resolution: "is-buffer@npm:2.0.4"
@@ -25667,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"
@@ -25705,24 +26508,6 @@ __metadata:
languageName: node
linkType: hard
-"is-data-descriptor@npm:^0.1.4":
- version: 0.1.4
- resolution: "is-data-descriptor@npm:0.1.4"
- dependencies:
- kind-of: ^3.0.2
- checksum: 5c622e078ba933a78338ae398a3d1fc5c23332b395312daf4f74bab4afb10d061cea74821add726cb4db8b946ba36217ee71a24fe71dd5bca4632edb7f6aad87
- languageName: node
- linkType: hard
-
-"is-data-descriptor@npm:^1.0.0":
- version: 1.0.0
- resolution: "is-data-descriptor@npm:1.0.0"
- dependencies:
- kind-of: ^6.0.0
- checksum: e705e6816241c013b05a65dc452244ee378d1c3e3842bd140beabe6e12c0d700ef23c91803f971aa7b091fb0573c5da8963af34a2b573337d87bc3e1f53a4e6d
- languageName: node
- linkType: hard
-
"is-date-object@npm:^1.0.1":
version: 1.0.5
resolution: "is-date-object@npm:1.0.5"
@@ -25746,28 +26531,6 @@ __metadata:
languageName: node
linkType: hard
-"is-descriptor@npm:^0.1.0":
- version: 0.1.6
- resolution: "is-descriptor@npm:0.1.6"
- dependencies:
- is-accessor-descriptor: ^0.1.6
- is-data-descriptor: ^0.1.4
- kind-of: ^5.0.0
- checksum: 0f780c1b46b465f71d970fd7754096ffdb7b69fd8797ca1f5069c163eaedcd6a20ec4a50af669075c9ebcfb5266d2e53c8b227e485eefdb0d1fee09aa1dd8ab6
- languageName: node
- linkType: hard
-
-"is-descriptor@npm:^1.0.0, is-descriptor@npm:^1.0.2":
- version: 1.0.2
- resolution: "is-descriptor@npm:1.0.2"
- dependencies:
- is-accessor-descriptor: ^1.0.0
- is-data-descriptor: ^1.0.0
- kind-of: ^6.0.2
- checksum: 2ed623560bee035fb67b23e32ce885700bef8abe3fbf8c909907d86507b91a2c89a9d3a4d835a4d7334dd5db0237a0aeae9ca109c1e4ef1c0e7b577c0846ab5a
- languageName: node
- linkType: hard
-
"is-docker@npm:^2.0.0, is-docker@npm:^2.1.1":
version: 2.2.1
resolution: "is-docker@npm:2.2.1"
@@ -25777,32 +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-extendable@npm:^0.1.0, is-extendable@npm:^0.1.1":
- version: 0.1.1
- resolution: "is-extendable@npm:0.1.1"
- checksum: 3875571d20a7563772ecc7a5f36cb03167e9be31ad259041b4a8f73f33f885441f778cee1f1fe0085eb4bc71679b9d8c923690003a36a6a5fdf8023e6e3f0672
- languageName: node
- linkType: hard
-
-"is-extendable@npm:^1.0.1":
- version: 1.0.1
- resolution: "is-extendable@npm:1.0.1"
- dependencies:
- is-plain-object: ^2.0.4
- checksum: db07bc1e9de6170de70eff7001943691f05b9d1547730b11be01c0ebfe67362912ba743cf4be6fd20a5e03b4180c685dad80b7c509fe717037e3eee30ad8e84f
- languageName: node
- linkType: hard
-
"is-extglob@npm:^2.1.1":
version: 2.1.1
resolution: "is-extglob@npm:2.1.1"
@@ -25947,15 +26684,6 @@ __metadata:
languageName: node
linkType: hard
-"is-number@npm:^3.0.0":
- version: 3.0.0
- resolution: "is-number@npm:3.0.0"
- dependencies:
- kind-of: ^3.0.2
- checksum: 0c62bf8e9d72c4dd203a74d8cfc751c746e75513380fef420cda8237e619a988ee43e678ddb23c87ac24d91ac0fe9f22e4ffb1301a50310c697e9d73ca3994e9
- languageName: node
- linkType: hard
-
"is-number@npm:^7.0.0":
version: 7.0.0
resolution: "is-number@npm:7.0.0"
@@ -25963,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"
@@ -25977,7 +26698,7 @@ __metadata:
languageName: node
linkType: hard
-"is-path-inside@npm:^3.0.2":
+"is-path-inside@npm:^3.0.2, is-path-inside@npm:^3.0.3":
version: 3.0.3
resolution: "is-path-inside@npm:3.0.3"
checksum: abd50f06186a052b349c15e55b182326f1936c89a78bf6c8f2b707412517c097ce04bc49a0ca221787bc44e1049f51f09a2ffb63d22899051988d3a618ba13e9
@@ -26005,7 +26726,7 @@ __metadata:
languageName: node
linkType: hard
-"is-plain-object@npm:^2.0.3, is-plain-object@npm:^2.0.4":
+"is-plain-object@npm:^2.0.4":
version: 2.0.4
resolution: "is-plain-object@npm:2.0.4"
dependencies:
@@ -26234,21 +26955,14 @@ __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, is-windows@npm:^1.0.2":
+"is-windows@npm:^1.0.0, is-windows@npm:^1.0.1":
version: 1.0.2
resolution: "is-windows@npm:1.0.2"
checksum: 438b7e52656fe3b9b293b180defb4e448088e7023a523ec21a91a80b9ff8cdb3377ddb5b6e60f7c7de4fa8b63ab56e121b6705fe081b3cf1b828b0a380009ad7
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:
@@ -26264,13 +26978,6 @@ __metadata:
languageName: node
linkType: hard
-"isarray@npm:1.0.0, isarray@npm:^1.0.0, isarray@npm:~1.0.0":
- version: 1.0.0
- resolution: "isarray@npm:1.0.0"
- checksum: f032df8e02dce8ec565cf2eb605ea939bdccea528dbcf565cdf92bfa2da9110461159d86a537388ef1acef8815a330642d7885b29010e8f7eac967c9993b65ab
- languageName: node
- linkType: hard
-
"isarray@npm:2.0.1":
version: 2.0.1
resolution: "isarray@npm:2.0.1"
@@ -26278,6 +26985,13 @@ __metadata:
languageName: node
linkType: hard
+"isarray@npm:^1.0.0, isarray@npm:~1.0.0":
+ version: 1.0.0
+ resolution: "isarray@npm:1.0.0"
+ checksum: f032df8e02dce8ec565cf2eb605ea939bdccea528dbcf565cdf92bfa2da9110461159d86a537388ef1acef8815a330642d7885b29010e8f7eac967c9993b65ab
+ languageName: node
+ linkType: hard
+
"isbinaryfile@npm:^4.0.10":
version: 4.0.10
resolution: "isbinaryfile@npm:4.0.10"
@@ -26306,16 +27020,7 @@ __metadata:
languageName: node
linkType: hard
-"isobject@npm:^2.0.0":
- version: 2.1.0
- resolution: "isobject@npm:2.1.0"
- dependencies:
- isarray: 1.0.0
- checksum: 811c6f5a866877d31f0606a88af4a45f282544de886bf29f6a34c46616a1ae2ed17076cc6bf34c0128f33eecf7e1fcaa2c82cf3770560d3e26810894e96ae79f
- languageName: node
- linkType: hard
-
-"isobject@npm:^3.0.0, isobject@npm:^3.0.1":
+"isobject@npm:^3.0.1":
version: 3.0.1
resolution: "isobject@npm:3.0.1"
checksum: db85c4c970ce30693676487cca0e61da2ca34e8d4967c2e1309143ff910c207133a969f9e4ddb2dc6aba670aabce4e0e307146c310350b298e74a31f7d464703
@@ -27069,17 +27774,17 @@ __metadata:
languageName: node
linkType: hard
-"jose@npm:^4.1.4":
- version: 4.5.0
- resolution: "jose@npm:4.5.0"
- checksum: 51142150a9f571ca318842d34ac0daec49fb70bfb6034c68fd46d8c804a8325065876067202310c8ff3cbfc5ca8e44d4712467b4da0d3cadf1e47c96989ca4ca
+"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.9.3
- resolution: "jose@npm:4.9.3"
- checksum: 95865830768dcf82774d19e92dc854c5bc9dc5d9c9626a65a2974272e3aca5d2f56678611943f85802431d2d6d6f8bff9548b7cdb7578e6fe61529bd9c82e1d3
+ version: 4.11.0
+ resolution: "jose@npm:4.11.0"
+ checksum: 8d81e978e0da306911b61b1de1e2d78bd4903b4aa68a4b338b7c89c41edc3d56aea4d5ef4784a078a630dd6aa81f6328901ae3ce215f33b90d51ee8ebf4c9dbd
languageName: node
linkType: hard
@@ -27218,9 +27923,9 @@ __metadata:
languageName: node
linkType: hard
-"jscodeshift@npm:^0.13.0":
- version: 0.13.1
- resolution: "jscodeshift@npm:0.13.1"
+"jscodeshift@npm:^0.14.0":
+ version: 0.14.0
+ resolution: "jscodeshift@npm:0.14.0"
dependencies:
"@babel/core": ^7.13.16
"@babel/parser": ^7.13.16
@@ -27235,17 +27940,17 @@ __metadata:
chalk: ^4.1.2
flow-parser: 0.*
graceful-fs: ^4.2.4
- micromatch: ^3.1.10
+ micromatch: ^4.0.4
neo-async: ^2.5.0
node-dir: ^0.1.17
- recast: ^0.20.4
+ recast: ^0.21.0
temp: ^0.8.4
write-file-atomic: ^2.3.0
peerDependencies:
"@babel/preset-env": ^7.1.6
bin:
jscodeshift: bin/jscodeshift.js
- checksum: 1c35938de5fc29cafec80e2c37d5c3411f85cd5d40e0243b52f2da0c1ab4b659daddfd62de558eca5d562303616f7838097727b651f4ad8e32b1e96f169cdd76
+ checksum: 54ea6d639455883336f80b38a70648821c88b7942315dc0fbab01bc34a9ad0f0f78e3bd69304b5ab167e4262d6ed7e6284c6d32525ab01c89d9118df89b3e2a0
languageName: node
linkType: hard
@@ -27434,15 +28139,15 @@ __metadata:
linkType: hard
"json-schema-library@npm:^7.0.0":
- version: 7.2.1
- resolution: "json-schema-library@npm:7.2.1"
+ version: 7.3.0
+ resolution: "json-schema-library@npm:7.3.0"
dependencies:
deepmerge: ^4.2.2
fast-deep-equal: ^3.1.3
gson-pointer: ^4.1.1
gson-query: ^5.1.0
valid-url: ^1.0.9
- checksum: 65bc4014cdfe22c4f46d6cb0a0c059d94045128fb96189c4823dff653b6788c2dbab8d5d2e8475bbdc65fd47abf19cedcc3f02df608452c5413fea5d6e675003
+ checksum: 3d148d4be1e59e058bd777d247c181e2cb4820f9f5b9c97f7258f88fa73e1c0ed5c8e07c3fef4e1e8e892666def02b2b5fe5366d3d8d2bed09be3752e5593319
languageName: node
linkType: hard
@@ -27566,14 +28271,7 @@ __metadata:
languageName: node
linkType: hard
-"jsonc-parser@npm:^3.0.0":
- version: 3.0.0
- resolution: "jsonc-parser@npm:3.0.0"
- checksum: 1df2326f1f9688de30c70ff19c5b2a83ba3b89a1036160da79821d1361090775e9db502dc57a67c11b56e1186fc1ed70b887f25c5febf9a3ec4f91435836c99d
- 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
@@ -27885,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:
@@ -27904,38 +28592,31 @@ __metadata:
languageName: node
linkType: hard
-"kind-of@npm:^3.0.2, kind-of@npm:^3.0.3, kind-of@npm:^3.2.0":
- version: 3.2.2
- resolution: "kind-of@npm:3.2.2"
+"keyv@npm:^4.5.2":
+ version: 4.5.2
+ resolution: "keyv@npm:4.5.2"
dependencies:
- is-buffer: ^1.1.5
- checksum: e898df8ca2f31038f27d24f0b8080da7be274f986bc6ed176f37c77c454d76627619e1681f6f9d2e8d2fd7557a18ecc419a6bb54e422abcbb8da8f1a75e4b386
+ json-buffer: 3.0.1
+ checksum: 13ad58303acd2261c0d4831b4658451603fd159e61daea2121fcb15feb623e75ee328cded0572da9ca76b7b3ceaf8e614f1806c6b3af5db73c9c35a345259651
languageName: node
linkType: hard
-"kind-of@npm:^4.0.0":
- version: 4.0.0
- resolution: "kind-of@npm:4.0.0"
- dependencies:
- is-buffer: ^1.1.5
- checksum: 1b9e7624a8771b5a2489026e820f3bbbcc67893e1345804a56b23a91e9069965854d2a223a7c6ee563c45be9d8c6ff1ef87f28ed5f0d1a8d00d9dcbb067c529f
- languageName: node
- linkType: hard
-
-"kind-of@npm:^5.0.0":
- version: 5.1.0
- resolution: "kind-of@npm:5.1.0"
- checksum: f2a0102ae0cf19c4a953397e552571bad2b588b53282874f25fca7236396e650e2db50d41f9f516bd402536e4df968dbb51b8e69e4d5d4a7173def78448f7bab
- languageName: node
- linkType: hard
-
-"kind-of@npm:^6.0.0, kind-of@npm:^6.0.2, kind-of@npm:^6.0.3":
+"kind-of@npm:^6.0.2, kind-of@npm:^6.0.3":
version: 6.0.3
resolution: "kind-of@npm:6.0.3"
checksum: 3ab01e7b1d440b22fe4c31f23d8d38b4d9b91d9f291df683476576493d5dfd2e03848a8b05813dd0c3f0e835bc63f433007ddeceb71f05cb25c45ae1b19c6d3b
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"
@@ -28304,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
@@ -28325,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"
@@ -28774,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
@@ -28914,7 +29606,7 @@ __metadata:
languageName: node
linkType: hard
-"map-cache@npm:^0.2.0, map-cache@npm:^0.2.2":
+"map-cache@npm:^0.2.0":
version: 0.2.2
resolution: "map-cache@npm:0.2.2"
checksum: 3067cea54285c43848bb4539f978a15dedc63c03022abeec6ef05c8cb6829f920f13b94bcaf04142fc6a088318e564c4785704072910d120d55dbc2e0c421969
@@ -28942,15 +29634,6 @@ __metadata:
languageName: node
linkType: hard
-"map-visit@npm:^1.0.0":
- version: 1.0.0
- resolution: "map-visit@npm:1.0.0"
- dependencies:
- object-visit: ^1.0.0
- checksum: c27045a5021c344fc19b9132eb30313e441863b2951029f8f8b66f79d3d8c1e7e5091578075a996f74e417479506fe9ede28c44ca7bc351a61c9d8073daec36a
- languageName: node
- linkType: hard
-
"markdown-it-anchor@npm:^8.4.1":
version: 8.6.4
resolution: "markdown-it-anchor@npm:8.6.4"
@@ -29678,27 +30361,6 @@ __metadata:
languageName: node
linkType: hard
-"micromatch@npm:^3.1.10":
- version: 3.1.10
- resolution: "micromatch@npm:3.1.10"
- dependencies:
- arr-diff: ^4.0.0
- array-unique: ^0.3.2
- braces: ^2.3.1
- define-property: ^2.0.2
- extend-shallow: ^3.0.2
- extglob: ^2.0.4
- fragment-cache: ^0.2.1
- kind-of: ^6.0.2
- nanomatch: ^1.2.9
- object.pick: ^1.3.0
- regex-not: ^1.0.0
- snapdragon: ^0.8.1
- to-regex: ^3.0.2
- checksum: ad226cba4daa95b4eaf47b2ca331c8d2e038d7b41ae7ed0697cde27f3f1d6142881ab03d4da51b65d9d315eceb5e4cdddb3fbb55f5f72cfa19cf3ea469d054dc
- languageName: node
- linkType: hard
-
"micromatch@npm:^4.0.2, micromatch@npm:^4.0.4, micromatch@npm:^4.0.5":
version: 4.0.5
resolution: "micromatch@npm:4.0.5"
@@ -29856,12 +30518,12 @@ __metadata:
languageName: node
linkType: hard
-"minimatch@npm:3.0.4":
- version: 3.0.4
- resolution: "minimatch@npm:3.0.4"
+"minimatch@npm:3.1.2, minimatch@npm:^3.0.2, minimatch@npm:^3.0.4, minimatch@npm:^3.0.5, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2":
+ version: 3.1.2
+ resolution: "minimatch@npm:3.1.2"
dependencies:
brace-expansion: ^1.1.7
- checksum: 66ac295f8a7b59788000ea3749938b0970344c841750abd96694f80269b926ebcafad3deeb3f1da2522978b119e6ae3a5869b63b13a7859a456b3408bd18a078
+ checksum: c154e566406683e7bcb746e000b84d74465b3a832c45d59912b9b55cd50dee66e5c4b1e5566dba26154040e51672f9aa450a9aef0c97cfc7336b78b7afb9540a
languageName: node
linkType: hard
@@ -29883,15 +30545,6 @@ __metadata:
languageName: node
linkType: hard
-"minimatch@npm:^3.0.2, minimatch@npm:^3.0.4, minimatch@npm:^3.0.5, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2":
- version: 3.1.2
- resolution: "minimatch@npm:3.1.2"
- dependencies:
- brace-expansion: ^1.1.7
- checksum: c154e566406683e7bcb746e000b84d74465b3a832c45d59912b9b55cd50dee66e5c4b1e5566dba26154040e51672f9aa450a9aef0c97cfc7336b78b7afb9540a
- languageName: node
- linkType: hard
-
"minimist-options@npm:^4.0.2":
version: 4.1.0
resolution: "minimist-options@npm:4.1.0"
@@ -30002,15 +30655,6 @@ __metadata:
languageName: node
linkType: hard
-"minipass@npm:*":
- version: 3.3.4
- resolution: "minipass@npm:3.3.4"
- dependencies:
- yallist: ^4.0.0
- checksum: 5d95a7738c54852ba78d484141e850c792e062666a2d0c681a5ac1021275beb7e1acb077e59f9523ff1defb80901aea4e30fac10ded9a20a25d819a42916ef1b
- languageName: node
- linkType: hard
-
"minipass@npm:^3.0.0, minipass@npm:^3.1.0, minipass@npm:^3.1.1, minipass@npm:^3.1.3, minipass@npm:^3.1.6":
version: 3.1.6
resolution: "minipass@npm:3.1.6"
@@ -30039,16 +30683,6 @@ __metadata:
languageName: node
linkType: hard
-"mixin-deep@npm:^1.2.0":
- version: 1.3.2
- resolution: "mixin-deep@npm:1.3.2"
- dependencies:
- for-in: ^1.0.2
- is-extendable: ^1.0.1
- checksum: 820d5a51fcb7479f2926b97f2c3bb223546bc915e6b3a3eb5d906dda871bba569863595424a76682f2b15718252954644f3891437cb7e3f220949bed54b1750d
- languageName: node
- linkType: hard
-
"mixme@npm:^0.5.1":
version: 0.5.4
resolution: "mixme@npm:0.5.4"
@@ -30109,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
@@ -30199,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
@@ -30230,7 +30864,7 @@ __metadata:
optional: true
bin:
msw: cli/index.js
- checksum: 10ff632641d40384d6622abf4df6399e4ae649db0f676b5d1ee2d0a515ec96f33abe9d4fecba08cdba4b2e43255af419da9eefc020d40a7e10669d0906457197
+ checksum: a931232d18ad02c8b98ffb5db507824d619860743eab6ecf2c228a403b5a20e2b167d4e0ef6cdd7ca2c0d1e4cc913dce1a690e80d7ef3ec6724d3ee060abc477
languageName: node
linkType: hard
@@ -30311,6 +30945,15 @@ __metadata:
languageName: node
linkType: hard
+"nan@npm:^2.17.0":
+ version: 2.17.0
+ resolution: "nan@npm:2.17.0"
+ dependencies:
+ node-gyp: latest
+ checksum: ec609aeaf7e68b76592a3ba96b372aa7f5df5b056c1e37410b0f1deefbab5a57a922061e2c5b369bae9c7c6b5e6eecf4ad2dac8833a1a7d3a751e0a7c7f849ed
+ languageName: node
+ linkType: hard
+
"nano-css@npm:^5.3.1":
version: 5.3.1
resolution: "nano-css@npm:5.3.1"
@@ -30346,25 +30989,6 @@ __metadata:
languageName: node
linkType: hard
-"nanomatch@npm:^1.2.9":
- version: 1.2.13
- resolution: "nanomatch@npm:1.2.13"
- dependencies:
- arr-diff: ^4.0.0
- array-unique: ^0.3.2
- define-property: ^2.0.2
- extend-shallow: ^3.0.2
- fragment-cache: ^0.2.1
- is-windows: ^1.0.2
- kind-of: ^6.0.2
- object.pick: ^1.3.0
- regex-not: ^1.0.0
- snapdragon: ^0.8.1
- to-regex: ^3.0.1
- checksum: 54d4166d6ef08db41252eb4e96d4109ebcb8029f0374f9db873bd91a1f896c32ec780d2a2ea65c0b2d7caf1f28d5e1ea33746a470f32146ac8bba821d80d38d8
- languageName: node
- linkType: hard
-
"napi-build-utils@npm:^1.0.1":
version: 1.0.2
resolution: "napi-build-utils@npm:1.0.2"
@@ -30408,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:
@@ -30513,6 +31144,26 @@ __metadata:
languageName: node
linkType: hard
+"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"
@@ -30634,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"
@@ -30898,17 +31560,6 @@ __metadata:
languageName: node
linkType: hard
-"object-copy@npm:^0.1.0":
- version: 0.1.0
- resolution: "object-copy@npm:0.1.0"
- dependencies:
- copy-descriptor: ^0.1.0
- define-property: ^0.2.5
- kind-of: ^3.0.3
- checksum: a9e35f07e3a2c882a7e979090360d1a20ab51d1fa19dfdac3aa8873b328a7c4c7683946ee97c824ae40079d848d6740a3788fa14f2185155dab7ed970a72c783
- languageName: node
- linkType: hard
-
"object-hash@npm:3.0.0, object-hash@npm:^3.0.0":
version: 3.0.0
resolution: "object-hash@npm:3.0.0"
@@ -30937,15 +31588,6 @@ __metadata:
languageName: node
linkType: hard
-"object-visit@npm:^1.0.0":
- version: 1.0.1
- resolution: "object-visit@npm:1.0.1"
- dependencies:
- isobject: ^3.0.0
- checksum: b0ee07f5bf3bb881b881ff53b467ebbde2b37ebb38649d6944a6cd7681b32eedd99da9bd1e01c55facf81f54ed06b13af61aba6ad87f0052982995e09333f790
- languageName: node
- linkType: hard
-
"object.assign@npm:^4.1.0":
version: 4.1.2
resolution: "object.assign@npm:4.1.2"
@@ -31002,15 +31644,6 @@ __metadata:
languageName: node
linkType: hard
-"object.pick@npm:^1.3.0":
- version: 1.3.0
- resolution: "object.pick@npm:1.3.0"
- dependencies:
- isobject: ^3.0.1
- checksum: 77fb6eed57c67adf75e9901187e37af39f052ef601cb4480386436561357eb9e459e820762f01fd02c5c1b42ece839ad393717a6d1850d848ee11fbabb3e580a
- languageName: node
- linkType: hard
-
"object.values@npm:^1.1.5":
version: 1.1.5
resolution: "object.values@npm:1.1.5"
@@ -31030,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
@@ -31129,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"
@@ -31157,27 +31800,27 @@ __metadata:
languageName: node
linkType: hard
-"openid-client@npm:^5.1.3":
- version: 5.1.10
- resolution: "openid-client@npm:5.1.10"
+"openid-client@npm:^5.1.6":
+ version: 5.2.1
+ resolution: "openid-client@npm:5.2.1"
dependencies:
- jose: ^4.1.4
+ jose: ^4.10.0
lru-cache: ^6.0.0
object-hash: ^2.0.1
oidc-token-hash: ^5.0.1
- checksum: 38a4bf08ea4ee4576043968307cf53f0369df224bd025c1bc348b295152df36c47d2a836dfe1505d15c6b79c05f86aadefad798bd3ea3ccbe90834be01f2245c
+ checksum: b2e9ee8bafb30981fe8eb4446d86578649f05e61d6289abfe79c863578ef8ab24eb4430461c2b8dbb50cbaff89af01e77439df5ebb87c391ed1e336a0e69e590
languageName: node
linkType: hard
-"openid-client@npm:^5.1.6":
- version: 5.1.9
- resolution: "openid-client@npm:5.1.9"
+"openid-client@npm:^5.2.1":
+ version: 5.3.0
+ resolution: "openid-client@npm:5.3.0"
dependencies:
- jose: ^4.1.4
+ jose: ^4.10.0
lru-cache: ^6.0.0
object-hash: ^2.0.1
oidc-token-hash: ^5.0.1
- checksum: 55390a7eceaafdc340a5f2ece576eb4863fcb4cd8840e4a7a1af66bbaf830623b18cf1dd0b8ce472c6f36c6313e78f92db48ca0c10eb8c681a81e5a3d607fc9f
+ checksum: 27faa298e083daae2a2a99629b25cc89f648302f4845dd1acd04ec6e7105a6edf13a5c38ab1159bcb7b88c5bc54be08e021c911e22f0b8bfcca1b2d686ae3d95
languageName: node
linkType: hard
@@ -31717,13 +32360,6 @@ __metadata:
languageName: node
linkType: hard
-"pascalcase@npm:^0.1.1":
- version: 0.1.1
- resolution: "pascalcase@npm:0.1.1"
- checksum: f83681c3c8ff75fa473a2bb2b113289952f802ff895d435edd717e7cb898b0408cbdb247117a938edcbc5d141020909846cc2b92c47213d764e2a94d2ad2b925
- languageName: node
- linkType: hard
-
"passport-auth0@npm:^1.4.3":
version: 1.4.3
resolution: "passport-auth0@npm:1.4.3"
@@ -31860,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"
@@ -31928,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"
@@ -32371,13 +33038,6 @@ __metadata:
languageName: node
linkType: hard
-"posix-character-classes@npm:^0.1.0":
- version: 0.1.1
- resolution: "posix-character-classes@npm:0.1.1"
- checksum: dedb99913c60625a16050cfed2fb5c017648fc075be41ac18474e1c6c3549ef4ada201c8bd9bd006d36827e289c571b6092e1ef6e756cdbab2fd7046b25c6442
- languageName: node
- linkType: hard
-
"postcss-calc@npm:^8.0.0":
version: 8.0.0
resolution: "postcss-calc@npm:8.0.0"
@@ -32799,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
@@ -33639,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:
@@ -33832,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
@@ -34060,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:
@@ -34177,15 +34821,15 @@ __metadata:
linkType: hard
"react-window@npm:^1.8.6":
- version: 1.8.7
- resolution: "react-window@npm:1.8.7"
+ version: 1.8.8
+ resolution: "react-window@npm:1.8.8"
dependencies:
"@babel/runtime": ^7.0.0
memoize-one: ">=3.1.1 <6"
peerDependencies:
react: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0
react-dom: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0
- checksum: 1e122c29224781e70359978287a2e850ccdf509cd71ba16b16ea258725687a62f5c16ab69f52f732b4ed20df583196dbe2a04804f3e4a176bb3e62f3fc910452
+ checksum: a19f43b9015fb84e16db983617dac618a8b298881d2ca96ffc2fb00534afd958ee57a00fd0017733b56f8c34dd84e5be59337877aed3c66329ed3b84e8d018ba
languageName: node
linkType: hard
@@ -34337,7 +34981,7 @@ __metadata:
languageName: node
linkType: hard
-"recast@npm:^0.20.3, recast@npm:^0.20.4":
+"recast@npm:^0.20.3":
version: 0.20.4
resolution: "recast@npm:0.20.4"
dependencies:
@@ -34349,6 +34993,18 @@ __metadata:
languageName: node
linkType: hard
+"recast@npm:^0.21.0":
+ version: 0.21.5
+ resolution: "recast@npm:0.21.5"
+ dependencies:
+ ast-types: 0.15.2
+ esprima: ~4.0.0
+ source-map: ~0.6.1
+ tslib: ^2.0.1
+ checksum: 03cc7f57562238ba258d468be67bf7446ce7a707bc87a087891dad15afead46c36e9aaeedf2130e2ab5a465244a9c62bfd4127849761cf8f4085abe2f3e5f485
+ languageName: node
+ linkType: hard
+
"recharts-scale@npm:^0.4.4":
version: 0.4.5
resolution: "recharts-scale@npm:0.4.5"
@@ -34570,16 +35226,6 @@ __metadata:
languageName: node
linkType: hard
-"regex-not@npm:^1.0.0, regex-not@npm:^1.0.2":
- version: 1.0.2
- resolution: "regex-not@npm:1.0.2"
- dependencies:
- extend-shallow: ^3.0.2
- safe-regex: ^1.1.0
- checksum: 3081403de79559387a35ef9d033740e41818a559512668cef3d12da4e8a29ef34ee13c8ed1256b07e27ae392790172e8a15c8a06b72962fd4550476cde3d8f77
- languageName: node
- linkType: hard
-
"regexp.prototype.flags@npm:^1.4.1, regexp.prototype.flags@npm:^1.4.3":
version: 1.4.3
resolution: "regexp.prototype.flags@npm:1.4.3"
@@ -34768,14 +35414,7 @@ __metadata:
languageName: node
linkType: hard
-"repeat-element@npm:^1.1.2":
- version: 1.1.3
- resolution: "repeat-element@npm:1.1.3"
- checksum: 0743a136b484117016ad587577ede60a3ffe604b74e57bd5d7d0aa041fe2f1c956e6b2f3ff83c86f4db9fac022c3fa2da8e58b9d3618b8b4cb1c3d041bcc422f
- languageName: node
- linkType: hard
-
-"repeat-string@npm:^1.5.2, repeat-string@npm:^1.6.1":
+"repeat-string@npm:^1.5.2":
version: 1.6.1
resolution: "repeat-string@npm:1.6.1"
checksum: 1b809fc6db97decdc68f5b12c4d1a671c8e3f65ec4a40c238bc5200e44e85bcc52a54f78268ab9c29fcf5fe4f1343e805420056d1f30fa9a9ee4c2d93e3cc6c0
@@ -34927,13 +35566,6 @@ __metadata:
languageName: node
linkType: hard
-"resolve-url@npm:^0.2.1":
- version: 0.2.1
- resolution: "resolve-url@npm:0.2.1"
- checksum: 7b7035b9ed6e7bc7d289e90aef1eab5a43834539695dac6416ca6e91f1a94132ae4796bbd173cdacfdc2ade90b5f38a3fb6186bebc1b221cd157777a23b9ad14
- languageName: node
- linkType: hard
-
"resolve.exports@npm:^1.1.0":
version: 1.1.0
resolution: "resolve.exports@npm:1.1.0"
@@ -35103,13 +35735,6 @@ __metadata:
languageName: node
linkType: hard
-"ret@npm:~0.1.10":
- version: 0.1.15
- resolution: "ret@npm:0.1.15"
- checksum: d76a9159eb8c946586567bd934358dfc08a36367b3257f7a3d7255fdd7b56597235af23c6afa0d7f0254159e8051f93c918809962ebd6df24ca2a83dbe4d4151
- languageName: node
- linkType: hard
-
"retry-request@npm:^5.0.0":
version: 5.0.0
resolution: "retry-request@npm:5.0.0"
@@ -35240,8 +35865,8 @@ __metadata:
linkType: hard
"rollup-plugin-esbuild@npm:^4.7.2":
- version: 4.10.1
- resolution: "rollup-plugin-esbuild@npm:4.10.1"
+ version: 4.10.3
+ resolution: "rollup-plugin-esbuild@npm:4.10.3"
dependencies:
"@rollup/pluginutils": ^4.1.1
debug: ^4.3.3
@@ -35251,7 +35876,7 @@ __metadata:
peerDependencies:
esbuild: ">=0.10.1"
rollup: ^1.20.0 || ^2.0.0
- checksum: 8bc7c90c972e00d6757b92d6ee4c04d9b0f34b61659f4c544b3994091bc5fdfe4ffdcbf56999111da39e39e650eb93001d587843e87bc306322d9869afe4d60b
+ checksum: 490a6a77573672cfda64a0222bb0dc2c202060bf4e9162571e24f2c26689e0e9faffced9c409eac80b35943dab06d1f0bd8bb3e2d3c6957b6bac1c0d6e5155cc
languageName: node
linkType: hard
@@ -35369,6 +35994,7 @@ __metadata:
husky: ^8.0.0
lint-staged: ^13.0.0
minimist: ^1.2.5
+ node-gyp: ^9.1.0
prettier: ^2.2.1
semver: ^7.3.2
shx: ^0.3.2
@@ -35475,15 +36101,6 @@ __metadata:
languageName: node
linkType: hard
-"safe-regex@npm:^1.1.0":
- version: 1.1.0
- resolution: "safe-regex@npm:1.1.0"
- dependencies:
- ret: ~0.1.10
- checksum: 9a8bba57c87a841f7997b3b951e8e403b1128c1a4fd1182f40cc1a20e2d490593d7c2a21030fadfea320c8e859219019e136f678c6689ed5960b391b822f01d5
- languageName: node
- linkType: hard
-
"safe-stable-stringify@npm:^2.2.0, safe-stable-stringify@npm:^2.3.1":
version: 2.3.1
resolution: "safe-stable-stringify@npm:2.3.1"
@@ -35628,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:
@@ -35651,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:
@@ -35756,18 +36382,18 @@ __metadata:
linkType: hard
"serve-handler@npm:^6.1.3":
- version: 6.1.3
- resolution: "serve-handler@npm:6.1.3"
+ version: 6.1.5
+ resolution: "serve-handler@npm:6.1.5"
dependencies:
bytes: 3.0.0
content-disposition: 0.5.2
fast-url-parser: 1.1.3
mime-types: 2.1.18
- minimatch: 3.0.4
+ minimatch: 3.1.2
path-is-inside: 1.0.2
path-to-regexp: 2.2.1
range-parser: 1.2.0
- checksum: 384c1bc10add07a554207f918acaa75af47fcfd8fb89e070faa3468ab45ec5bbc9f976e62d659b6b63404edcf5c54efb7e0a48f3f55946eec83b62b283b9837e
+ checksum: 7a98ca9cbf8692583b6cde4deb3941cff900fa38bf16adbfccccd8430209bab781e21d9a1f61c9c03e226f9f67689893bbce25941368f3ddaf985fc3858b49dc
languageName: node
linkType: hard
@@ -35819,18 +36445,6 @@ __metadata:
languageName: node
linkType: hard
-"set-value@npm:^2.0.0, set-value@npm:^2.0.1":
- version: 2.0.1
- resolution: "set-value@npm:2.0.1"
- dependencies:
- extend-shallow: ^2.0.1
- is-extendable: ^0.1.1
- is-plain-object: ^2.0.3
- split-string: ^3.0.1
- checksum: 09a4bc72c94641aeae950eb60dc2755943b863780fcc32e441eda964b64df5e3f50603d5ebdd33394ede722528bd55ed43aae26e9df469b4d32e2292b427b601
- languageName: node
- linkType: hard
-
"set-value@npm:^4.1.0":
version: 4.1.0
resolution: "set-value@npm:4.1.0"
@@ -36026,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"
@@ -36054,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"
@@ -36126,42 +36761,6 @@ __metadata:
languageName: node
linkType: hard
-"snapdragon-node@npm:^2.0.1":
- version: 2.1.1
- resolution: "snapdragon-node@npm:2.1.1"
- dependencies:
- define-property: ^1.0.0
- isobject: ^3.0.0
- snapdragon-util: ^3.0.1
- checksum: 9bb57d759f9e2a27935dbab0e4a790137adebace832b393e350a8bf5db461ee9206bb642d4fe47568ee0b44080479c8b4a9ad0ebe3712422d77edf9992a672fd
- languageName: node
- linkType: hard
-
-"snapdragon-util@npm:^3.0.1":
- version: 3.0.1
- resolution: "snapdragon-util@npm:3.0.1"
- dependencies:
- kind-of: ^3.2.0
- checksum: 684997dbe37ec995c03fd3f412fba2b711fc34cb4010452b7eb668be72e8811a86a12938b511e8b19baf853b325178c56d8b78d655305e5cfb0bb8b21677e7b7
- languageName: node
- linkType: hard
-
-"snapdragon@npm:^0.8.1":
- version: 0.8.2
- resolution: "snapdragon@npm:0.8.2"
- dependencies:
- base: ^0.11.1
- debug: ^2.2.0
- define-property: ^0.2.5
- extend-shallow: ^2.0.1
- map-cache: ^0.2.2
- source-map: ^0.5.6
- source-map-resolve: ^0.5.0
- use: ^3.1.0
- checksum: a197f242a8f48b11036563065b2487e9b7068f50a20dd81d9161eca6af422174fc158b8beeadbe59ce5ef172aa5718143312b3aebaae551c124b7824387c8312
- languageName: node
- linkType: hard
-
"socket.io-adapter@npm:~1.1.0":
version: 1.1.2
resolution: "socket.io-adapter@npm:1.1.2"
@@ -36189,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
@@ -36291,19 +36890,6 @@ __metadata:
languageName: node
linkType: hard
-"source-map-resolve@npm:^0.5.0":
- version: 0.5.3
- resolution: "source-map-resolve@npm:0.5.3"
- dependencies:
- atob: ^2.1.2
- decode-uri-component: ^0.2.0
- resolve-url: ^0.2.1
- source-map-url: ^0.4.0
- urix: ^0.1.0
- checksum: c73fa44ac00783f025f6ad9e038ab1a2e007cd6a6b86f47fe717c3d0765b4a08d264f6966f3bd7cd9dbcd69e4832783d5472e43247775b2a550d6f2155d24bae
- languageName: node
- linkType: hard
-
"source-map-support@npm:0.5.13":
version: 0.5.13
resolution: "source-map-support@npm:0.5.13"
@@ -36324,13 +36910,6 @@ __metadata:
languageName: node
linkType: hard
-"source-map-url@npm:^0.4.0":
- version: 0.4.0
- resolution: "source-map-url@npm:0.4.0"
- checksum: 63ed54045fcd7b4ec7ca17513f48fdc23b573eef679326ecf1a31333e1aaecc0a9c085adaa7d118283b160e65b71cc72da9e1385f2de4ac5ed68294e3920d719
- languageName: node
- linkType: hard
-
"source-map@npm:0.5.6":
version: 0.5.6
resolution: "source-map@npm:0.5.6"
@@ -36338,7 +36917,7 @@ __metadata:
languageName: node
linkType: hard
-"source-map@npm:^0.5.0, source-map@npm:^0.5.6":
+"source-map@npm:^0.5.0":
version: 0.5.7
resolution: "source-map@npm:0.5.7"
checksum: 5dc2043b93d2f194142c7f38f74a24670cd7a0063acdaf4bf01d2964b402257ae843c2a8fa822ad5b71013b5fcafa55af7421383da919752f22ff488bc553f4d
@@ -36472,15 +37051,6 @@ __metadata:
languageName: node
linkType: hard
-"split-string@npm:^3.0.1, split-string@npm:^3.0.2":
- version: 3.1.0
- resolution: "split-string@npm:3.1.0"
- dependencies:
- extend-shallow: ^3.0.0
- checksum: ae5af5c91bdc3633628821bde92fdf9492fa0e8a63cf6a0376ed6afde93c701422a1610916f59be61972717070119e848d10dfbbd5024b7729d6a71972d2a84c
- languageName: node
- linkType: hard
-
"split2@npm:^3.0.0":
version: 3.2.2
resolution: "split2@npm:3.2.2"
@@ -36690,16 +37260,6 @@ __metadata:
languageName: node
linkType: hard
-"static-extend@npm:^0.1.1":
- version: 0.1.2
- resolution: "static-extend@npm:0.1.2"
- dependencies:
- define-property: ^0.2.5
- object-copy: ^0.1.0
- checksum: 8657485b831f79e388a437260baf22784540417a9b29e11572c87735df24c22b84eda42107403a64b30861b2faf13df9f7fc5525d51f9d1d2303aba5cbf4e12c
- languageName: node
- linkType: hard
-
"statuses@npm:2.0.1, statuses@npm:^2.0.0":
version: 2.0.1
resolution: "statuses@npm:2.0.1"
@@ -37166,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:
@@ -37183,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"
@@ -37302,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
@@ -37317,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
@@ -37341,7 +37919,7 @@ __metadata:
peerDependencies:
react: ">=17.0.0"
react-dom: ">=17.0.0"
- checksum: ae8e932ff7eb0b4be71fd1ad7f00ef3eb461636a83985bd36ea28647f60769e6234a9921ff2f84aa33c370f30b8fa1c30a6ca7cf3c4a6ded963aaf9a337aa197
+ checksum: 22a72947da865ebfa9269f66b42c2b50105b6285bcb6546f8f356cf73961f76e397b7d79003641c9569bfb2163ea98e2f3f73a27b5b66843d308786c37362e1c
languageName: node
linkType: hard
@@ -37455,7 +38033,7 @@ __metadata:
languageName: node
linkType: hard
-"tar@npm:^6.0.2, tar@npm:^6.1.0, tar@npm:^6.1.11, tar@npm:^6.1.2":
+"tar@npm:^6.0.2, tar@npm:^6.1.0, tar@npm:^6.1.11":
version: 6.1.11
resolution: "tar@npm:6.1.11"
dependencies:
@@ -37469,6 +38047,20 @@ __metadata:
languageName: node
linkType: hard
+"tar@npm:^6.1.12, tar@npm:^6.1.2":
+ version: 6.1.12
+ resolution: "tar@npm:6.1.12"
+ dependencies:
+ chownr: ^2.0.0
+ fs-minipass: ^2.0.0
+ minipass: ^3.0.0
+ minizlib: ^2.1.1
+ mkdirp: ^1.0.3
+ yallist: ^4.0.0
+ checksum: 49d72e4420944e7ede2782d6b0826a6ede6cdab23c7de63470917e7a78166bc4d5b1a96279d3d79a85f1ba5a17cd37c0acbb3cbff19a07447691445b8b051c55
+ languageName: node
+ linkType: hard
+
"tarn@npm:^3.0.2":
version: 3.0.2
resolution: "tarn@npm:3.0.2"
@@ -37615,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
@@ -37630,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
@@ -37839,25 +38431,6 @@ __metadata:
languageName: node
linkType: hard
-"to-object-path@npm:^0.3.0":
- version: 0.3.0
- resolution: "to-object-path@npm:0.3.0"
- dependencies:
- kind-of: ^3.0.2
- checksum: 9425effee5b43e61d720940fa2b889623f77473d459c2ce3d4a580a4405df4403eec7be6b857455908070566352f9e2417304641ed158dda6f6a365fe3e66d70
- languageName: node
- linkType: hard
-
-"to-regex-range@npm:^2.1.0":
- version: 2.1.1
- resolution: "to-regex-range@npm:2.1.1"
- dependencies:
- is-number: ^3.0.0
- repeat-string: ^1.6.1
- checksum: 46093cc14be2da905cc931e442d280b2e544e2bfdb9a24b3cf821be8d342f804785e5736c108d5be026021a05d7b38144980a61917eee3c88de0a5e710e10320
- languageName: node
- linkType: hard
-
"to-regex-range@npm:^5.0.1":
version: 5.0.1
resolution: "to-regex-range@npm:5.0.1"
@@ -37867,18 +38440,6 @@ __metadata:
languageName: node
linkType: hard
-"to-regex@npm:^3.0.1, to-regex@npm:^3.0.2":
- version: 3.0.2
- resolution: "to-regex@npm:3.0.2"
- dependencies:
- define-property: ^2.0.2
- extend-shallow: ^3.0.2
- regex-not: ^1.0.2
- safe-regex: ^1.1.0
- checksum: 4ed4a619059b64e204aad84e4e5f3ea82d97410988bcece7cf6cbfdbf193d11bff48cf53842d88b8bb00b1bfc0d048f61f20f0709e6f393fd8fe0122662d9db4
- languageName: node
- linkType: hard
-
"toggle-selection@npm:^1.0.6":
version: 1.0.6
resolution: "toggle-selection@npm:1.0.6"
@@ -38140,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
@@ -38577,18 +39138,6 @@ __metadata:
languageName: node
linkType: hard
-"union-value@npm:^1.0.0":
- version: 1.0.1
- resolution: "union-value@npm:1.0.1"
- dependencies:
- arr-union: ^3.1.0
- get-value: ^2.0.6
- is-extendable: ^0.1.1
- set-value: ^2.0.1
- checksum: a3464097d3f27f6aa90cf103ed9387541bccfc006517559381a10e0dffa62f465a9d9a09c9b9c3d26d0f4cbe61d4d010e2fbd710fd4bf1267a768ba8a774b0ba
- languageName: node
- linkType: hard
-
"uniq@npm:^1.0.1":
version: 1.0.1
resolution: "uniq@npm:1.0.1"
@@ -38742,16 +39291,6 @@ __metadata:
languageName: node
linkType: hard
-"unset-value@npm:^1.0.0":
- version: 1.0.0
- resolution: "unset-value@npm:1.0.0"
- dependencies:
- has-value: ^0.3.1
- isobject: ^3.0.0
- checksum: 5990ecf660672be2781fc9fb322543c4aa592b68ed9a3312fa4df0e9ba709d42e823af090fc8f95775b4cd2c9a5169f7388f0cec39238b6d0d55a69fc2ab6b29
- languageName: node
- linkType: hard
-
"untildify@npm:^4.0.0":
version: 4.0.0
resolution: "untildify@npm:4.0.0"
@@ -38814,13 +39353,6 @@ __metadata:
languageName: node
linkType: hard
-"urix@npm:^0.1.0":
- version: 0.1.0
- resolution: "urix@npm:0.1.0"
- checksum: 4c076ecfbf3411e888547fe844e52378ab5ada2d2f27625139011eada79925e77f7fbf0e4016d45e6a9e9adb6b7e64981bd49b22700c7c401c5fc15f423303b3
- languageName: node
- linkType: hard
-
"url-parse@npm:^1.5.8":
version: 1.5.10
resolution: "url-parse@npm:1.5.10"
@@ -38910,13 +39442,6 @@ __metadata:
languageName: node
linkType: hard
-"use@npm:^3.1.0":
- version: 3.1.1
- resolution: "use@npm:3.1.1"
- checksum: 08a130289f5238fcbf8f59a18951286a6e660d17acccc9d58d9b69dfa0ee19aa038e8f95721b00b432c36d1629a9e32a464bf2e7e0ae6a244c42ddb30bdd8b33
- languageName: node
- linkType: hard
-
"utf8-byte-length@npm:^1.0.1":
version: 1.0.4
resolution: "utf8-byte-length@npm:1.0.4"