diff --git a/.changeset/all-my-auth-wanna-ride-today.md b/.changeset/all-my-auth-wanna-ride-today.md new file mode 100644 index 0000000000..40537c30f4 --- /dev/null +++ b/.changeset/all-my-auth-wanna-ride-today.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-components': patch +--- + +Fixed a bug that could prevent auth from working when using the `guest` or `custom` auth providers. diff --git a/.changeset/bright-pumpkins-bake.md b/.changeset/bright-pumpkins-bake.md new file mode 100644 index 0000000000..4c16e307ec --- /dev/null +++ b/.changeset/bright-pumpkins-bake.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend': patch +--- + +Rename output parameter `mergeRequestURL` of `publish:gitlab:merge-request` action to `mergeRequestUrl`. diff --git a/.changeset/clean-dolls-search.md b/.changeset/clean-dolls-search.md new file mode 100644 index 0000000000..a8f0da3c4d --- /dev/null +++ b/.changeset/clean-dolls-search.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-common': patch +--- + +Added permissions for authorizing parameters and steps diff --git a/.changeset/create-app-1679405836.md b/.changeset/create-app-1679405836.md new file mode 100644 index 0000000000..b50d431d4b --- /dev/null +++ b/.changeset/create-app-1679405836.md @@ -0,0 +1,5 @@ +--- +'@backstage/create-app': patch +--- + +Bumped create-app version. diff --git a/.changeset/curly-boats-trade.md b/.changeset/curly-boats-trade.md new file mode 100644 index 0000000000..773d66734c --- /dev/null +++ b/.changeset/curly-boats-trade.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-api-docs': patch +--- + +Corrected styling of nested objects in AsyncAPI to avoid inappropriate uppercase text transformation of nested objects. diff --git a/.changeset/curly-jobs-kneel.md b/.changeset/curly-jobs-kneel.md new file mode 100644 index 0000000000..f313beab88 --- /dev/null +++ b/.changeset/curly-jobs-kneel.md @@ -0,0 +1,8 @@ +--- +'@backstage/plugin-scaffolder': patch +'@backstage/plugin-scaffolder-backend': patch +'@backstage/plugin-scaffolder-node': patch +'@backstage/plugin-scaffolder-react': patch +--- + +Added a possibility to cancel the running task (executing of a scaffolder template) diff --git a/.changeset/curvy-rocks-guess.md b/.changeset/curvy-rocks-guess.md new file mode 100644 index 0000000000..0ce46f787d --- /dev/null +++ b/.changeset/curvy-rocks-guess.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-org': patch +--- + +Allow the title of the group profile card to use the title of the entity, if it is set. diff --git a/.changeset/eleven-bats-tease.md b/.changeset/eleven-bats-tease.md new file mode 100644 index 0000000000..732055ca52 --- /dev/null +++ b/.changeset/eleven-bats-tease.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-kubernetes-backend': minor +--- + +**BREAKING**: `KubernetesBuilder.create` now requires a `permissions` field of type `PermissionEvaluator`. The kubernetes `/proxy` endpoint now requires two tokens: the `Backstage-Kubernetes-Authorization` header should contain a bearer token for the target cluster, and the `Authorization` header should contain a backstage identity token. The kubernetes `/proxy` endpoint now requires a `Backstage-Kubernetes-Cluster` header replacing the previously required `X-Kubernetes-Cluster` header. diff --git a/.changeset/eleven-coats-refuse.md b/.changeset/eleven-coats-refuse.md new file mode 100644 index 0000000000..a7589ff733 --- /dev/null +++ b/.changeset/eleven-coats-refuse.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Support importing `.md` files in build loader diff --git a/.changeset/fair-roses-stare.md b/.changeset/fair-roses-stare.md new file mode 100644 index 0000000000..358765e092 --- /dev/null +++ b/.changeset/fair-roses-stare.md @@ -0,0 +1,14 @@ +--- +'@backstage/plugin-scaffolder': patch +--- + +Allow use of `{ exists: true }` value inside filters to filter entities that has that key. + +this example will filter all entities that has the annotation `someAnnotation` set to any value. + +```yaml +ui:options: + catalogFilter: + kind: Group + metadata.annotations.someAnnotation: { exists: true } +``` diff --git a/.changeset/fast-snakes-buy.md b/.changeset/fast-snakes-buy.md new file mode 100644 index 0000000000..711588918d --- /dev/null +++ b/.changeset/fast-snakes-buy.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-entity-feedback': minor +'@backstage/plugin-entity-feedback-backend': patch +'@backstage/plugin-entity-feedback-common': patch +--- + +Added an endpoint to fetch anonymous aggregated results from an entity diff --git a/.changeset/fresh-schools-fly.md b/.changeset/fresh-schools-fly.md new file mode 100644 index 0000000000..e364e08d43 --- /dev/null +++ b/.changeset/fresh-schools-fly.md @@ -0,0 +1,11 @@ +--- +'@backstage/plugin-catalog-backend-module-gitlab': minor +--- + +**BREAKING**: The configuration of the `GitlabDiscoveryEntityProvider` has changed as follows: + +- The configuration key `branch` is now used to define the branch from which the catalog-info should be discovered. +- The old configuration key `branch` is now called `fallbackBranch`. This value specifies which branch should be used + if no default branch is defined on the project itself. + +To migrate to the new configuration value, rename `branch` to `fallbackBranch` diff --git a/.changeset/funny-pots-hide.md b/.changeset/funny-pots-hide.md new file mode 100644 index 0000000000..32388a93a5 --- /dev/null +++ b/.changeset/funny-pots-hide.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-search-backend': minor +--- + +Exports search plugin that can be used with the new backend system. For documentation on how to migrate, check out the [how to migrate to the new backend system guide](../docs/features/search/how-to-guides.md#how-to-migrate-to-use-search-together-with-the-new-backend-system). diff --git a/.changeset/funny-rivers-grin.md b/.changeset/funny-rivers-grin.md new file mode 100644 index 0000000000..55463e40a7 --- /dev/null +++ b/.changeset/funny-rivers-grin.md @@ -0,0 +1,5 @@ +--- +'@backstage/create-app': patch +--- + +Add `permissionApi` as dependency of the scaffolder-backend plugin diff --git a/.changeset/fuzzy-actors-turn.md b/.changeset/fuzzy-actors-turn.md new file mode 100644 index 0000000000..bd92ad34ef --- /dev/null +++ b/.changeset/fuzzy-actors-turn.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-kubernetes-backend': patch +--- + +Fixes bug whereby backstage crashes when bad credentials are provided to the kubernetes plugin. diff --git a/.changeset/fuzzy-wombats-search.md b/.changeset/fuzzy-wombats-search.md new file mode 100644 index 0000000000..693e42399a --- /dev/null +++ b/.changeset/fuzzy-wombats-search.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend': minor +--- + +Added `fetch:plain:file` action to fetch a single file, this action is also added to the list of built-in actions. diff --git a/.changeset/giant-hairs-serve.md b/.changeset/giant-hairs-serve.md new file mode 100644 index 0000000000..0f77a6fe34 --- /dev/null +++ b/.changeset/giant-hairs-serve.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-search-backend-module-elasticsearch': minor +'@backstage/plugin-search-backend-module-pg': patch +--- + +Search backend modules migrated to the new backend system. For documentation on how to migrate, check out the [how to migrate to the new backend system guide](../docs/features/search/how-to-guides.md#how-to-migrate-to-use-search-together-with-the-new-backend-system). diff --git a/.changeset/heavy-colts-wash.md b/.changeset/heavy-colts-wash.md new file mode 100644 index 0000000000..c22cb70dbf --- /dev/null +++ b/.changeset/heavy-colts-wash.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-common': patch +--- + +Export `typeguard` for `isTemplateEntityV1beta3` diff --git a/.changeset/hungry-lies-cry.md b/.changeset/hungry-lies-cry.md new file mode 100644 index 0000000000..712aef6172 --- /dev/null +++ b/.changeset/hungry-lies-cry.md @@ -0,0 +1,8 @@ +--- +'@backstage/plugin-catalog-backend-module-gitlab': patch +--- + +The gitlab org data integration now makes use of the GraphQL API to determine +the relationships between imported User and Group entities, effectively making +this integration usable without an administrator account's Personal Access +Token. diff --git a/.changeset/hungry-monkeys-reply.md b/.changeset/hungry-monkeys-reply.md new file mode 100644 index 0000000000..c7f5d54ea1 --- /dev/null +++ b/.changeset/hungry-monkeys-reply.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog': minor +--- + +Added a new EntitySwitch isResourceType to allow different views depending on Resource type diff --git a/.changeset/khaki-cars-drum.md b/.changeset/khaki-cars-drum.md new file mode 100644 index 0000000000..325b0f8ba5 --- /dev/null +++ b/.changeset/khaki-cars-drum.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-auth-backend': patch +--- + +Enforce the secret visibility of certificates and client secrets in the auth backend. Also, document all known options for each auth plugin. diff --git a/.changeset/khaki-guests-turn.md b/.changeset/khaki-guests-turn.md new file mode 100644 index 0000000000..5676236aae --- /dev/null +++ b/.changeset/khaki-guests-turn.md @@ -0,0 +1,9 @@ +--- +'@backstage/plugin-catalog-backend-module-msgraph': patch +'@backstage/plugin-catalog-backend-module-openapi': patch +'@backstage/plugin-catalog-backend-module-ldap': patch +'@backstage/plugin-scaffolder-backend': patch +'@backstage/plugin-catalog-backend': patch +--- + +Fix deprecated types. diff --git a/.changeset/lazy-apples-destroy.md b/.changeset/lazy-apples-destroy.md new file mode 100644 index 0000000000..43fcfbae85 --- /dev/null +++ b/.changeset/lazy-apples-destroy.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-scaffolder-react': patch +'@backstage/plugin-scaffolder': patch +--- + +`scaffolder/next`: Bump `@rjsf/*` deps to 5.3.1 diff --git a/.changeset/lazy-monkeys-worry.md b/.changeset/lazy-monkeys-worry.md new file mode 100644 index 0000000000..9dc3ea514e --- /dev/null +++ b/.changeset/lazy-monkeys-worry.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-tech-insights': patch +--- + +The `Check` type now optionally includes the `failureMetadata` and `successMetadata` as returned by the `runChecks` call. diff --git a/.changeset/long-gorillas-remain.md b/.changeset/long-gorillas-remain.md new file mode 100644 index 0000000000..60ad6fa092 --- /dev/null +++ b/.changeset/long-gorillas-remain.md @@ -0,0 +1,9 @@ +--- +'@backstage/core-components': patch +'@backstage/app-defaults': minor +'@backstage/core-app-api': minor +'@backstage/plugin-auth-backend': patch +'@backstage/test-utils': minor +--- + +Introduce a new global config parameter, `auth.enableExperimentalRedirectFlow`. When enabled, auth will happen with an in-window redirect flow rather than through a popup window. diff --git a/.changeset/many-eggs-press.md b/.changeset/many-eggs-press.md new file mode 100644 index 0000000000..551cf9e759 --- /dev/null +++ b/.changeset/many-eggs-press.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-search-react': patch +'@backstage/plugin-techdocs': patch +--- + +Fixes a UI bug in search result item which rendered the item text with incorrect font size and color diff --git a/.changeset/mighty-lamps-cross.md b/.changeset/mighty-lamps-cross.md new file mode 100644 index 0000000000..af09263f2e --- /dev/null +++ b/.changeset/mighty-lamps-cross.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Fixed backend start command on Windows by removing the use of platform dependent path joins. diff --git a/.changeset/nasty-nails-appear.md b/.changeset/nasty-nails-appear.md new file mode 100644 index 0000000000..fdb35f052c --- /dev/null +++ b/.changeset/nasty-nails-appear.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-gitlab': minor +--- + +Add Gitlab Scaffolder Plugin diff --git a/.changeset/neat-donkeys-work.md b/.changeset/neat-donkeys-work.md new file mode 100644 index 0000000000..dfa3236d43 --- /dev/null +++ b/.changeset/neat-donkeys-work.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': minor +--- + +scaffolder/next: removing the `routeRefs` and exporting the originals on `scaffolderPlugin.routes.x` instead diff --git a/.changeset/odd-grapes-double.md b/.changeset/odd-grapes-double.md new file mode 100644 index 0000000000..7ef7486b60 --- /dev/null +++ b/.changeset/odd-grapes-double.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-permission-node': patch +--- + +Added createConditionAuthorizer utility function, which takes some permission conditions and returns a function that returns a definitive authorization result given a decision and a resource. diff --git a/.changeset/olive-months-talk.md b/.changeset/olive-months-talk.md new file mode 100644 index 0000000000..b3a89d1f9e --- /dev/null +++ b/.changeset/olive-months-talk.md @@ -0,0 +1,8 @@ +--- +'@backstage/plugin-scaffolder-backend': minor +--- + +Added the possibility to authorize parameters and steps of a template + +The scaffolder plugin is now integrated with the permission framework. +It is possible to toggle parameters or actions within templates by marking each section with specific `tags`, inside a `backstage:permissions` property under each parameter or action. Each parameter or action can then be permissioned by using a conditional decision containing the `scaffolderTemplateRules.hasTag` rule. diff --git a/.changeset/orange-rabbits-jam.md b/.changeset/orange-rabbits-jam.md new file mode 100644 index 0000000000..fb60813c7d --- /dev/null +++ b/.changeset/orange-rabbits-jam.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +Add full text search support to the `by-query` endpoint. diff --git a/.changeset/pre.json b/.changeset/pre.json new file mode 100644 index 0000000000..042939035f --- /dev/null +++ b/.changeset/pre.json @@ -0,0 +1,262 @@ +{ + "mode": "pre", + "tag": "next", + "initialVersions": { + "example-app": "0.2.81", + "@backstage/app-defaults": "1.2.1", + "example-backend": "0.2.81", + "@backstage/backend-app-api": "0.4.1", + "@backstage/backend-common": "0.18.3", + "@backstage/backend-defaults": "0.1.8", + "@backstage/backend-dev-utils": "0.1.1", + "example-backend-next": "0.0.9", + "@backstage/backend-plugin-api": "0.5.0", + "@backstage/backend-tasks": "0.5.0", + "@backstage/backend-test-utils": "0.1.35", + "@backstage/catalog-client": "1.4.0", + "@backstage/catalog-model": "1.2.1", + "@backstage/cli": "0.22.4", + "@backstage/cli-common": "0.1.12", + "@backstage/codemods": "0.1.44", + "@backstage/config": "1.0.7", + "@backstage/config-loader": "1.1.9", + "@backstage/core-app-api": "1.6.0", + "@backstage/core-components": "0.12.5", + "@backstage/core-plugin-api": "1.5.0", + "@backstage/create-app": "0.4.38", + "@backstage/dev-utils": "1.0.13", + "e2e-test": "0.2.1", + "@backstage/errors": "1.1.5", + "@backstage/eslint-plugin": "0.1.2", + "@backstage/integration": "1.4.3", + "@backstage/integration-aws-node": "0.1.2", + "@backstage/integration-react": "1.1.11", + "@backstage/release-manifests": "0.0.9", + "@backstage/repo-tools": "0.1.3", + "@techdocs/cli": "1.4.0", + "techdocs-cli-embedded-app": "0.2.80", + "@backstage/test-utils": "1.2.6", + "@backstage/theme": "0.2.18", + "@backstage/types": "1.0.2", + "@backstage/version-bridge": "1.0.3", + "@backstage/plugin-adr": "0.4.1", + "@backstage/plugin-adr-backend": "0.3.1", + "@backstage/plugin-adr-common": "0.2.7", + "@backstage/plugin-airbrake": "0.3.16", + "@backstage/plugin-airbrake-backend": "0.2.16", + "@backstage/plugin-allure": "0.1.32", + "@backstage/plugin-analytics-module-ga": "0.1.27", + "@backstage/plugin-apache-airflow": "0.2.9", + "@backstage/plugin-api-docs": "0.9.1", + "@backstage/plugin-api-docs-module-protoc-gen-doc": "0.1.1", + "@backstage/plugin-apollo-explorer": "0.1.9", + "@backstage/plugin-app-backend": "0.3.43", + "@backstage/plugin-auth-backend": "0.18.1", + "@backstage/plugin-auth-node": "0.2.12", + "@backstage/plugin-azure-devops": "0.2.7", + "@backstage/plugin-azure-devops-backend": "0.3.22", + "@backstage/plugin-azure-devops-common": "0.3.0", + "@backstage/plugin-azure-sites": "0.1.5", + "@backstage/plugin-azure-sites-backend": "0.1.5", + "@backstage/plugin-azure-sites-common": "0.1.0", + "@backstage/plugin-badges": "0.2.40", + "@backstage/plugin-badges-backend": "0.1.37", + "@backstage/plugin-bazaar": "0.2.6", + "@backstage/plugin-bazaar-backend": "0.2.6", + "@backstage/plugin-bitbucket-cloud-common": "0.2.4", + "@backstage/plugin-bitrise": "0.1.43", + "@backstage/plugin-catalog": "1.9.0", + "@backstage/plugin-catalog-backend": "1.8.0", + "@backstage/plugin-catalog-backend-module-aws": "0.1.17", + "@backstage/plugin-catalog-backend-module-azure": "0.1.14", + "@backstage/plugin-catalog-backend-module-bitbucket": "0.2.10", + "@backstage/plugin-catalog-backend-module-bitbucket-cloud": "0.1.10", + "@backstage/plugin-catalog-backend-module-bitbucket-server": "0.1.8", + "@backstage/plugin-catalog-backend-module-gerrit": "0.1.11", + "@backstage/plugin-catalog-backend-module-github": "0.2.6", + "@backstage/plugin-catalog-backend-module-gitlab": "0.1.14", + "@backstage/plugin-catalog-backend-module-incremental-ingestion": "0.3.0", + "@backstage/plugin-catalog-backend-module-ldap": "0.5.10", + "@backstage/plugin-catalog-backend-module-msgraph": "0.5.2", + "@backstage/plugin-catalog-backend-module-openapi": "0.1.9", + "@backstage/plugin-catalog-backend-module-puppetdb": "0.1.0", + "@backstage/plugin-catalog-common": "1.0.12", + "@internal/plugin-catalog-customized": "0.0.8", + "@backstage/plugin-catalog-graph": "0.2.28", + "@backstage/plugin-catalog-graphql": "0.3.19", + "@backstage/plugin-catalog-import": "0.9.6", + "@backstage/plugin-catalog-node": "1.3.4", + "@backstage/plugin-catalog-react": "1.4.0", + "@backstage/plugin-cicd-statistics": "0.1.18", + "@backstage/plugin-cicd-statistics-module-gitlab": "0.1.12", + "@backstage/plugin-circleci": "0.3.16", + "@backstage/plugin-cloudbuild": "0.3.16", + "@backstage/plugin-code-climate": "0.1.16", + "@backstage/plugin-code-coverage": "0.2.9", + "@backstage/plugin-code-coverage-backend": "0.2.9", + "@backstage/plugin-codescene": "0.1.11", + "@backstage/plugin-config-schema": "0.1.39", + "@backstage/plugin-cost-insights": "0.12.5", + "@backstage/plugin-cost-insights-common": "0.1.1", + "@backstage/plugin-dynatrace": "3.0.0", + "@backstage/plugin-entity-feedback": "0.1.1", + "@backstage/plugin-entity-feedback-backend": "0.1.1", + "@backstage/plugin-entity-feedback-common": "0.1.0", + "@backstage/plugin-entity-validation": "0.1.1", + "@backstage/plugin-events-backend": "0.2.4", + "@backstage/plugin-events-backend-module-aws-sqs": "0.1.5", + "@backstage/plugin-events-backend-module-azure": "0.1.5", + "@backstage/plugin-events-backend-module-bitbucket-cloud": "0.1.5", + "@backstage/plugin-events-backend-module-gerrit": "0.1.5", + "@backstage/plugin-events-backend-module-github": "0.1.5", + "@backstage/plugin-events-backend-module-gitlab": "0.1.5", + "@backstage/plugin-events-backend-test-utils": "0.1.5", + "@backstage/plugin-events-node": "0.2.4", + "@internal/plugin-todo-list": "1.0.11", + "@internal/plugin-todo-list-backend": "1.0.11", + "@internal/plugin-todo-list-common": "1.0.9", + "@backstage/plugin-explore": "0.4.1", + "@backstage/plugin-explore-backend": "0.0.5", + "@backstage/plugin-explore-common": "0.0.1", + "@backstage/plugin-explore-react": "0.0.27", + "@backstage/plugin-firehydrant": "0.2.0", + "@backstage/plugin-fossa": "0.2.48", + "@backstage/plugin-gcalendar": "0.3.12", + "@backstage/plugin-gcp-projects": "0.3.35", + "@backstage/plugin-git-release-manager": "0.3.29", + "@backstage/plugin-github-actions": "0.5.16", + "@backstage/plugin-github-deployments": "0.1.47", + "@backstage/plugin-github-issues": "0.2.5", + "@backstage/plugin-github-pull-requests-board": "0.1.10", + "@backstage/plugin-gitops-profiles": "0.3.34", + "@backstage/plugin-gocd": "0.1.22", + "@backstage/plugin-graphiql": "0.2.48", + "@backstage/plugin-graphql-backend": "0.1.33", + "@backstage/plugin-graphql-voyager": "0.1.1", + "@backstage/plugin-home": "0.4.32", + "@backstage/plugin-ilert": "0.2.5", + "@backstage/plugin-jenkins": "0.7.15", + "@backstage/plugin-jenkins-backend": "0.1.33", + "@backstage/plugin-jenkins-common": "0.1.14", + "@backstage/plugin-kafka": "0.3.16", + "@backstage/plugin-kafka-backend": "0.2.36", + "@backstage/plugin-kubernetes": "0.7.9", + "@backstage/plugin-kubernetes-backend": "0.9.4", + "@backstage/plugin-kubernetes-common": "0.6.1", + "@backstage/plugin-lighthouse": "0.4.1", + "@backstage/plugin-lighthouse-backend": "0.1.1", + "@backstage/plugin-lighthouse-common": "0.1.1", + "@backstage/plugin-linguist": "0.1.1", + "@backstage/plugin-linguist-backend": "0.2.0", + "@backstage/plugin-linguist-common": "0.1.0", + "@backstage/plugin-microsoft-calendar": "0.1.1", + "@backstage/plugin-newrelic": "0.3.34", + "@backstage/plugin-newrelic-dashboard": "0.2.9", + "@backstage/plugin-octopus-deploy": "0.1.0", + "@backstage/plugin-org": "0.6.6", + "@backstage/plugin-org-react": "0.1.5", + "@backstage/plugin-pagerduty": "0.5.9", + "@backstage/plugin-periskop": "0.1.14", + "@backstage/plugin-periskop-backend": "0.1.14", + "@backstage/plugin-permission-backend": "0.5.18", + "@backstage/plugin-permission-common": "0.7.4", + "@backstage/plugin-permission-node": "0.7.6", + "@backstage/plugin-permission-react": "0.4.11", + "@backstage/plugin-playlist": "0.1.7", + "@backstage/plugin-playlist-backend": "0.2.6", + "@backstage/plugin-playlist-common": "0.1.5", + "@backstage/plugin-proxy-backend": "0.2.37", + "@backstage/plugin-rollbar": "0.4.16", + "@backstage/plugin-rollbar-backend": "0.1.40", + "@backstage/plugin-scaffolder": "1.12.0", + "@backstage/plugin-scaffolder-backend": "1.12.0", + "@backstage/plugin-scaffolder-backend-module-cookiecutter": "0.2.18", + "@backstage/plugin-scaffolder-backend-module-rails": "0.4.11", + "@backstage/plugin-scaffolder-backend-module-sentry": "0.1.3", + "@backstage/plugin-scaffolder-backend-module-yeoman": "0.2.16", + "@backstage/plugin-scaffolder-common": "1.2.6", + "@backstage/plugin-scaffolder-node": "0.1.1", + "@backstage/plugin-scaffolder-react": "1.2.0", + "@backstage/plugin-search": "1.1.1", + "@backstage/plugin-search-backend": "1.2.4", + "@backstage/plugin-search-backend-module-elasticsearch": "1.1.4", + "@backstage/plugin-search-backend-module-pg": "0.5.4", + "@backstage/plugin-search-backend-node": "1.1.4", + "@backstage/plugin-search-common": "1.2.2", + "@backstage/plugin-search-react": "1.5.1", + "@backstage/plugin-sentry": "0.5.1", + "@backstage/plugin-shortcuts": "0.3.8", + "@backstage/plugin-sonarqube": "0.6.5", + "@backstage/plugin-sonarqube-backend": "0.1.8", + "@backstage/plugin-sonarqube-react": "0.1.4", + "@backstage/plugin-splunk-on-call": "0.4.5", + "@backstage/plugin-stack-overflow": "0.1.12", + "@backstage/plugin-stack-overflow-backend": "0.1.12", + "@backstage/plugin-stackstorm": "0.1.0", + "@backstage/plugin-tech-insights": "0.3.8", + "@backstage/plugin-tech-insights-backend": "0.5.9", + "@backstage/plugin-tech-insights-backend-module-jsonfc": "0.1.27", + "@backstage/plugin-tech-insights-common": "0.2.10", + "@backstage/plugin-tech-insights-node": "0.4.1", + "@backstage/plugin-tech-radar": "0.6.2", + "@backstage/plugin-techdocs": "1.6.0", + "@backstage/plugin-techdocs-addons-test-utils": "1.0.11", + "@backstage/plugin-techdocs-backend": "1.6.0", + "@backstage/plugin-techdocs-module-addons-contrib": "1.0.11", + "@backstage/plugin-techdocs-node": "1.6.0", + "@backstage/plugin-techdocs-react": "1.1.4", + "@backstage/plugin-todo": "0.2.18", + "@backstage/plugin-todo-backend": "0.1.40", + "@backstage/plugin-user-settings": "0.7.1", + "@backstage/plugin-user-settings-backend": "0.1.7", + "@backstage/plugin-vault": "0.1.10", + "@backstage/plugin-vault-backend": "0.2.10", + "@backstage/plugin-xcmetrics": "0.2.36", + "@backstage/plugin-scaffolder-backend-module-gitlab": "0.0.0" + }, + "changesets": [ + "bright-pumpkins-bake", + "create-app-1679405836", + "curly-boats-trade", + "curly-jobs-kneel", + "eleven-bats-tease", + "fair-roses-stare", + "fast-snakes-buy", + "fresh-schools-fly", + "fuzzy-actors-turn", + "heavy-colts-wash", + "hungry-lies-cry", + "hungry-monkeys-reply", + "khaki-cars-drum", + "khaki-doors-compare", + "khaki-guests-turn", + "lazy-apples-destroy", + "lazy-monkeys-worry", + "long-gorillas-remain", + "many-eggs-press", + "mighty-lamps-cross", + "nasty-nails-appear", + "neat-donkeys-work", + "old-cougars-sit", + "orange-rabbits-jam", + "rare-seals-decide", + "renovate-a9116b7", + "renovate-c574b04", + "rotten-carrots-cheer", + "seven-gifts-fetch", + "short-panthers-float", + "soft-roses-cover", + "sour-dragons-cheat", + "strong-crews-repeat", + "swift-meals-live", + "ten-hounds-bathe", + "ten-mayflies-beam", + "thick-forks-prove", + "thin-spoons-prove", + "thirty-crabs-tell", + "twelve-parrots-camp", + "weak-turtles-arrive", + "wise-garlics-camp", + "witty-berries-love" + ] +} diff --git a/.changeset/pretty-carpets-cross.md b/.changeset/pretty-carpets-cross.md new file mode 100644 index 0000000000..e479ab5bda --- /dev/null +++ b/.changeset/pretty-carpets-cross.md @@ -0,0 +1,11 @@ +--- +'@backstage/plugin-analytics-module-ga': patch +'@backstage/plugin-apollo-explorer': patch +'@backstage/plugin-adr-backend': patch +'@backstage/plugin-dynatrace': patch +'@backstage/plugin-airbrake': patch +'@backstage/plugin-circleci': patch +'@backstage/plugin-adr': patch +--- + +chore: Improve API Reference documentation diff --git a/.changeset/rare-seals-decide.md b/.changeset/rare-seals-decide.md new file mode 100644 index 0000000000..e3cbadee69 --- /dev/null +++ b/.changeset/rare-seals-decide.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs-react': patch +--- + +Fix a bug that caused the header to not render when generating a document for the first time diff --git a/.changeset/renovate-179fa0e.md b/.changeset/renovate-179fa0e.md new file mode 100644 index 0000000000..57efcc4d83 --- /dev/null +++ b/.changeset/renovate-179fa0e.md @@ -0,0 +1,16 @@ +--- +'@backstage/core-components': patch +'@backstage/plugin-entity-validation': patch +'@backstage/integration-react': patch +'@backstage/plugin-apollo-explorer': patch +'@backstage/plugin-github-issues': patch +'@backstage/plugin-stackstorm': patch +'@backstage/plugin-codescene': patch +'@backstage/plugin-org-react': patch +'@backstage/plugin-linguist': patch +'@backstage/plugin-playlist': patch +'@backstage/plugin-vault': patch +'@backstage/cli': patch +--- + +Updated dependency `@material-ui/lab` to `4.0.0-alpha.61`. diff --git a/.changeset/renovate-a9116b7.md b/.changeset/renovate-a9116b7.md new file mode 100644 index 0000000000..168230442e --- /dev/null +++ b/.changeset/renovate-a9116b7.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-scaffolder-react': patch +'@backstage/plugin-scaffolder': patch +--- + +Updated dependency `@rjsf/validator-ajv8` to `5.3.0`. diff --git a/.changeset/renovate-c574b04.md b/.changeset/renovate-c574b04.md new file mode 100644 index 0000000000..e409c71940 --- /dev/null +++ b/.changeset/renovate-c574b04.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-catalog-graphql': patch +'@backstage/plugin-graphql-backend': patch +--- + +Updated dependency `@apollo/server` to `^4.0.0`. diff --git a/.changeset/rotten-carrots-cheer.md b/.changeset/rotten-carrots-cheer.md new file mode 100644 index 0000000000..58da6d2a21 --- /dev/null +++ b/.changeset/rotten-carrots-cheer.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-app-api': patch +--- + +Register unhandled rejection and uncaught exception handlers to avoid backend crashes. diff --git a/.changeset/seven-gifts-fetch.md b/.changeset/seven-gifts-fetch.md new file mode 100644 index 0000000000..acb66e2d18 --- /dev/null +++ b/.changeset/seven-gifts-fetch.md @@ -0,0 +1,72 @@ +--- +'@backstage/plugin-techdocs-module-addons-contrib': patch +'@backstage/plugin-github-pull-requests-board': patch +'@backstage/plugin-techdocs-addons-test-utils': patch +'@backstage/plugin-analytics-module-ga': patch +'@backstage/plugin-git-release-manager': patch +'@backstage/plugin-github-deployments': patch +'@backstage/plugin-newrelic-dashboard': patch +'@backstage/core-components': patch +'@backstage/plugin-scaffolder-react': patch +'@backstage/plugin-cicd-statistics': patch +'@backstage/plugin-entity-feedback': patch +'@backstage/plugin-gitops-profiles': patch +'@backstage/plugin-graphql-voyager': patch +'@backstage/plugin-apache-airflow': patch +'@backstage/plugin-catalog-import': patch +'@backstage/plugin-github-actions': patch +'@backstage/plugin-octopus-deploy': patch +'@backstage/plugin-splunk-on-call': patch +'@backstage/plugin-techdocs-react': patch +'@backstage/plugin-catalog-graph': patch +'@backstage/plugin-catalog-react': patch +'@backstage/plugin-code-coverage': patch +'@backstage/plugin-config-schema': patch +'@backstage/plugin-cost-insights': patch +'@backstage/plugin-tech-insights': patch +'@backstage/plugin-user-settings': patch +'@backstage/plugin-azure-devops': patch +'@backstage/plugin-code-climate': patch +'@backstage/plugin-gcp-projects': patch +'@backstage/plugin-search-react': patch +'@backstage/plugin-azure-sites': patch +'@backstage/plugin-firehydrant': patch +'@backstage/plugin-cloudbuild': patch +'@backstage/plugin-kubernetes': patch +'@backstage/plugin-lighthouse': patch +'@backstage/plugin-scaffolder': patch +'@backstage/plugin-tech-radar': patch +'@backstage/plugin-dynatrace': patch +'@backstage/plugin-gcalendar': patch +'@backstage/plugin-pagerduty': patch +'@backstage/plugin-shortcuts': patch +'@backstage/plugin-sonarqube': patch +'@backstage/plugin-xcmetrics': patch +'@backstage/plugin-airbrake': patch +'@backstage/plugin-api-docs': patch +'@backstage/plugin-circleci': patch +'@backstage/plugin-graphiql': patch +'@backstage/plugin-newrelic': patch +'@backstage/plugin-periskop': patch +'@backstage/plugin-techdocs': patch +'@backstage/plugin-bitrise': patch +'@backstage/plugin-catalog': patch +'@backstage/plugin-explore': patch +'@backstage/plugin-jenkins': patch +'@backstage/plugin-rollbar': patch +'@backstage/plugin-allure': patch +'@backstage/plugin-badges': patch +'@backstage/plugin-bazaar': patch +'@backstage/plugin-search': patch +'@backstage/plugin-sentry': patch +'@backstage/plugin-fossa': patch +'@backstage/plugin-ilert': patch +'@backstage/plugin-kafka': patch +'@backstage/plugin-gocd': patch +'@backstage/plugin-home': patch +'@backstage/plugin-todo': patch +'@backstage/plugin-adr': patch +'@backstage/plugin-org': patch +--- + +Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) diff --git a/.changeset/short-panthers-float.md b/.changeset/short-panthers-float.md new file mode 100644 index 0000000000..91eafe28aa --- /dev/null +++ b/.changeset/short-panthers-float.md @@ -0,0 +1,5 @@ +--- +'@techdocs/cli': patch +--- + +Adding global-agent to enable the ability to publish through a proxy diff --git a/.changeset/silly-adults-accept.md b/.changeset/silly-adults-accept.md new file mode 100644 index 0000000000..9db04d2490 --- /dev/null +++ b/.changeset/silly-adults-accept.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +Allow replacement of the BuiltinKindsEntityProcessor which enables customization of schema validation and connections emitted. diff --git a/.changeset/soft-roses-cover.md b/.changeset/soft-roses-cover.md new file mode 100644 index 0000000000..94cbe6d0bd --- /dev/null +++ b/.changeset/soft-roses-cover.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog': minor +--- + +Added `isEntityWith` condition helper for `EntitySwitch` case statements. diff --git a/.changeset/sour-dragons-cheat.md b/.changeset/sour-dragons-cheat.md new file mode 100644 index 0000000000..1b577d85f7 --- /dev/null +++ b/.changeset/sour-dragons-cheat.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Add `onboard` command. While still in development, this command aims to guide users in setting up their Backstage App. diff --git a/.changeset/strong-crews-repeat.md b/.changeset/strong-crews-repeat.md new file mode 100644 index 0000000000..1e772ae036 --- /dev/null +++ b/.changeset/strong-crews-repeat.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-shortcuts': patch +--- + +Allow external links to be added as shortcuts diff --git a/.changeset/swift-meals-live.md b/.changeset/swift-meals-live.md new file mode 100644 index 0000000000..ad8106b04e --- /dev/null +++ b/.changeset/swift-meals-live.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': minor +--- + +Allow `TemplateListPage` and `TemplateWizardPage` to be passed in as props diff --git a/.changeset/tall-chairs-explain.md b/.changeset/tall-chairs-explain.md new file mode 100644 index 0000000000..9709f225b4 --- /dev/null +++ b/.changeset/tall-chairs-explain.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-techdocs-backend': patch +'@backstage/plugin-catalog-backend': patch +'@backstage/plugin-explore-backend': patch +--- + +Collator factories instantiated in new backend system modules and now marked as deprecated. Will be continued to be exported publicly until the new backend system is fully rolled out. diff --git a/.changeset/ten-hounds-bathe.md b/.changeset/ten-hounds-bathe.md new file mode 100644 index 0000000000..85bda89138 --- /dev/null +++ b/.changeset/ten-hounds-bathe.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-common': patch +--- + +Improve GitlabUrlReader to only load requested sub-path diff --git a/.changeset/ten-mayflies-beam.md b/.changeset/ten-mayflies-beam.md new file mode 100644 index 0000000000..ff7d9e52e9 --- /dev/null +++ b/.changeset/ten-mayflies-beam.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': minor +--- + +Added a `templateFilter` prop to the `` component to allow for filtering of templates through a function. diff --git a/.changeset/thick-forks-prove.md b/.changeset/thick-forks-prove.md new file mode 100644 index 0000000000..5025852e79 --- /dev/null +++ b/.changeset/thick-forks-prove.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-scaffolder-react': minor +'@backstage/plugin-scaffolder': minor +--- + +Move `CategoryPicker` from `scaffolder` into `scaffolder-react` +Move `ContextMenu` into `scaffolder-react` and rename it to `ScaffolderPageContextMenu` diff --git a/.changeset/thin-spoons-prove.md b/.changeset/thin-spoons-prove.md new file mode 100644 index 0000000000..a9bf3052f5 --- /dev/null +++ b/.changeset/thin-spoons-prove.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-react': minor +--- + +To offer better customization options, `ScaffolderPageContextMenu` takes callbacks as props instead of booleans diff --git a/.changeset/thirty-crabs-tell.md b/.changeset/thirty-crabs-tell.md new file mode 100644 index 0000000000..2ca5e8cd34 --- /dev/null +++ b/.changeset/thirty-crabs-tell.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-components': patch +--- + +Fixed the font color on `BackstageHeaderLabel` to respect the active page theme. diff --git a/.changeset/tiny-apes-scream.md b/.changeset/tiny-apes-scream.md new file mode 100644 index 0000000000..b4a28e0745 --- /dev/null +++ b/.changeset/tiny-apes-scream.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-common': patch +--- + +Define optional `backstage:permissions` property to parameters and steps used to authorize part of the template using the permission framework diff --git a/.changeset/twelve-vans-sell.md b/.changeset/twelve-vans-sell.md new file mode 100644 index 0000000000..25c4a077fd --- /dev/null +++ b/.changeset/twelve-vans-sell.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-graphiql': patch +--- + +Allow to pass lazy GraphQL endpoint URL diff --git a/.changeset/warm-buses-switch.md b/.changeset/warm-buses-switch.md new file mode 100644 index 0000000000..5564f33d67 --- /dev/null +++ b/.changeset/warm-buses-switch.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-search-backend-node': minor +--- + +Exports services and extension points that can be used with the new backend system. For documentation on how to migrate, check out the [how to migrate to the new backend system guide](../docs/features/search/how-to-guides.md#how-to-migrate-to-use-search-together-with-the-new-backend-system). diff --git a/.changeset/weak-turtles-arrive.md b/.changeset/weak-turtles-arrive.md new file mode 100644 index 0000000000..3bb56909f9 --- /dev/null +++ b/.changeset/weak-turtles-arrive.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-react': minor +--- + +`scaffolder/next`: Export the `TemplateGroupFilter` and `TemplateGroups` and make an extensible component diff --git a/.changeset/wet-lamps-happen.md b/.changeset/wet-lamps-happen.md new file mode 100644 index 0000000000..066b34b23c --- /dev/null +++ b/.changeset/wet-lamps-happen.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-search-backend-module-techdocs': minor +'@backstage/plugin-search-backend-module-catalog': minor +'@backstage/plugin-search-backend-module-explore': minor +--- + +Package introduced to export search backend modules that can be used with the new backend system to extend search with plugin specific functionality, such as collators. For documentation on how to migrate, check out the [how to migrate to the new backend system guide](../docs/features/search/how-to-guides.md#how-to-migrate-to-use-search-together-with-the-new-backend-system). diff --git a/.changeset/wise-garlics-camp.md b/.changeset/wise-garlics-camp.md new file mode 100644 index 0000000000..e7639ad71c --- /dev/null +++ b/.changeset/wise-garlics-camp.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-kubernetes-common': patch +--- + +Introduced proxy permission types to be used with the kubernetes proxy endpoint's permission framework integration. diff --git a/.changeset/witty-berries-love.md b/.changeset/witty-berries-love.md new file mode 100644 index 0000000000..00fa230dc8 --- /dev/null +++ b/.changeset/witty-berries-love.md @@ -0,0 +1,5 @@ +--- +'@backstage/repo-tools': patch +--- + +Log API report instructions when api-report is missing. diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 010af451af..a38d085dc9 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -13,6 +13,7 @@ yarn.lock @backstage/maintainers @back /docs/features/search @backstage/techdocs-core /docs/features/techdocs @backstage/techdocs-core /docs/plugins/integrating-search-into-plugins.md @backstage/techdocs-core +/packages/cli/src/commands/onboard @backstage/sharks /packages/techdocs-cli @backstage/techdocs-core /packages/techdocs-cli-embedded-app @backstage/techdocs-core /plugins/adr @backstage/maintainers @kuangp @@ -60,9 +61,9 @@ yarn.lock @backstage/maintainers @back /plugins/jenkins-backend @backstage/maintainers @timja /plugins/kafka @backstage/maintainers @nirga @andrewthauer /plugins/kafka-backend @backstage/maintainers @nirga @andrewthauer -/plugins/kubernetes @backstage/maintainers @backstage/warpspeed -/plugins/kubernetes-* @backstage/maintainers @backstage/warpspeed -/plugins/microsoft-calendar @backstage/maintainers @abhay-soni-developer +/plugins/kubernetes @backstage/maintainers @backstage/kubernetes-maintainers +/plugins/kubernetes-* @backstage/maintainers @backstage/kubernetes-maintainers +/plugins/microsoft-calendar @backstage/maintainers @abhay-soni-developer @NishkarshRaj /plugins/newrelic-dashboard @backstage/maintainers @mufaddal7 /plugins/playlist @backstage/maintainers @kuangp /plugins/playlist-* @backstage/maintainers @kuangp diff --git a/.github/vale/Vocab/Backstage/accept.txt b/.github/vale/Vocab/Backstage/accept.txt index 63fa474115..f058475367 100644 --- a/.github/vale/Vocab/Backstage/accept.txt +++ b/.github/vale/Vocab/Backstage/accept.txt @@ -82,6 +82,7 @@ Debounce debuggability declaratively deduplicated +deliverables dependabot deps destructured @@ -158,6 +159,7 @@ img incentivised Indal indexable +ingestors inlined inlinehilite integrator's @@ -367,6 +369,7 @@ templaters Templaters TFRecord theia +threenager thumbsup todo todos @@ -403,6 +406,7 @@ validator validators varchar VMware +Vodafone VPCs VSCode Wayfair diff --git a/ADOPTERS.md b/ADOPTERS.md index 26f4331b70..61e149e498 100644 --- a/ADOPTERS.md +++ b/ADOPTERS.md @@ -234,4 +234,5 @@ _You can do this by using the [Adopter form](https://info.backstage.spotify.com/ | [N26](https://n26.com) | [Alexei Timofti](https://www.linkedin.com/in/alexeitimofti) | We use Backstage for our service catalog and are actively looking into adopting other plugins like TechDocs, TechInsights and Software Templates. | | [The LEGO Group](https://www.lego.com) | [Waqas Ali](https://www.linkedin.com/in/waqasali47) | We are building our internal develper portal on top of Backstage. | | [CORS.gmbh](https://www.cors.gmbh) | [@dpfaffenbauer](https://github.com/dpfaffenbauer) | Developer Portal for our Projects we develop for our Customers and Hosting them On Kubernetes. | +| [Comcast](https://comcast.github.io/) | [Ryan Emerle](https://github.com/remerle) | Developer portal enabling discovery of products, services, and documentation throughout the enterprise to ultimately reduce friction and improve time-to-market. | diff --git a/GOVERNANCE.md b/GOVERNANCE.md index 5bafa19c81..3314e40993 100644 --- a/GOVERNANCE.md +++ b/GOVERNANCE.md @@ -1,88 +1,233 @@ -# Process for becoming a maintainer +# Project Areas -## a) Your organization is not yet a maintainer +The Backstage project is divided into several project areas, each covering particular parts of the project. The main driver for each area is ownership of code in the main Backstage repository, as well as other repositories in the Backstage GitHub organization. Each area has a set of maintainers and repository content that they own. There may be no overlap in ownership between areas, which means that any given line in the GitHub code owners file should have only one owner specified. Each area is represented by a team in the Backstage GitHub organization. Apart from certain project-wide concerns, such as the release process, each area is self-governing and chooses their own ways of working. Project areas may also have special interest groups (SIGs) related to their area, but this is not required. -- Express interest to the sponsors that your organization is interested in becoming a maintainer. Becoming a maintainer generally means that you are going to be spending substantial time on Backstage for the foreseeable future. You should have domain expertise and be extremely proficient in TypeScript. -- We will expect you to start contributing increasingly complicated PRs, under the guidance of the existing maintainers. -- We may ask you to do some PRs from our backlog. -- As you gain experience with the code base and our standards, we will ask you to do code reviews for incoming PRs. -- After a period of approximately 2-3 months of working together and making sure we see eye to eye, the existing sponsors and maintainers will confer and decide whether to grant maintainer status or not. We make no guarantees on the length of time this will take, but 2-3 months is the approximate goal. +The project areas as well as their maintainers are listed in the [OWNERS.md](./OWNERS.md) file. -## b) Your organization is currently a maintainer +Each project area must have at least one maintainer. Project area maintainers may have shared ownership with the core maintainers, which in that case is considered an incubating area. The project area maintainers help drive work forward in the area, but they might not yet feel ready to take on ownership. The goal should generally be that these project area maintainers eventually become sole maintainers of the project area. This is to allow for a more smooth onboarding and transition of ownership, where members of the community might for example be new to open source maintainership. -To become a maintainer you need to demonstrate the following: +## Adding new project areas -- First decide whether your organization really needs more people with maintainer access. Valid reasons are "blast radius", a large organization that is working on multiple unrelated projects, etc. -- Contact a sponsor for your organization and express interest. -- Start doing PRs and code reviews under the guidance of your maintainer. -- After a period of 1-2 months the existing sponsors will discuss granting maintainer access. -- Maintainer access can be upgraded to sponsor access after another conference of the existing sponsors. +Project areas are added by nominating new maintainers for that area. See the sections for becoming a [Project Area Maintainer](#project-area-maintainer). -# Maintainer responsibilities +Project areas may also by added by splitting existing areas. Every area that is created through this process must have at least one maintainer. -- Monitor email aliases. -- Monitor Discord (delayed response is perfectly acceptable). -- Triage GitHub issues and perform pull request reviews for other maintainers and the community. -- Triage build issues - file issues for known flaky builds or bugs, and either fix or find someone to fix any master build breakages. -- During GitHub issue triage, apply all applicable ([labels](https://github.com/backstage/backstage/labels)) to each new issue. Labels are extremely useful for future issue follow-up. Which labels to apply is somewhat subjective so just use your best judgment. A few of the most important labels that are not self-explanatory are: - - good first issue: Mark any issue that can reasonably be accomplished by a new contributor with this label. - - help wanted: Unless it is immediately obvious that someone is going to work on an issue (and if so assign it), mark it help wanted. -- Make sure that ongoing PRs are moving forward at the right pace or closing them. -- Participate when called upon in the security release process. Note that although this should be a rare occurrence, if a serious vulnerability is found, the process may take up to several full days of work to implement. This reality should be taken into account when discussing time commitment obligations with employers. -- In general, continue to be willing to spend at least 25% of one's time working on Backstage (~1.25 business days per week). -- We currently maintain an "on-call" rotation within the maintainers. Each on-call is 1 week. Although all maintainers are welcome to perform all of the above tasks, it is the on-call maintainer's responsibility to triage incoming issues/questions and marshal ongoing work forward. To reiterate, it is not the responsibility of the on-call maintainer to answer all questions and do all reviews, but it is their responsibility to make sure that everything is being actively covered by someone. +## Removing project areas -# When does a maintainer lose maintainer status +Project areas are removed by removing all maintainers for that area and removing the corresponding team from the Backstage GitHub organization. The project area can be re-added later if there is a need for it. Reasons for removal may include lack of activity, lack of maintainers, or lack of relevance to the project. -If a maintainer is no longer interested or cannot perform the maintainer duties listed above, they should volunteer to be moved to emeritus status. In extreme cases this can also occur by a vote of the sponsors and maintainers per the voting process below. +# Project Roles -# End User Sponsors +## Contributor -## Role of a Backstage End User Sponsor +A Contributor contributes directly to the project and adds value to it. Contributions need not be code. People at the Contributor level may be new contributors, or they may only contribute occasionally. -- Provide support for Backstage by removing blockers, securing funding, providing advocacy, feedback, and ensuring project continuity and long term success. -- Assist Backstage maintainers in prioritizing upcoming roadmap items and planned work. -- Provide neutral mediation for any disputes that arise as part of the project. +### Responsibilities -## Backstage End User Sponsor Membership +- Follow the [CNCF CoC](https://github.com/cncf/foundation/blob/main/code-of-conduct.md) +- Follow the project [contributing guide](CONTRIBUTING.md) + +### How to get involved + +- Participate in community discussions +- Help other users +- Submit bug reports +- Comment on issues +- Try out new releases +- Attend community events + +### How to contribute + +- Report and sometimes resolve issues +- Occasionally submit PRs +- Contribute to the documentation +- Show up at meetings, take notes +- Answer questions from other community members +- Submit feedback on issues and PRs +- Test releases and patches and submit reviews +- Run or help run events +- Promote the project in public + +## Organization Member + +An org member is a frequent contributor that has become a member of the Backstage GitHub organization. In addition to the responsibilities of contributors, an org member is also expected to be reasonably active in the community through continuous contributions of any type. + +An Organization Member must meet the responsibilities and has the requirements of a Contributor. + +### Responsibilities + +- Continues to contribute regularly, as demonstrated by having at least 10 GitHub contributions per year in [Devstats](https://backstage.devstats.cncf.io/d/48/users-statistics-by-repository-group?orgId=1&var-period=y&var-metric=contributions&var-repogroup_name=All&from=now-1y&to=now&var-users=All), or contributions of a similar effort that might not be captured in Devstats. + +### Requirements + +- Must have at least 10 contributions to the projects in the form of: + - Accepted PRs + - Helpful PR reviews + - Resolving GitHub issues + - Or some equivalent contributions to the project +- Must have been contributing for at least 3 months +- Or is the member of a team that owns a project area, in which case the above requirements do not apply and the member is instead vetted by the project area maintainers + +### Becoming an Organization Member + +Open an issue towards [the community repository](https://github.com/backstage/community) using the [org membership request template](https://github.com/backstage/community/issues/new?template=org_member.yaml&title=Org+Member%3A+%3Cyour-github-login%3E). + +### Privileges + +- Membership in the Backstage GitHub organization + +## Plugin Maintainer + +A Plugin Maintainer is responsible for maintaining an individual Backstage plugin or module. This includes reviewing contributions and responding to issues towards an individual plugin, as well as keeping the plugin up to date. + +Plugin Maintainer is a lightweight form of ownership that is primarily reflected though code owners of the plugin packages in the [CODEOWNERS](./.github/CODEOWNERS) file. Each plugin can have one or more maintainers. If a plugin becomes a significant part of the Backstage ecosystem, it may be promoted to be a distinct project area instead. + +A Plugin Maintainer has all the rights and responsibilities of an Organization Member. + +### Responsibilities + +- Review the majority of PRs towards the plugin +- Respond to GitHub issues related to the plugin +- Keep the plugin up-to-date with Backstage libraries and other dependencies +- Follow the [reviewing guide](REVIEWING.md) + +### Requirements + +- Is an Organization Member +- Display knowledge of Backstage's review process and best practices for plugin design +- Is supportive of new and occasional contributors and helps get useful PRs in shape to merge + +### Privileges + +- GitHub code owner of the plugin directory, with rights to approve and merge PRs towards the plugin + +### Becoming a Plugin Maintainer + +To become a Plugin Maintainer, you first need to be an Organization Member. You can then file a pull request towards [CODEOWNERS.md](./.github/CODEOWNERS) requesting to be added as a code owner of the plugin directory. Existing code owners of that plugin alongside the core maintainers will then review the request. + +## Project Area Maintainer + +Project Area Maintainers are owners of a particular project area. They are expected to review and merge pull requests towards their area, and also drive development and manage tech health. A Project Area Maintainer also need to commit a certain number of hours per month towards the project, and exercise judgment for the good of the project, independent of their employer. Project Area Maintainers should also mentor new maintainers and participate in and lead community meetings related to their area. New Project Area Maintainers need to be approved by the existing project area maintainers, or the core maintainers if it is a new area. + +The maintainers of a project area may be represented by a team in external organization. In this case, the state as a project area maintainer is tied to the membership in that team. New members of the team may automatically be added as maintainers, as well as removed when they leave. This process is governed autonomously by the team of project area maintainers. + +A Project Area Maintainer has all the rights and responsibilities of an Organization Member. + +### Responsibilities + +- Review PRs towards their project area. Project area maintainers are expected to review at least 20 PRs per year, or the majority of all PRs towards the area, if it is less than 20 +- Follow the [reviewing guide](REVIEWING.md) +- Triage and respond to issues related to their project area +- Mentor new project area maintainers +- Write refactoring PRs +- Determine strategy and policy for the project area +- Participate in or leading community meetings related to their project area + +### Requirements + +- Is an Organization Member +- Have made at least 5 meaningful contributions towards the project area +- Demonstrates knowledge of their project area, and how it fits into the larger Backstage project +- Is able to exercise judgment for the good of the project, independent of their employer, friends, or team +- Mentors other contributors and project area maintainers +- Can commit to spending at least 16 hours per month working on the project, preferably distributed evenly across the month + +### Privileges + +- Approve and merge PRs towards their project area +- Drive the direction and roadmap of their project area + +### Becoming a Project Area Maintainer + +If you are interested in becoming a project area maintainer, reach out to the existing maintainers for that area. If you wish to become a maintainer for a new area, reach out to the core maintainers. + +Any current project area maintainer or core maintainer may nominate a new project area maintainer by opening a PR towards the [OWNERS.md](OWNERS.md) file. A majority of the project area maintainers for that area must approve the PR. If there are no existing maintainers for that area, the PR must be approved by a majority of the core maintainers. + +## Core Maintainer + +Core Maintainers are responsible for the Backstage project as a whole. They help review and merge project-level pull requests as well as coordinate work affecting multiple project areas. A core maintainer needs to commit the majority of their working time towards the project, and exercise judgment for the good of the project, independent of their employer. Core maintainers should also mentor and seek out new maintainers, lead community meetings, and communicate with the CNCF on behalf of the project. To become a core maintainer one needs to have been the maintainer of a number of different project areas, demonstrate a deep knowledge of large parts of the Backstage project, and be backed by the existing core maintainers. + +A Core Maintainer have all the rights and responsibilities of a Project Area Maintainer. + +### Responsibilities + +- Take part in the incoming issue and PR triage and review process. PRs are shared equally among all maintainers +- Mentor new Project Area Maintainers and Plugin Maintainers +- Drive refactoring and manage tech health across the entire project +- Participate in CNCF maintainer activities +- Respond to security incidents in accordance to our [security policy](./SECURITY.md) +- Determine strategy and policy for the project +- Participate in or leading community meetings + +### Requirements + +- Experience as a Project Area Maintainer for at least 6 months +- Demonstrates a broad knowledge of the project across multiple areas +- Is able to exercise judgment for the good of the project, independent of their employer, friends, or team +- Mentors other contributors +- Can commit to spending at least 10 days per month working on the project + +### Privileges + +- Approve PRs that fall outside any specific project area +- Merge PRs to any area of the project +- Represent the project in public as a Maintainer +- Communicate with the CNCF on behalf of the project +- Have a vote in Maintainer decision-making meetings + +### Becoming a Core Maintainer + +Any core maintainer or end user sponsor may nominate a new core maintainer by opening a PR towards the [OWNERS.md](OWNERS.md) file. Core maintainers must be approved by a majority of the existing core maintainers and end user sponsors. + +## End User Sponsors + +### Role of a Backstage End User Sponsor + +- Provide support for Backstage by removing blockers, securing funding, providing advocacy, feedback, and ensuring project continuity and long term success +- Assist Backstage maintainers in prioritizing upcoming roadmap items and planned work +- Provide neutral mediation for any disputes that arise as part of the project + +### Backstage End User Sponsor Membership The End User Sponsors group comprises at most 5 people. To be eligible for membership in the group, you or the company where you work you must: - Be responsible for and end user of a production Backstage deployment of non-trivial size - Be active contributors to the open source project - Be willing and able to attend regularly-scheduled End User Sponsor meetings -- Abide by [Backstage’s Code of Conduct](./CODE_OF_CONDUCT.md). +- Abide by [CNCF CoC](https://github.com/cncf/foundation/blob/main/code-of-conduct.md) Candidates for membership will be nominated by current Sponsor members or by Backstage maintainers. If there are more nominations than Sponsor seats remaining, existing sponsors shall vote on the candidates, and the candidates with the most votes will become Sponsors. Any ties will be broken by current Backstage sponsors. -# Reviewers - -The project also contains a team called [@backstage/reviewers](https://github.com/orgs/backstage/teams/reviewers). This is the team of people who are the fallback in [`CODEOWNERS`](./.github/CODEOWNERS). This team will typically contain the maintainers, and a small number of additional people who are permitted to approve and merge pull requests. The purpose of this group is to offload some of the review work from the maintainers, simplifying and speeding up the review process for contributors. - -This responsibility is distinct from the maintainer role. A reviewer must not approve and merge changes that have a level of impact that a maintainer should oversee; see below for clarification. For that class of changes, a reviewer can still review the pull request thoroughly without approving it (e.g. with a comment on the pull request), and is expected to notify `@backstage/maintainers` for final approval. Note that it is best to not use the GitHub review approve functionality for this, since that would let Hall of Fame members self-merge the pull request before maintainers get the chance to look at it. - -The following is a non-exhaustive list of types of change, for which a reviewer should defer final decision and merge to a maintainer: - -- A larger refactoring that significantly affects the structure of/between packages -- Changes that settle or alter the trajectory of contested ongoing topics in issues or elsewhere -- Changes that affect the [Architecture Decision Records](./docs/architecture-decisions) -- Changes to APIs that have large customer impact, such as the core APIs in `@backstage/core-*` packages, or significant `@backstage/cli` changes. -- Pull requests whose build checks are not passing fully -- Additions and removals of entire packages -- Releases (e.g. pull requests titled `Version Packages`) - -A maintainer may suggest an addition to the reviewers team by opening a pull request that modifies [`OWNERS.md`](./OWNERS.md) accordingly. Prospective reviewers are not expected to do this themselves, but should rather ask a maintainer to sponsor their addition. All of the maintainers and sponsors are called to vote on the addition (see the section below about voting). If the vote passes, the pull request can be approved and merged, and the corresponding addition to the GitHub team can be made. - -A reviewer can elect to remove themselves from the reviewers group by opening, or asking a maintainer to open, a pull request that modifies [`OWNERS.md`](./OWNERS.md) accordingly. A maintainer will approve and merge the pull request, and the corresponding removal from the GitHub team can be made. - -A maintainer can call on the other maintainers and sponsors for a vote to remove a reviewer (see the section below about conflict resolution and voting). If the vote passes, a maintainer creates a pull request that modifies [`OWNERS.md`](./OWNERS.md) accordingly. After approval by another maintainer, the pull request can be merged, and the corresponding removal from the GitHub team can be made. - # Conflict resolution and voting -In general, we prefer that technical issues and membership are amicably worked out between the persons involved. If a dispute cannot be decided independently, the sponsors and maintainers can be called in to decide an issue. If the sponsors and maintainers themselves cannot decide an issue, the issue will be resolved by voting. +In general, we prefer that technical issues and membership are amicably worked out between the persons involved. If a dispute cannot be decided independently, the sponsors and core maintainers can be called in to decide an issue. If the sponsors and maintainers themselves cannot decide an issue, the issue will be resolved by voting. -In all cases in this document where voting is mentioned, the voting process is a simple majority in which each sponsor receives two votes and each maintainer receives one vote. If such a majority is reached, the vote is said to have _passed_. +In all cases in this document where voting is mentioned, the voting process is a simple majority in which each sponsor receives two votes and each core maintainer receives one vote. If such a majority is reached, the vote is said to have _passed_. -# Adding new projects to the Backstage GitHub organization +## Inactivity -New projects will be added to the Backstage organization via GitHub issue discussion in one of the existing projects in the organization. Once sufficient discussion has taken place (~3-5 business days but depending on the volume of conversation), the maintainers of the project where the issue was opened (since different projects in the organization may have different maintainers) will decide whether the new project should be added. See the section above on voting if the maintainers cannot easily decide. +It is important for contributors to be and stay active to set an example and show commitment to the project. Inactivity is harmful to the project as it may lead to unexpected delays, contributor attrition, and a loss of trust in the project. + +Inactivity is measured by periods of no contributions for longer than: + +- Core Maintainer: 2 months +- Project Area Maintainer: 4 months +- Plugin Maintainer: 6 months +- Organization Member: 8 months + +Consequences of being inactive include: + +- Involuntary removal or demotion +- Being asked to move to Emeritus status + +## Involuntary Removal or Demotion + +Involuntary removal/demotion of a contributor happens when responsibilities and requirements aren't being met. This may include repeated patterns of inactivity, extended period of inactivity, a period of failing to meet the requirements of your role, and/or a violation of the Code of Conduct. This process is important because it protects the community and its deliverables while also opens up opportunities for new contributors to step in. + +Involuntary removal or demotion is handled through a vote by a majority of the current Core Maintainers. Some aspects of this process may be automated, such as removal after periods of inactivity. + +## Stepping Down/Emeritus Process + +If and when contributors' commitment levels change, contributors can consider stepping down (moving down the contributor ladder) vs moving to emeritus status (completely stepping away from the project). + +Contact the Maintainers about changing to Emeritus status, or reducing your contributor level. diff --git a/OWNERS.md b/OWNERS.md index 6615046540..1834abe227 100644 --- a/OWNERS.md +++ b/OWNERS.md @@ -1,43 +1,79 @@ - See [CONTRIBUTING.md](CONTRIBUTING.md) for general contribution guidelines. - See [GOVERNANCE.md](GOVERNANCE.md) for governance guidelines and responsibilities. -This page lists all active sponsors and maintainers. +## Core Maintainers -# Sponsors +Team: @backstage/maintainers -- Niklas Gustavsson ([protocol7](https://github.com/protocol7)) (ngn@spotify.com) -- Dave Zolotusky ([dzolotusky](https://github.com/dzolotusky)) (dzolo@spotify.com) -- Lee Mills ([leemills83](https://github.com/leemills83)) (leem@spotify.com) +| Maintainer | Organization | GitHub | Discord | +| --------------- | ------------ | ----------------------------------------------- | ------------- | +| Patrik Oldsberg | Spotify | [Rugvip](https://github.com/Rugvip) | `Rugvip#0019` | +| Fredrik Adelöw | Spotify | [freben](https://github.com/freben) | `freben#3926` | +| Ben Lambert | Spotify | [benjdlambert](https://github.com/benjdlambert) | `blam#2159` | +| Johan Haals | Spotify | [jhaals](https://github.com/jhaals) | `Johan#0679` | -# Maintainers +## Project Areas -- Patrik Oldsberg ([rugvip](https://github.com/rugvip)) (Discord: @Rugvip) -- Fredrik Adelöw ([freben](https://github.com/freben)) (Discord: @freben) -- Ben Lambert ([benjdlambert](https://github.com/benjdlambert)) (Discord: @blam) -- Johan Haals ([jhaals](https://github.com/jhaals)) (Discord: @jhaals) +These are the separate project areas of Backstage, each with their own project area maintainers -# Reviewers +### Catalog -See [`GOVERNANCE.md`](./GOVERNANCE.md) for details about how the reviewers team -works. +Team: @backstage/catalog-maintainers -- Patrik Oldsberg ([rugvip](https://github.com/rugvip)) (Discord: @Rugvip) -- Fredrik Adelöw ([freben](https://github.com/freben)) (Discord: @freben) -- Ben Lambert ([benjdlambert](https://github.com/benjdlambert)) (Discord: @blam) -- Johan Haals ([jhaals](https://github.com/jhaals)) (Discord: @jhaals) -- Himanshu Mishra ([OrkoHunter](https://github.com/OrkoHunter)) (Discord: @OrkoHunter) -- Tim Hansen ([timbonicus](https://github.com/timbonicus)) (Discord: @timbonicus) +| Name | Organization | Team | GitHub | Discord | +| ---- | ------------ | --------- | ---------------------------- | ------- | +| TBD | Spotify | Chipmunks | [TBD](http://github.com/TBD) | - | -# Emeritus maintainers +### Kubernetes -- Stefan Ålund ([stefanalund](https://github.com/stefanalund)) (Discord: @stalund) +Team: @backstage/kubernetes-maintainers -# Hall of Fame +Scope: The Kubernetes plugin and the base it provides for other plugins to build upon. -People that have made significant contributions to the project and earned write access. +| Name | Organization | Team | GitHub | Discord | +| -------------- | ------------ | ---- | ---------------------------------------- | ------------ | +| Matthew Clarke | Spotify | | [mclarke47](http://github.com/mclarke47) | mclarke#0725 | -- Andrew Thauer - Wealthsimple (GitHub: [andrewthauer](https://github.com/andrewthauer)) -- Oliver Sand - SDA SE (GitHub: [Fox32](https://github.com/Fox32)) -- David Tuite - Roadie (GitHub: [dtuite](https://github.com/dtuite)) -- Adam Harvey - Cisco (GitHub: [adamdmharvey](https://github.com/adamdmharvey)) -- Dominik Henneke - SDA SE (GitHub: [dhenneke](https://github.com/dhenneke)) +### TechDocs + +Team: @backstage/techdocs-maintainers + +| Name | Organization | Team | GitHub | Discord | +| ---- | ------------ | ------------ | ---------------------------- | ------- | +| TBD | Spotify | Pulp Fiction | [TBD](http://github.com/TBD) | - | + +### Search + +Team: @backstage/search-maintainers + +| Name | Organization | Team | GitHub | Discord | +| ---- | ------------ | ---- | ---------------------------- | ------- | +| TBD | Spotify | BUX | [TBD](http://github.com/TBD) | - | + +## Sponsors + +| Name | Organization | GitHub | Email | +| ----------------- | ------------ | ------------------------------------------- | ----------------- | +| Niklas Gustavsson | Spotify | [protocol7](https://github.com/protocol7) | ngn@spotify.com | +| Dave Zolotusky | Spotify | [dzolotusky](https://github.com/dzolotusky) | dzolo@spotify.com | +| Lee Mills | Spotify | [leemills83](https://github.com/leemills83) | leem@spotify.com | + +## Organization Members + +| Name | Organization | GitHub | Discord | +| --------------- | ------------------------ | ----------------------------------------------- | ------------------------------ | +| Adam Harvey | Cisco | [adamdmharvey](https://github.com/adamdmharvey) | `adamharvey#3739` | +| Andre Wanlin | Keyloop | [awanlin](https://github.com/awanlin) | `Ahhhndre#3095` | +| Andrew Thauer | Wealthsimple | [andrewthauer](https://github.com/andrewthauer) | `andrewthauer#3060` | +| Brian Fletcher | RoadieHQ | [punkle](https://github.com/punkle) | `Brian Fletcher#7051` | +| David Tuite | Roadie | [dtuite](https://github.com/dtuite) | `David Tuite (roadie.io)#1010` | +| Jussi Hallila | Roadie | [Xantier](https://github.com/Xantier) | `Xantier#0086` | +| Mark Avery | Cvent | [webark](https://github.com/webark) | `webark#8471` | +| Phil Kuang | FactSet Research Systems | [kuangp](https://github.com/kuangp) | `pkuang#3202` | +| Taras Mankovski | Frontside | [taras](https://github.com/taras) | `tarasm#1256` | + +## Emeritus Core Maintainers + +| Maintainer | Organization | GitHub | Discord | +| ------------ | ------------ | --------------------------------------------- | -------------- | +| Stefan Ålund | Spotify | [stefanalund](https://github.com/stefanalund) | `stalund#9602` | diff --git a/docs/features/kubernetes/installation.md b/docs/features/kubernetes/installation.md index ae7826a804..17028ef90f 100644 --- a/docs/features/kubernetes/installation.md +++ b/docs/features/kubernetes/installation.md @@ -75,6 +75,7 @@ export default async function createPlugin( logger: env.logger, config: env.config, catalogApi, + permissions: env.permissions, }).build(); return router; } diff --git a/docs/features/kubernetes/proxy.md b/docs/features/kubernetes/proxy.md index 5848d62e3e..b53dfeb29d 100644 --- a/docs/features/kubernetes/proxy.md +++ b/docs/features/kubernetes/proxy.md @@ -22,6 +22,7 @@ import { discoveryApiRef, googleAuthApiRef, useApi, + identityApiRef, } from '@backstage/core-plugin-api'; const CLUSTER_NAME = ''; // use a known cluster name @@ -32,6 +33,10 @@ const token = await googleAuthApi.getAccessToken( 'https://www.googleapis.com/auth/cloud-platform', ); +// get a backstage ID token +const identityApi = useApi(identityApiRef); +const { token: userToken } = await identityApi.getCredentials(); + const discoveryApi = useApi(discoveryApiRef); const kubernetesBaseUrl = await discoveryApi.getBaseUrl('kubernetes'); const kubernetesProxyEndpoint = `${kubernetesBaseUrl}/proxy`; @@ -40,8 +45,9 @@ const kubernetesProxyEndpoint = `${kubernetesBaseUrl}/proxy`; await fetch(`${kubernetesProxyEndpoint}/api/v1/namespaces`, { method: 'GET', headers: { - 'X-Kubernetes-Cluster': CLUSTER_NAME, - Authorization: `Bearer ${token}`, + 'Backstage-Kubernetes-Cluster': CLUSTER_NAME, + 'Backstage-Kubernetes-Authorization': `Bearer ${token}`, + Authorization: `Bearer ${userToken}`, }, }); ``` @@ -49,16 +55,19 @@ await fetch(`${kubernetesProxyEndpoint}/api/v1/namespaces`, { ## How it works The proxy will interpret the -[`X-Kubernetes-Cluster` -header](https://backstage.io/docs/reference/plugin-kubernetes-backend.header_kubernetes_cluster) -as the name of the cluster to target. This name will be compared to each cluster +[`Backstage-Kubernetes-Cluster`](https://backstage.io/docs/reference/plugin-kubernetes-backend.header_kubernetes_cluster) +header as the name of the cluster to target. This name will be compared to each cluster returned by all the configured [cluster locators](https://backstage.io/docs/features/kubernetes/configuration#clusterlocatormethods) -- the first cluster whose [`name` field](https://backstage.io/docs/features/kubernetes/configuration#clustersname) matches the value in the header will be targeted. -Then the request will be forwarded verbatim (but with the endpoint's base URL -prefix stripped) to the cluster. +Then the request will be forwarded to the cluster. + +Overall, the only changes to each request are: + +- the endpoint's base URL prefix is stripped. +- the `Backstage-Kubernetes-Authorization` header becomes the `Authorization` header that is used when forwarding the request. ## Authentication @@ -73,9 +82,59 @@ providers](https://backstage.io/docs/features/kubernetes/authentication#client-s The proxy has no provisions for mTLS, so it cannot be used to connect to clusters using the [x509 Client Certs](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#x509-client-certs) -authentication strategy. [Bearer -tokens](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#putting-a-bearer-token-in-a-request) -will be forwarded as-is. +authentication strategy.\ +The current `/proxy` Implementation expects a +[Bearer +token](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#putting-a-bearer-token-in-a-request) +to be provided as a `Backstage-Kubernetes-Authorization` header for a target cluster. This token will be used as the `Authorization` header when forwarding a request to a target cluster. + +## How to disable the proxy endpoint via PermissionPolicy + +The kubernetes plugin can disable the use of the `proxy` endpoint by leveraging the permission framework. This integration allows admins to use well defined PermissionPolicies to restrict the use of the endpoint all together. The `proxy` endpoint can return 403 errors even if it has a valid ID token attached that a cluster would authorize thus allowing integrators the confidence that Backstage is not accessing kubernetes clusters on behalf of undesired parties. + +This feature assumes your backstage instance has enabled the [permissions framework](https://backstage.io/docs/permissions/getting-started) + +A sample policy like: + +[packages/backend/src/plugins/permissions.ts](https://github.com/backstage/backstage/blob/master/packages/backend/src/plugins/permission.ts) + +```typescript +import { BackstageIdentityResponse } from '@backstage/plugin-auth-node'; +import { + AuthorizeResult, + PolicyDecision, +} from '@backstage/plugin-permission-common'; +import { + PermissionPolicy, + PolicyQuery, +} from '@backstage/plugin-permission-node'; + +class KubernetesDenyAllProxyEndpointPolicy implements PermissionPolicy { + async handle( + request: PolicyQuery, + user?: BackstageIdentityResponse, + ): Promise { + if (request.permission.name === 'kubernetes.proxy') { + return { + result: AuthorizeResult.DENY, + }; + } + return { result: AuthorizeResult.ALLOW }; + } +} +``` + +would leverage the permission framework to return the following response: + +```json +{ + "error": { + "name": "NotAllowedError" + } +} +``` + +even if a valid ID token was attached that a cluster would authorize. ## Other known limitations diff --git a/docs/features/search/how-to-guides.md b/docs/features/search/how-to-guides.md index 5b28e259b5..abb29ab4eb 100644 --- a/docs/features/search/how-to-guides.md +++ b/docs/features/search/how-to-guides.md @@ -51,7 +51,7 @@ The TechDocs plugin has supported integrations to Search, meaning that it provides a default collator factory ready to be used. The purpose of this guide is to walk you through how to register the -[DefaultTechDocsCollatorFactory](https://github.com/backstage/backstage/blob/master/plugins/techdocs-backend/src/search/DefaultTechDocsCollatorFactory.ts) +[DefaultTechDocsCollatorFactory](https://github.com/backstage/backstage/blob/de294ce5c410c9eb56da6870a1fab795268f60e3/plugins/techdocs-backend/src/search/DefaultTechDocsCollatorFactory.ts) in your App, so that you can get TechDocs documents indexed. If you have been through the @@ -369,3 +369,31 @@ export const SearchModal = ({ toggleModal }: { toggleModal: () => void }) => ( ``` There are other more specific search results layout components that also accept result item extensions, check their documentation: [SearchResultList](https://backstage.io/storybook/?path=/story/plugins-search-searchresultlist--with-result-item-extensions) and [SearchResultGroup](https://backstage.io/storybook/?path=/story/plugins-search-searchresultgroup--with-result-item-extensions). + +## How to migrate your backend installation to use Search together with the new backend system + +> DISCLAIMER: The new backend system is in alpha, and so are the search backend support for the new backend system. We don't recommend you to migrate your backend installations to the new system yet. But if you want to experiment, this is the guide for you! + +Recently, the Backstage maintainers [announced the new Backend System](https://backstage.io/blog/2023/02/15/backend-system-alpha). The search plugins are now migrated to support the new backend system. In this guide you will learn how to update your backend set up. + +In packages/backend-next/index.ts + +```ts +import { searchPlugin } from '@backstage/plugin-search-backend/alpha'; +import { searchModuleElasticsearchEngine } from '@backstage/plugin-search-backend-module-elasticsearch/alpha'; +import { searchModuleCatalogCollator } from '@backstage/plugin-search-backend-module-catalog/alpha'; +import { searchModuleTechDocsCollator } from '@backstage/plugin-search-backend-module-techdocs/alpha'; +import { searchModuleExploreCollator } from '@backstage/plugin-search-backend-module-explore/alpha'; + +const backend = createBackend(); +// adding the search plugin to the backend +backend.add(searchPlugin()); +// (optional) the default search engine is Lunr, if you want to extend the search backend with another search engine. +backend.add(searchModuleElasticsearchEngine()); +// extending search with collator modules to start index documents, take in optional schedule parameters. +backend.add(searchModuleCatalogCollator()); +backend.add(searchModuleTechDocsCollator()); +backend.add(searchModuleExploreCollator()); + +backend.start(); +``` diff --git a/docs/features/software-catalog/extending-the-model.md b/docs/features/software-catalog/extending-the-model.md index bdd043b8a8..c254d7d0b6 100644 --- a/docs/features/software-catalog/extending-the-model.md +++ b/docs/features/software-catalog/extending-the-model.md @@ -170,6 +170,7 @@ its schema. There is a builtin processor that implements this for all known core kinds and matches the data against their fixed validation schema. This processor can be replaced when building the backend catalog using the `CatalogBuilder`, with a processor of your own that validates the data differently. +This replacement processor must have a name that matches the builtin processor, `BuiltinKindsEntityProcessor`. This type of extension is high risk, and may have high impact across the ecosystem depending on the type of change that is made. It is therefore not diff --git a/docs/features/software-catalog/external-integrations.md b/docs/features/software-catalog/external-integrations.md index 6f957625bd..0f2459d6e0 100644 --- a/docs/features/software-catalog/external-integrations.md +++ b/docs/features/software-catalog/external-integrations.md @@ -506,9 +506,10 @@ import { processingResult, CatalogProcessor, CatalogProcessorEmit, - LocationSpec, } from '@backstage/plugin-catalog-node'; +import { LocationSpec } from '@backstage/plugin-catalog-common'; + // A processor that reads from the fictional System-X export class SystemXReaderProcessor implements CatalogProcessor { constructor(private readonly reader: UrlReader) {} diff --git a/docs/features/software-templates/configuration.md b/docs/features/software-templates/configuration.md index ff5191bed2..24b8c530b8 100644 --- a/docs/features/software-templates/configuration.md +++ b/docs/features/software-templates/configuration.md @@ -93,3 +93,18 @@ You can also further customize groups by passing in a `titleComponent` instead of a `title` which will be a component to use as the header instead of just the default `ContentHeader` with the `title` set as it's value. ![Grouped Templates](../../assets/software-templates/grouped-templates.png) + +There is also an option to hide some templates. +You can have several use cases for that: + +- it's still in an experimental phase, so you can combine it with feature flagging for example +- you don't want to make them accessible from template list, but only open it on some action with pre-filled data. +- show different set of templates depends on target environment + +```typescript jsx + + entity?.metadata?.tags?.includes('experimental') ?? false + } +/> +``` diff --git a/docs/features/software-templates/index.md b/docs/features/software-templates/index.md index 5911e192b1..fbccf8848c 100644 --- a/docs/features/software-templates/index.md +++ b/docs/features/software-templates/index.md @@ -58,6 +58,10 @@ It shouldn't take too long, and you'll have a success screen! If it fails, you'll be able to click on each section to get the log from the step that failed which can be helpful in debugging. +You can also cancel the running process. Once you clicked on button "Cancel", the abort signal +will be sent to a task and all next steps won't be executed. The current step will be cancelled +only if it supports it. + ![Templating failed](../../assets/software-templates/failed.png) ## View Component in Catalog diff --git a/docs/features/software-templates/testing-scaffolder-alpha.md b/docs/features/software-templates/testing-scaffolder-alpha.md index c0b97e897c..02e579ef83 100644 --- a/docs/features/software-templates/testing-scaffolder-alpha.md +++ b/docs/features/software-templates/testing-scaffolder-alpha.md @@ -52,33 +52,54 @@ And this API should be the exact same as the previous Router, so you should be a ```tsx - entity?.metadata?.tags?.includes('recommended') ?? false, - }, - ]} - /> - } - > - - - {/* ... other extensions */} - - - - {/* ... other layouts */} - - + path="/create" + element={ + {/* highlight-remove-next-line */} + + entity?.metadata?.tags?.includes('recommended') ?? false, + }, + ]} + /> + } +> + + + {/* ... other extensions */} + + + + {/* ... other layouts */} + + ``` +Optionally, you can choose to run the two side by side by using `FeatureFlags` in your `App.tsx` if you wish, but, we would also recommend duplicating any `CustomFieldExtensions` too as the new `CustomFieldExtensions` might not be compatible with the old form. + +```tsx + + }> + + + + + + + }> + + + + + +``` + +You should then be able to enable the `scaffolder-next-preview` feature flag under `/settings/feature-flags` in Backstage. + ### Make the required changes to your `CustomFieldExtensions` There's differently named function for creating field extensions part of the `/alpha` exports as these are the ones that can contain breaking changes because of the breaking changes that have been applied in `react-jsonschema-form`. @@ -197,9 +218,9 @@ You will need to change the import for `FieldValidation` to point at the new `re ```ts /* highlight-remove-next-line */ -- import { FieldValidation } from '@rjsf/core'; +import { FieldValidation } from '@rjsf/core'; /* highlight-add-next-line */ -+ import { FieldValidation } from '@rjsf/utils; +import { FieldValidation } from '@rjsf/utils; import { KubernetesValidatorFunctions } from '@backstage/catalog-model'; export const entityNamePickerValidation = ( diff --git a/docs/features/software-templates/writing-custom-actions.md b/docs/features/software-templates/writing-custom-actions.md index 3e89e89582..7a841dfd0e 100644 --- a/docs/features/software-templates/writing-custom-actions.md +++ b/docs/features/software-templates/writing-custom-actions.md @@ -71,7 +71,7 @@ You can also choose to define your custom action using JSON schema instead of `z ```ts title="With JSON Schema" import { createTemplateAction } from '@backstage/plugin-scaffolder-node'; -import fs from 'fs-extra'; +import { writeFile } from 'fs'; export const createNewFileAction = () => { return createTemplateAction<{ contents: string; filename: string }>({ @@ -95,9 +95,12 @@ export const createNewFileAction = () => { }, }, async handler(ctx) { - await fs.outputFile( + const { signal } = ctx; + await writeFile( `${ctx.workspacePath}/${ctx.input.filename}`, ctx.input.contents, + { signal }, + _ => {}, ); }, }); diff --git a/docs/features/software-templates/writing-templates.md b/docs/features/software-templates/writing-templates.md index a272f05f3f..15e6a833cc 100644 --- a/docs/features/software-templates/writing-templates.md +++ b/docs/features/software-templates/writing-templates.md @@ -472,6 +472,20 @@ owner: kind: [Group, User] ``` +#### `catalogFilter` + +The `catalogFilter` allow you to filter the list entities using any of the [catalog api filters](https://backstage.io/docs/features/software-catalog/software-catalog-api#filtering): + +For example, if you want to show users in the `default` namespace, and groups with the `github.com/team-slug` annotation, you can do the following: + +```yaml +catalogFilter: + - kind: [User] + metadata.namespace: default + - kind: [Group] + metadata.annotations.github.com/team-slug: { exists: true } +``` + ## `spec.steps` - `Action[]` The `steps` is an array of the things that you want to happen part of this diff --git a/docs/features/techdocs/cli.md b/docs/features/techdocs/cli.md index b174896d6a..76589de5a8 100644 --- a/docs/features/techdocs/cli.md +++ b/docs/features/techdocs/cli.md @@ -200,6 +200,15 @@ Options: -h, --help display help for command ``` +#### Publishing from behind a proxy + +For users attempting to publish TechDocs content behind a proxy, the TechDocs CLI leverages `global-agent` to navigate the proxy to successfully connect to that location. To enable `global-agent`, the following variables need to be set prior to running the techdocs-cli command: + +```bash +export GLOBAL_AGENT_HTTPS_PROXY=${HTTP_PROXY} +export GLOBAL_AGENT_NO_PROXY=${NO_PROXY} +``` + ### Migrate content for case-insensitive access Prior to the beta version of TechDocs (`v[0.11.0]`), TechDocs were stored in diff --git a/docs/integrations/gitlab/discovery.md b/docs/integrations/gitlab/discovery.md index 6d0bb7e2e2..45991b2cf5 100644 --- a/docs/integrations/gitlab/discovery.md +++ b/docs/integrations/gitlab/discovery.md @@ -21,6 +21,7 @@ catalog: gitlab: yourProviderId: host: gitlab-host # Identifies one of the hosts set up in the integrations + branch: main # Optional. Used to discover on a specific branch fallbackBranch: main # Optional. Fallback to be used if there is no default branch configured at the Gitlab repository. It is only used, if `branch` is undefined. Uses `master` as default group: example-group # Optional. Group and subgroup (if needed) to look for repositories. If not present the whole instance will be scanned entityFilename: catalog-info.yaml # Optional. Defaults to `catalog-info.yaml` diff --git a/docs/integrations/gitlab/org.md b/docs/integrations/gitlab/org.md index 7ddc5202b5..d78b0ed388 100644 --- a/docs/integrations/gitlab/org.md +++ b/docs/integrations/gitlab/org.md @@ -2,15 +2,14 @@ id: org title: GitLab Organizational Data sidebar_label: Org Data -description: Importing users and groups from a GitLab organization into Backstage +description: Importing users and groups from GitLab into Backstage --- -The Backstage catalog can be set up to ingest organizational data - users and -teams - directly from an organization in GitLab. The result -is a hierarchy of +The Backstage catalog can be set up to ingest organizational data -- users and +groups -- directly from GitLab. The result is a hierarchy of [`User`](../../features/software-catalog/descriptor-format.md#kind-user) and -[`Group`](../../features/software-catalog/descriptor-format.md#kind-group) kind -entities that mirror your org setup. +[`Group`](../../features/software-catalog/descriptor-format.md#kind-group) +entities that mirrors your org setup. ```yaml integrations: @@ -19,10 +18,11 @@ integrations: token: ${GITLAB_TOKEN} ``` -This will query all users and groups from your gitlab installation. Depending on the size -of the Gitlab Instance, this can take some time and resources. +This will query all users and groups from your GitLab instance. Depending on the +amount of data, this can take significant time and resources. -The token that is used for the Organization Integration, has to be an Admin Personal Access Token (PAT). +The token used must have the `read_api` scope, and the Users and Groups fetched +will be those visible to the account which provisioned the token. ```yaml catalog: @@ -35,6 +35,7 @@ catalog: groupPattern: '[\s\S]*' # Optional. Filters found groups based on provided pattern. Defaults to `[\s\S]*`, which means to not filter anything ``` -When the `group` parameter is provided, the corresponding path prefix will be stripped out from each matching group -when computing the unique entity name. e.g. If `group` is `org/teams`, the name for `org/teams/avengers/gotg` will -be `avengers-gotg`. +When the `group` parameter is provided, the corresponding path prefix will be +stripped out from each matching group when computing the unique entity name. +e.g. If `group` is `org/teams`, the name for `org/teams/avengers/gotg` will be +`avengers-gotg`. diff --git a/docs/local-dev/cli-build-system.md b/docs/local-dev/cli-build-system.md index a86c0eaa35..a5df84f8dc 100644 --- a/docs/local-dev/cli-build-system.md +++ b/docs/local-dev/cli-build-system.md @@ -505,6 +505,7 @@ of all supported file extensions: | `.jpg` | URL Path | Image | | `.png` | URL Path | Image | | `.svg` | URL Path | Image | +| `.md` | URL Path | Markdown File | | `.icon.svg` | React Component | SVG converted into a [MUI SvgIcon](https://mui.com/components/icons/#svgicon) | ## Jest Configuration diff --git a/docs/local-dev/cli-commands.md b/docs/local-dev/cli-commands.md index 8c1e061237..c4c057ffe6 100644 --- a/docs/local-dev/cli-commands.md +++ b/docs/local-dev/cli-commands.md @@ -73,7 +73,7 @@ Build packages in the project, excluding bundled app and backend packages. Options: --all Build all packages, including bundled app and backend packages. - --since <ref> Only build packages and their dev dependents that changed since the specified ref + --since Only build packages and their dev dependents that changed since the specified ref ``` ## repo lint @@ -86,8 +86,8 @@ Usage: backstage-cli repo lint [options] Lint all packages in the project Options: - --format <format> Lint report output format (default: "eslint-formatter-friendly") - --since <ref> Only lint packages that changed since the specified ref + --format Lint report output format (default: "eslint-formatter-friendly") + --since Only lint packages that changed since the specified ref --fix Attempt to automatically fix violations ``` @@ -101,8 +101,8 @@ Usage: backstage-cli package start [options] Start a package for local development Options: - --config <path> Config files to load instead of app-config.yaml (default: []) - --role <name> Run the command with an explicit package role + --config Config files to load instead of app-config.yaml (default: []) + --role Run the command with an explicit package role --check Enable type checking and linting if available --inspect Enable debugger in Node.js environments --inspect-brk Enable debugger in Node.js environments, breaking before code starts @@ -118,11 +118,11 @@ Usage: backstage-cli package build [options] Build a package for production deployment or publishing Options: - --role <name> Run the command with an explicit package role + --role Run the command with an explicit package role --minify Minify the generated code. Does not apply to app or backend packages. --skip-build-dependencies Skip the automatic building of local dependencies. Applies to backend packages only. --stats If bundle stats are available, write them to the output directory. Applies to app packages only. - --config <path> Config files to load instead of app-config.yaml. Applies to app packages only. (default: []) + --config Config files to load instead of app-config.yaml. Applies to app packages only. (default: []) ``` ## package lint @@ -138,7 +138,7 @@ Usage: backstage-cli package lint [options] Lint a package Options: - --format <format> Lint report output format (default: "eslint-formatter-friendly") + --format Lint report output format (default: "eslint-formatter-friendly") --fix Attempt to automatically fix violations ``` @@ -227,10 +227,10 @@ that owns the app repo. For example you may have it set up like this: Usage: backstage-cli create [options] Options: - --select <name> Select the thing you want to be creating upfront - --option <name>=<value> Pre-fill options for the creation process (default: []) - --scope <scope> The scope to use for new packages - --npm-registry <URL> The package registry to use for new packages + --select Select the thing you want to be creating upfront + --option = Pre-fill options for the creation process (default: []) + --scope The scope to use for new packages + --npm-registry The package registry to use for new packages --no-private Do not mark new packages as private -h, --help display help for command ``` @@ -248,7 +248,7 @@ Usage: backstage-cli config:docs [options] Browse the configuration reference documentation Options: - --package <name> Only include the schema that applies to the given package + --package Only include the schema that applies to the given package -h, --help display help for command ``` @@ -268,12 +268,12 @@ yarn backstage-cli config:print --frontend --package my-app Usage: backstage-cli config:print [options] Options: - --package <name> Only load config schema that applies to the given package + --package Only load config schema that applies to the given package --lax Do not require environment variables to be set --frontend Print only the frontend configuration --with-secrets Include secrets in the printed configuration - --format <format> Format to print the configuration in, either json or yaml [yaml] - --config <path> Config files to load instead of app-config.yaml (default: []) + --format Format to print the configuration in, either json or yaml [yaml] + --config Config files to load instead of app-config.yaml (default: []) -h, --help display help for command ``` @@ -287,11 +287,11 @@ local packages in the repo. Usage: backstage-cli config:check [options] Options: - --package <name> Only load config schema that applies to the given package + --package Only load config schema that applies to the given package --lax Do not require environment variables to be set --frontend Only validate the frontend configuration --deprecated List all deprecated configuration settings - --config <path> Config files to load instead of app-config.yaml (default: []) + --config Config files to load instead of app-config.yaml (default: []) -h, --help display help for command ``` @@ -309,8 +309,8 @@ Usage: backstage-cli config:schema [options] Print configuration schema Options: - --package <name> Only output config schema that applies to the given package - --format <format> Format to print the schema in, either json or yaml [yaml] + --package Only output config schema that applies to the given package + --format Format to print the schema in, either json or yaml [yaml] -h, --help display help for command ``` @@ -325,8 +325,8 @@ Usage: backstage-cli versions:bump [options] Options: -h, --help display help for command - --pattern <glob> Override glob for matching packages to upgrade - --release <version|next|main> Bump to a specific Backstage release line or version (default: "main") + --pattern Override glob for matching packages to upgrade + --release Bump to a specific Backstage release line or version (default: "main") ``` ## versions:check diff --git a/docs/permissions/plugin-authors/03-adding-a-resource-permission-check.md b/docs/permissions/plugin-authors/03-adding-a-resource-permission-check.md index e714301ded..103e463cda 100644 --- a/docs/permissions/plugin-authors/03-adding-a-resource-permission-check.md +++ b/docs/permissions/plugin-authors/03-adding-a-resource-permission-check.md @@ -91,7 +91,7 @@ This enables decisions based on characteristics of the resource, but it's import Install the missing module: ```bash -$ yarn workspace @internal/plugin-todo-list-backend add @backstage/plugin-permission-node zod +$ yarn workspace @internal/plugin-todo-list-backend add @backstage/plugin-permission-node zod@~3.18.0 ``` Create a new `plugins/todo-list-backend/src/service/rules.ts` file and append the following code: diff --git a/docs/plugins/composability.md b/docs/plugins/composability.md index 1c64fd3f68..124a612f26 100644 --- a/docs/plugins/composability.md +++ b/docs/plugins/composability.md @@ -480,7 +480,7 @@ function isKind(kind: string) { ``` The `@backstage/catalog` plugin provides a couple of built-in conditions, -`isKind`, `isComponentType`, and `isNamespace`. +`isKind`, `isComponentType`, `isResourceType`, `isEntityWith`, and `isNamespace`. In addition to the `EntitySwitch` component, the catalog plugin also exports a new `EntityLayout` component. It is a tweaked version and replacement for the diff --git a/docs/plugins/integrating-search-into-plugins.md b/docs/plugins/integrating-search-into-plugins.md index 4e829b6ae9..7fb8e40b20 100644 --- a/docs/plugins/integrating-search-into-plugins.md +++ b/docs/plugins/integrating-search-into-plugins.md @@ -142,7 +142,7 @@ export class FaqCollatorFactory implements DocumentCollatorFactory { To verify your implementation works as expected make sure to add tests for it. For your convenience, there is the [`TestPipeline`](https://backstage.io/docs/reference/plugin-search-backend-node.testpipeline) utility that emulates a pipeline into which you can integrate your custom collator. -Look at [DefaultTechDocsCollatorFactory test](https://github.com/backstage/backstage/blob/master/plugins/techdocs-backend/src/search/DefaultTechDocsCollatorFactory.test.ts), for an example. +Look at [DefaultTechDocsCollatorFactory test](https://github.com/backstage/backstage/blob/de294ce5c410c9eb56da6870a1fab795268f60e3/plugins/techdocs-backend/src/search/DefaultTechDocsCollatorFactory.test.ts), for an example. #### 6. Make your plugins collator discoverable for others diff --git a/docs/releases/v1.12.0.md b/docs/releases/v1.12.0.md new file mode 100644 index 0000000000..789be8beca --- /dev/null +++ b/docs/releases/v1.12.0.md @@ -0,0 +1,62 @@ +--- +id: v1.12.0 +title: v1.12.0 +description: Backstage Release v1.12.0 +--- + +These are the release notes for the v1.12.0 release of [Backstage](https://backstage.io/). + +A huge thanks to the whole team of maintainers and contributors as well as the amazing Backstage Community for the hard work in getting this release developed and done. + +## Highlights + +This release mostly contains a bunch of smaller additions and bug fixes, but on top of that, there’s also some quality of life improvements and features as listed below. Enjoy! + +### Using `zod` for action definitions + +As a convenience, it is now possible to define your action inputs and outputs as `zod` schemas. This tends to be more convenient than writing JSON schema by hand, and gives you instant type feedback in your editor. + +Added by [@zcason](https://github.com/zcason) in [#15561](https://github.com/backstage/backstage/pull/15561) + +### Reading paginated data from the catalog + +The catalog has a new backend endpoint and corresponding client method, for fetching entities with proper cursor based pagination and server side filtering and ordering. This will be used to target performance hot-spots in the frontend and elsewhere. + +Added by [@vinzscam](https://github.com/vinzscam) in [#12246](https://github.com/backstage/backstage/pull/12246) + +### Renamed backend system related plugin exports + +As we settle the new backend system bit by bit, we have renamed a number of exports from individual plugins, to match the new [recommended naming patterns](https://backstage.io/docs/backend-system/architecture/naming-patterns). If you are already leveraging the new backend system, you may find that you need to update some imports. For example, `githubEntityProviderCatalogModule` was renamed to `catalogModuleGithubEntityProvider`. These were considered non-breaking since they are still in alpha. More details can be found in [#16760](https://github.com/backstage/backstage/pull/16760) and [#16764](https://github.com/backstage/backstage/pull/16764). + +### New plugin: `catalog-backend` `puppetdb` module + +Added a `catalogModulePuppetDbEntityProvider` alpha export for the new backend system. Contributed by [@tdabasinskas](https://github.com/tdabasinskas) in [#16184](https://github.com/backstage/backstage/pull/16184) + +### New plugin: Octopus deploy + +[Octopus](https://octopus.com) deployment plugin. Contributed by [@jmezach](https://github.com/jmezach) in [#16353](https://github.com/backstage/backstage/pull/16353) + +### New plugin: StackStorm + +Integration with [StackStorm](https://stackstorm.com). Contributed by [@pamelin](https://github.com/pamelin) in [#16152](https://github.com/backstage/backstage/pull/16152) + +## Security Fixes + +This release does not contain any security fixes. + +## Upgrade path + +We recommend that you keep your Backstage project up to date with this latest release. For more guidance on how to upgrade, check out the documentation for [keeping Backstage updated](https://backstage.io/docs/getting-started/keeping-backstage-updated). + +## Links and References + +Below you can find a list of links and references to help you learn about and start using this new release. + +- [Backstage official website](https://backstage.io/), [documentation](https://backstage.io/docs/), and [getting started guide](https://backstage.io/docs/getting-started/) +- [GitHub repository](https://github.com/backstage/backstage) +- Backstage's [versioning and support policy](https://backstage.io/docs/overview/versioning-policy) +- [Community Discord](https://discord.gg/backstage-687207715902193673) for discussions and support +- [Changelog](https://github.com/backstage/backstage/tree/master/docs/releases/v1.12.0-changelog.md) +- Backstage [Demos](https://backstage.io/demos), [Blog](https://backstage.io/blog), [Roadmap](https://backstage.io/docs/overview/roadmap) and [Plugins](https://backstage.io/plugins) + +Sign up for our [newsletter](https://mailchi.mp/spotify/backstage-community) if you want to be informed about what is happening in the world of Backstage. diff --git a/docs/releases/v1.13.0-next.0-changelog.md b/docs/releases/v1.13.0-next.0-changelog.md new file mode 100644 index 0000000000..3075d80f61 --- /dev/null +++ b/docs/releases/v1.13.0-next.0-changelog.md @@ -0,0 +1,2387 @@ +# Release v1.13.0-next.0 + +## @backstage/app-defaults@1.3.0-next.0 + +### Minor Changes + +- 7908d72e033: Introduce a new global config parameter, `auth.enableExperimentalRedirectFlow`. When enabled, auth will happen with an in-window redirect flow rather than through a popup window. + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-app-api@1.7.0-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/plugin-permission-react@0.4.11 + - @backstage/theme@0.2.18 + +## @backstage/core-app-api@1.7.0-next.0 + +### Minor Changes + +- 7908d72e033: Introduce a new global config parameter, `auth.enableExperimentalRedirectFlow`. When enabled, auth will happen with an in-window redirect flow rather than through a popup window. + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.5.0 + - @backstage/config@1.0.7 + - @backstage/types@1.0.2 + - @backstage/version-bridge@1.0.3 + +## @backstage/test-utils@1.3.0-next.0 + +### Minor Changes + +- 7908d72e033: Introduce a new global config parameter, `auth.enableExperimentalRedirectFlow`. When enabled, auth will happen with an in-window redirect flow rather than through a popup window. + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.7.0-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/config@1.0.7 + - @backstage/plugin-permission-react@0.4.11 + - @backstage/theme@0.2.18 + - @backstage/types@1.0.2 + - @backstage/plugin-permission-common@0.7.4 + +## @backstage/plugin-catalog@1.10.0-next.0 + +### Minor Changes + +- 4dbf3d3e4da: Added a new EntitySwitch isResourceType to allow different views depending on Resource type +- fc6cab4eb48: Added `isEntityWith` condition helper for `EntitySwitch` case statements. + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-search-react@1.5.2-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/integration-react@1.1.12-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + - @backstage/types@1.0.2 + - @backstage/plugin-catalog-common@1.0.12 + - @backstage/plugin-search-common@1.2.2 + +## @backstage/plugin-catalog-backend-module-gitlab@0.2.0-next.0 + +### Minor Changes + +- f64345108a0: **BREAKING**: The configuration of the `GitlabDiscoveryEntityProvider` has changed as follows: + + - The configuration key `branch` is now used to define the branch from which the catalog-info should be discovered. + - The old configuration key `branch` is now called `fallbackBranch`. This value specifies which branch should be used + if no default branch is defined on the project itself. + + To migrate to the new configuration value, rename `branch` to `fallbackBranch` + +### Patch Changes + +- 7b1b7bfdb7b: The gitlab org data integration now makes use of the GraphQL API to determine + the relationships between imported User and Group entities, effectively making + this integration usable without an administrator account's Personal Access + Token. +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/types@1.0.2 + - @backstage/plugin-catalog-node@1.3.5-next.0 + +## @backstage/plugin-entity-feedback@0.2.0-next.0 + +### Minor Changes + +- 7eba760e6f6: Added an endpoint to fetch anonymous aggregated results from an entity + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/plugin-entity-feedback-common@0.1.1-next.0 + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + +## @backstage/plugin-kubernetes-backend@0.10.0-next.0 + +### Minor Changes + +- 804f6d16b0c: **BREAKING**: `KubernetesBuilder.create` now requires a `permissions` field of type `PermissionEvaluator`. The kubernetes `/proxy` endpoint now requires two tokens: the `Backstage-Kubernetes-Authorization` header should contain a bearer token for the target cluster, and the `Authorization` header should contain a backstage identity token. The kubernetes `/proxy` endpoint now requires a `Backstage-Kubernetes-Cluster` header replacing the previously required `X-Kubernetes-Cluster` header. + +### Patch Changes + +- 75d4985f5e8: Fixes bug whereby backstage crashes when bad credentials are provided to the kubernetes plugin. +- 83d250badc6: Fix parsing error when kubernetes api is returning badly structured data. +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/plugin-kubernetes-common@0.6.2-next.0 + - @backstage/config@1.0.7 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/plugin-auth-node@0.2.13-next.0 + - @backstage/plugin-permission-common@0.7.4 + - @backstage/plugin-permission-node@0.7.7-next.0 + +## @backstage/plugin-scaffolder@1.13.0-next.0 + +### Minor Changes + +- cdab34fd9a2: scaffolder/next: removing the `routeRefs` and exporting the originals on `scaffolderPlugin.routes.x` instead +- e5ad1bd61ec: Allow `TemplateListPage` and `TemplateWizardPage` to be passed in as props +- 92cf86a4b5d: Added a `templateFilter` prop to the `` component to allow for filtering of templates through a function. +- 259d3407b9b: Move `CategoryPicker` from `scaffolder` into `scaffolder-react` + Move `ContextMenu` into `scaffolder-react` and rename it to `ScaffolderPageContextMenu` + +### Patch Changes + +- e27ddc36dad: Added a possibility to cancel the running task (executing of a scaffolder template) + +- 57c1b4752fa: Allow use of `{ exists: true }` value inside filters to filter entities that has that key. + + this example will filter all entities that has the annotation `someAnnotation` set to any value. + + ```yaml + ui:options: + catalogFilter: + kind: Group + metadata.annotations.someAnnotation: { exists: true } + ``` + +- 7a6b16cc506: `scaffolder/next`: Bump `@rjsf/*` deps to 5.3.1 + +- f84fc7fd040: Updated dependency `@rjsf/validator-ajv8` to `5.3.0`. + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) + +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.3.0-next.0 + - @backstage/plugin-scaffolder-common@1.2.7-next.0 + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/integration-react@1.1.12-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/plugin-permission-react@0.4.11 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + - @backstage/types@1.0.2 + - @backstage/plugin-catalog-common@1.0.12 + +## @backstage/plugin-scaffolder-backend-module-gitlab@0.1.0-next.0 + +### Minor Changes + +- 1ad400bb2de: Add Gitlab Scaffolder Plugin + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.1.2-next.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/errors@1.1.5 + +## @backstage/plugin-scaffolder-react@1.3.0-next.0 + +### Minor Changes + +- 259d3407b9b: Move `CategoryPicker` from `scaffolder` into `scaffolder-react` + Move `ContextMenu` into `scaffolder-react` and rename it to `ScaffolderPageContextMenu` +- 2cfd03d7376: To offer better customization options, `ScaffolderPageContextMenu` takes callbacks as props instead of booleans +- 48da4c46e45: `scaffolder/next`: Export the `TemplateGroupFilter` and `TemplateGroups` and make an extensible component + +### Patch Changes + +- e27ddc36dad: Added a possibility to cancel the running task (executing of a scaffolder template) +- 7a6b16cc506: `scaffolder/next`: Bump `@rjsf/*` deps to 5.3.1 +- f84fc7fd040: Updated dependency `@rjsf/validator-ajv8` to `5.3.0`. +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.2.7-next.0 + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + - @backstage/types@1.0.2 + - @backstage/version-bridge@1.0.3 + +## @backstage/plugin-vault-backend@0.3.0-next.0 + +### Minor Changes + +- 5e959c9eb62: Allow generic Vault clients to be passed into the builder + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/errors@1.1.5 + +## @backstage/backend-app-api@0.4.2-next.0 + +### Patch Changes + +- 8cce2205a39: Register unhandled rejection and uncaught exception handlers to avoid backend crashes. +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/cli-common@0.1.12 + - @backstage/config-loader@1.1.9 + - @backstage/errors@1.1.5 + - @backstage/types@1.0.2 + - @backstage/plugin-auth-node@0.2.13-next.0 + - @backstage/plugin-permission-node@0.7.7-next.0 + +## @backstage/backend-common@0.18.4-next.0 + +### Patch Changes + +- 420164593cf: Improve GitlabUrlReader to only load requested sub-path +- Updated dependencies + - @backstage/backend-app-api@0.4.2-next.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/integration-aws-node@0.1.2 + - @backstage/backend-dev-utils@0.1.1 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/cli-common@0.1.12 + - @backstage/config-loader@1.1.9 + - @backstage/errors@1.1.5 + - @backstage/types@1.0.2 + +## @backstage/backend-defaults@0.1.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-app-api@0.4.2-next.0 + - @backstage/backend-common@0.18.4-next.0 + - @backstage/backend-plugin-api@0.5.1-next.0 + +## @backstage/backend-plugin-api@0.5.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.0.7 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/types@1.0.2 + - @backstage/plugin-auth-node@0.2.13-next.0 + - @backstage/plugin-permission-common@0.7.4 + +## @backstage/backend-tasks@0.5.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/errors@1.1.5 + - @backstage/types@1.0.2 + +## @backstage/backend-test-utils@0.1.36-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-app-api@0.4.2-next.0 + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/types@1.0.2 + - @backstage/plugin-auth-node@0.2.13-next.0 + +## @backstage/cli@0.22.6-next.0 + +### Patch Changes + +- b9839d7135c: Fixed backend start command on Windows by removing the use of platform dependent path joins. +- c07c3b7364b: Add `onboard` command. While still in development, this command aims to guide users in setting up their Backstage App. +- Updated dependencies + - @backstage/eslint-plugin@0.1.3-next.0 + - @backstage/config@1.0.7 + - @backstage/release-manifests@0.0.9 + - @backstage/cli-common@0.1.12 + - @backstage/config-loader@1.1.9 + - @backstage/errors@1.1.5 + - @backstage/types@1.0.2 + +## @backstage/core-components@0.12.6-next.0 + +### Patch Changes + +- 7908d72e033: Introduce a new global config parameter, `auth.enableExperimentalRedirectFlow`. When enabled, auth will happen with an in-window redirect flow rather than through a popup window. +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- 7245e744ab1: Fixed the font color on `BackstageHeaderLabel` to respect the active page theme. +- Updated dependencies + - @backstage/core-plugin-api@1.5.0 + - @backstage/config@1.0.7 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + - @backstage/version-bridge@1.0.3 + +## @backstage/create-app@0.4.39-next.0 + +### Patch Changes + +- Bumped create-app version. +- Updated dependencies + - @backstage/cli-common@0.1.12 + +## @backstage/dev-utils@1.0.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/app-defaults@1.3.0-next.0 + - @backstage/core-app-api@1.7.0-next.0 + - @backstage/test-utils@1.3.0-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/integration-react@1.1.12-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + +## @backstage/eslint-plugin@0.1.3-next.0 + +### Patch Changes + +- 911c25de59c: Add support for auto-fixing missing imports detected by the `no-undeclared-imports` rule. + +## @backstage/integration-react@1.1.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/theme@0.2.18 + +## @backstage/repo-tools@0.1.4-next.0 + +### Patch Changes + +- 9129ca8cabb: Log API report instructions when api-report is missing. +- Updated dependencies + - @backstage/cli-common@0.1.12 + - @backstage/errors@1.1.5 + +## @techdocs/cli@1.4.1-next.0 + +### Patch Changes + +- b348420a804: Adding global-agent to enable the ability to publish through a proxy +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/catalog-model@1.2.1 + - @backstage/cli-common@0.1.12 + - @backstage/plugin-techdocs-node@1.6.1-next.0 + +## @backstage/plugin-adr@0.4.2-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-search-react@1.5.2-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/integration-react@1.1.12-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + - @backstage/plugin-adr-common@0.2.7 + - @backstage/plugin-search-common@1.2.2 + +## @backstage/plugin-adr-backend@0.3.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/plugin-adr-common@0.2.7 + - @backstage/plugin-search-common@1.2.2 + +## @backstage/plugin-airbrake@0.3.17-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/test-utils@1.3.0-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/dev-utils@1.0.14-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + +## @backstage/plugin-airbrake-backend@0.2.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + +## @backstage/plugin-allure@0.1.33-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + +## @backstage/plugin-analytics-module-ga@0.1.28-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/config@1.0.7 + - @backstage/theme@0.2.18 + +## @backstage/plugin-apache-airflow@0.2.10-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-plugin-api@1.5.0 + +## @backstage/plugin-api-docs@0.9.2-next.0 + +### Patch Changes + +- ca50c3bbea1: Corrected styling of nested objects in AsyncAPI to avoid inappropriate uppercase text transformation of nested objects. +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/plugin-catalog@1.10.0-next.0 + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + +## @backstage/plugin-apollo-explorer@0.1.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/theme@0.2.18 + +## @backstage/plugin-app-backend@0.3.44-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/config-loader@1.1.9 + - @backstage/types@1.0.2 + +## @backstage/plugin-auth-backend@0.18.2-next.0 + +### Patch Changes + +- d8f774c30df: Enforce the secret visibility of certificates and client secrets in the auth backend. Also, document all known options for each auth plugin. +- 7908d72e033: Introduce a new global config parameter, `auth.enableExperimentalRedirectFlow`. When enabled, auth will happen with an in-window redirect flow rather than through a popup window. +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/types@1.0.2 + - @backstage/plugin-auth-node@0.2.13-next.0 + +## @backstage/plugin-auth-node@0.2.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/errors@1.1.5 + +## @backstage/plugin-azure-devops@0.2.8-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + - @backstage/plugin-azure-devops-common@0.3.0 + +## @backstage/plugin-azure-devops-backend@0.3.23-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/plugin-azure-devops-common@0.3.0 + +## @backstage/plugin-azure-sites@0.1.6-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + - @backstage/plugin-azure-sites-common@0.1.0 + +## @backstage/plugin-azure-sites-backend@0.1.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/plugin-azure-sites-common@0.1.0 + +## @backstage/plugin-badges@0.2.41-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + +## @backstage/plugin-badges-backend@0.1.38-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + +## @backstage/plugin-bazaar@0.2.7-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/plugin-catalog@1.10.0-next.0 + - @backstage/core-components@0.12.6-next.0 + - @backstage/cli@0.22.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + +## @backstage/plugin-bazaar-backend@0.2.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/errors@1.1.5 + - @backstage/plugin-auth-node@0.2.13-next.0 + +## @backstage/plugin-bitrise@0.1.44-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + +## @backstage/plugin-catalog-backend@1.8.1-next.0 + +### Patch Changes + +- c9a0fdcd2c8: Fix deprecated types. +- 899ebfd8e02: Add full text search support to the `by-query` endpoint. +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.2.7-next.0 + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/types@1.0.2 + - @backstage/plugin-catalog-common@1.0.12 + - @backstage/plugin-catalog-node@1.3.5-next.0 + - @backstage/plugin-permission-common@0.7.4 + - @backstage/plugin-permission-node@0.7.7-next.0 + - @backstage/plugin-search-common@1.2.2 + +## @backstage/plugin-catalog-backend-module-aws@0.1.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/plugin-kubernetes-common@0.6.2-next.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/types@1.0.2 + - @backstage/plugin-catalog-common@1.0.12 + - @backstage/plugin-catalog-node@1.3.5-next.0 + +## @backstage/plugin-catalog-backend-module-azure@0.1.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/types@1.0.2 + - @backstage/plugin-catalog-node@1.3.5-next.0 + +## @backstage/plugin-catalog-backend-module-bitbucket@0.2.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/types@1.0.2 + - @backstage/plugin-bitbucket-cloud-common@0.2.4 + - @backstage/plugin-catalog-node@1.3.5-next.0 + +## @backstage/plugin-catalog-backend-module-bitbucket-cloud@0.1.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/plugin-bitbucket-cloud-common@0.2.4 + - @backstage/plugin-catalog-common@1.0.12 + - @backstage/plugin-catalog-node@1.3.5-next.0 + - @backstage/plugin-events-node@0.2.5-next.0 + +## @backstage/plugin-catalog-backend-module-bitbucket-server@0.1.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/plugin-catalog-node@1.3.5-next.0 + +## @backstage/plugin-catalog-backend-module-gerrit@0.1.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/plugin-catalog-node@1.3.5-next.0 + +## @backstage/plugin-catalog-backend-module-github@0.2.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.8.1-next.0 + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/types@1.0.2 + - @backstage/plugin-catalog-common@1.0.12 + - @backstage/plugin-catalog-node@1.3.5-next.0 + - @backstage/plugin-events-node@0.2.5-next.0 + +## @backstage/plugin-catalog-backend-module-incremental-ingestion@0.3.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.8.1-next.0 + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/plugin-catalog-node@1.3.5-next.0 + - @backstage/plugin-events-node@0.2.5-next.0 + - @backstage/plugin-permission-common@0.7.4 + +## @backstage/plugin-catalog-backend-module-ldap@0.5.11-next.0 + +### Patch Changes + +- c9a0fdcd2c8: Fix deprecated types. +- Updated dependencies + - @backstage/config@1.0.7 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/types@1.0.2 + - @backstage/plugin-catalog-common@1.0.12 + - @backstage/plugin-catalog-node@1.3.5-next.0 + +## @backstage/plugin-catalog-backend-module-msgraph@0.5.3-next.0 + +### Patch Changes + +- c9a0fdcd2c8: Fix deprecated types. +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/catalog-model@1.2.1 + - @backstage/plugin-catalog-common@1.0.12 + - @backstage/plugin-catalog-node@1.3.5-next.0 + +## @backstage/plugin-catalog-backend-module-openapi@0.1.10-next.0 + +### Patch Changes + +- c9a0fdcd2c8: Fix deprecated types. +- Updated dependencies + - @backstage/plugin-catalog-backend@1.8.1-next.0 + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/catalog-model@1.2.1 + - @backstage/types@1.0.2 + - @backstage/plugin-catalog-common@1.0.12 + - @backstage/plugin-catalog-node@1.3.5-next.0 + +## @backstage/plugin-catalog-backend-module-puppetdb@0.1.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/types@1.0.2 + - @backstage/plugin-catalog-node@1.3.5-next.0 + +## @backstage/plugin-catalog-graph@0.2.29-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + +## @backstage/plugin-catalog-graphql@0.3.20-next.0 + +### Patch Changes + +- e47e69eadf0: Updated dependency `@apollo/server` to `^4.0.0`. +- Updated dependencies + - @backstage/config@1.0.7 + - @backstage/catalog-model@1.2.1 + - @backstage/types@1.0.2 + +## @backstage/plugin-catalog-import@0.9.7-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/integration-react@1.1.12-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/plugin-catalog-common@1.0.12 + +## @backstage/plugin-catalog-node@1.3.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/types@1.0.2 + - @backstage/plugin-catalog-common@1.0.12 + +## @backstage/plugin-catalog-react@1.4.1-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/integration@1.4.3 + - @backstage/plugin-permission-react@0.4.11 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + - @backstage/types@1.0.2 + - @backstage/version-bridge@1.0.3 + - @backstage/plugin-catalog-common@1.0.12 + - @backstage/plugin-permission-common@0.7.4 + +## @backstage/plugin-cicd-statistics@0.1.19-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + +## @backstage/plugin-cicd-statistics-module-gitlab@0.1.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-cicd-statistics@0.1.19-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + +## @backstage/plugin-circleci@0.3.17-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + +## @backstage/plugin-cloudbuild@0.3.17-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + +## @backstage/plugin-code-climate@0.1.17-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + +## @backstage/plugin-code-coverage@0.2.10-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/config@1.0.7 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + +## @backstage/plugin-code-coverage-backend@0.2.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + +## @backstage/plugin-codescene@0.1.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/config@1.0.7 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + +## @backstage/plugin-config-schema@0.1.40-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/config@1.0.7 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + - @backstage/types@1.0.2 + +## @backstage/plugin-cost-insights@0.12.6-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/config@1.0.7 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + - @backstage/plugin-cost-insights-common@0.1.1 + +## @backstage/plugin-dynatrace@3.0.1-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + +## @backstage/plugin-entity-feedback-backend@0.1.2-next.0 + +### Patch Changes + +- 7eba760e6f6: Added an endpoint to fetch anonymous aggregated results from an entity +- Updated dependencies + - @backstage/plugin-entity-feedback-common@0.1.1-next.0 + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/plugin-auth-node@0.2.13-next.0 + +## @backstage/plugin-entity-feedback-common@0.1.1-next.0 + +### Patch Changes + +- 7eba760e6f6: Added an endpoint to fetch anonymous aggregated results from an entity + +## @backstage/plugin-entity-validation@0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + - @backstage/plugin-catalog-common@1.0.12 + +## @backstage/plugin-events-backend@0.2.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/plugin-events-node@0.2.5-next.0 + +## @backstage/plugin-events-backend-module-aws-sqs@0.1.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/types@1.0.2 + - @backstage/plugin-events-node@0.2.5-next.0 + +## @backstage/plugin-events-backend-module-azure@0.1.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/plugin-events-node@0.2.5-next.0 + +## @backstage/plugin-events-backend-module-bitbucket-cloud@0.1.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/plugin-events-node@0.2.5-next.0 + +## @backstage/plugin-events-backend-module-gerrit@0.1.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/plugin-events-node@0.2.5-next.0 + +## @backstage/plugin-events-backend-module-github@0.1.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.0.7 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/plugin-events-node@0.2.5-next.0 + +## @backstage/plugin-events-backend-module-gitlab@0.1.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.0.7 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/plugin-events-node@0.2.5-next.0 + +## @backstage/plugin-events-backend-test-utils@0.1.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.2.5-next.0 + +## @backstage/plugin-events-node@0.2.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.5.1-next.0 + +## @backstage/plugin-explore@0.4.2-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-search-react@1.5.2-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/plugin-explore-react@0.0.27 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + - @backstage/plugin-explore-common@0.0.1 + - @backstage/plugin-search-common@1.2.2 + +## @backstage/plugin-explore-backend@0.0.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/plugin-explore-common@0.0.1 + - @backstage/plugin-search-common@1.2.2 + +## @backstage/plugin-firehydrant@0.2.1-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + +## @backstage/plugin-fossa@0.2.49-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + +## @backstage/plugin-gcalendar@0.3.13-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + +## @backstage/plugin-gcp-projects@0.3.36-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/theme@0.2.18 + +## @backstage/plugin-git-release-manager@0.3.30-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/integration@1.4.3 + - @backstage/theme@0.2.18 + +## @backstage/plugin-github-actions@0.5.17-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/integration@1.4.3 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + +## @backstage/plugin-github-deployments@0.1.48-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/integration-react@1.1.12-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/integration@1.4.3 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + +## @backstage/plugin-github-issues@0.2.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/integration@1.4.3 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + +## @backstage/plugin-github-pull-requests-board@0.1.11-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/integration@1.4.3 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + +## @backstage/plugin-gitops-profiles@0.3.35-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/config@1.0.7 + - @backstage/theme@0.2.18 + +## @backstage/plugin-gocd@0.1.23-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + +## @backstage/plugin-graphiql@0.2.49-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/theme@0.2.18 + +## @backstage/plugin-graphql-backend@0.1.34-next.0 + +### Patch Changes + +- e47e69eadf0: Updated dependency `@apollo/server` to `^4.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-graphql@0.3.20-next.0 + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + +## @backstage/plugin-graphql-voyager@0.1.2-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/theme@0.2.18 + +## @backstage/plugin-home@0.4.33-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/config@1.0.7 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + +## @backstage/plugin-ilert@0.2.6-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + +## @backstage/plugin-jenkins@0.7.16-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + - @backstage/plugin-jenkins-common@0.1.14 + +## @backstage/plugin-jenkins-backend@0.1.34-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/plugin-auth-node@0.2.13-next.0 + - @backstage/plugin-jenkins-common@0.1.14 + - @backstage/plugin-permission-common@0.7.4 + +## @backstage/plugin-kafka@0.3.17-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/config@1.0.7 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + +## @backstage/plugin-kafka-backend@0.2.37-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + +## @backstage/plugin-kubernetes@0.7.10-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/plugin-kubernetes-common@0.6.2-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/config@1.0.7 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + +## @backstage/plugin-kubernetes-common@0.6.2-next.0 + +### Patch Changes + +- 804f6d16b0c: Introduced proxy permission types to be used with the kubernetes proxy endpoint's permission framework integration. +- Updated dependencies + - @backstage/catalog-model@1.2.1 + - @backstage/plugin-permission-common@0.7.4 + +## @backstage/plugin-lighthouse@0.4.2-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/config@1.0.7 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + - @backstage/plugin-lighthouse-common@0.1.1 + +## @backstage/plugin-lighthouse-backend@0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/types@1.0.2 + - @backstage/plugin-lighthouse-common@0.1.1 + +## @backstage/plugin-linguist@0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + - @backstage/plugin-linguist-common@0.1.0 + +## @backstage/plugin-linguist-backend@0.2.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/types@1.0.2 + - @backstage/plugin-auth-node@0.2.13-next.0 + - @backstage/plugin-linguist-common@0.1.0 + +## @backstage/plugin-microsoft-calendar@0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + +## @backstage/plugin-newrelic@0.3.35-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/theme@0.2.18 + +## @backstage/plugin-newrelic-dashboard@0.2.10-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + +## @backstage/plugin-octopus-deploy@0.1.1-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + +## @backstage/plugin-org@0.6.7-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + +## @backstage/plugin-org-react@0.1.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + +## @backstage/plugin-pagerduty@0.5.10-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + +## @backstage/plugin-periskop@0.1.15-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + +## @backstage/plugin-periskop-backend@0.1.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/backend-plugin-api@0.5.1-next.0 + +## @backstage/plugin-permission-backend@0.5.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/errors@1.1.5 + - @backstage/plugin-auth-node@0.2.13-next.0 + - @backstage/plugin-permission-common@0.7.4 + - @backstage/plugin-permission-node@0.7.7-next.0 + +## @backstage/plugin-permission-node@0.7.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/errors@1.1.5 + - @backstage/plugin-auth-node@0.2.13-next.0 + - @backstage/plugin-permission-common@0.7.4 + +## @backstage/plugin-playlist@0.1.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-search-react@1.5.2-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/plugin-permission-react@0.4.11 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + - @backstage/plugin-catalog-common@1.0.12 + - @backstage/plugin-permission-common@0.7.4 + - @backstage/plugin-playlist-common@0.1.5 + +## @backstage/plugin-playlist-backend@0.2.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/plugin-auth-node@0.2.13-next.0 + - @backstage/plugin-permission-common@0.7.4 + - @backstage/plugin-permission-node@0.7.7-next.0 + - @backstage/plugin-playlist-common@0.1.5 + +## @backstage/plugin-proxy-backend@0.2.38-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/backend-plugin-api@0.5.1-next.0 + +## @backstage/plugin-rollbar@0.4.17-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + +## @backstage/plugin-rollbar-backend@0.1.41-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + +## @backstage/plugin-scaffolder-backend@1.12.1-next.0 + +### Patch Changes + +- e23abb37ec1: Rename output parameter `mergeRequestURL` of `publish:gitlab:merge-request` action to `mergeRequestUrl`. +- e27ddc36dad: Added a possibility to cancel the running task (executing of a scaffolder template) +- c9a0fdcd2c8: Fix deprecated types. +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.1.2-next.0 + - @backstage/plugin-scaffolder-common@1.2.7-next.0 + - @backstage/plugin-catalog-backend@1.8.1-next.0 + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/types@1.0.2 + - @backstage/plugin-auth-node@0.2.13-next.0 + - @backstage/plugin-catalog-common@1.0.12 + - @backstage/plugin-catalog-node@1.3.5-next.0 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.2.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.12.1-next.0 + - @backstage/plugin-scaffolder-node@0.1.2-next.0 + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/errors@1.1.5 + - @backstage/types@1.0.2 + +## @backstage/plugin-scaffolder-backend-module-rails@0.4.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.12.1-next.0 + - @backstage/plugin-scaffolder-node@0.1.2-next.0 + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/errors@1.1.5 + - @backstage/types@1.0.2 + +## @backstage/plugin-scaffolder-backend-module-sentry@0.1.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.1.2-next.0 + - @backstage/config@1.0.7 + - @backstage/errors@1.1.5 + +## @backstage/plugin-scaffolder-backend-module-yeoman@0.2.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.1.2-next.0 + - @backstage/config@1.0.7 + - @backstage/types@1.0.2 + +## @backstage/plugin-scaffolder-common@1.2.7-next.0 + +### Patch Changes + +- 48da4c46e45: Export `typeguard` for `isTemplateEntityV1beta3` +- Updated dependencies + - @backstage/catalog-model@1.2.1 + - @backstage/types@1.0.2 + +## @backstage/plugin-scaffolder-node@0.1.2-next.0 + +### Patch Changes + +- e27ddc36dad: Added a possibility to cancel the running task (executing of a scaffolder template) +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.2.7-next.0 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/catalog-model@1.2.1 + - @backstage/types@1.0.2 + +## @backstage/plugin-search@1.1.2-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-search-react@1.5.2-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/config@1.0.7 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + - @backstage/types@1.0.2 + - @backstage/version-bridge@1.0.3 + - @backstage/plugin-search-common@1.2.2 + +## @backstage/plugin-search-backend@1.2.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/errors@1.1.5 + - @backstage/types@1.0.2 + - @backstage/plugin-auth-node@0.2.13-next.0 + - @backstage/plugin-permission-common@0.7.4 + - @backstage/plugin-permission-node@0.7.7-next.0 + - @backstage/plugin-search-backend-node@1.1.5-next.0 + - @backstage/plugin-search-common@1.2.2 + +## @backstage/plugin-search-backend-module-elasticsearch@1.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.0.7 + - @backstage/plugin-search-backend-node@1.1.5-next.0 + - @backstage/plugin-search-common@1.2.2 + +## @backstage/plugin-search-backend-module-pg@0.5.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/plugin-search-backend-node@1.1.5-next.0 + - @backstage/plugin-search-common@1.2.2 + +## @backstage/plugin-search-backend-node@1.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/errors@1.1.5 + - @backstage/plugin-permission-common@0.7.4 + - @backstage/plugin-search-common@1.2.2 + +## @backstage/plugin-search-react@1.5.2-next.0 + +### Patch Changes + +- b2e182cdfa4: Fixes a UI bug in search result item which rendered the item text with incorrect font size and color +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/theme@0.2.18 + - @backstage/types@1.0.2 + - @backstage/version-bridge@1.0.3 + - @backstage/plugin-search-common@1.2.2 + +## @backstage/plugin-sentry@0.5.2-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + +## @backstage/plugin-shortcuts@0.3.9-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- 99df676e324: Allow external links to be added as shortcuts +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/theme@0.2.18 + - @backstage/types@1.0.2 + +## @backstage/plugin-sonarqube@0.6.6-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + - @backstage/plugin-sonarqube-react@0.1.4 + +## @backstage/plugin-sonarqube-backend@0.1.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/errors@1.1.5 + +## @backstage/plugin-splunk-on-call@0.4.6-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + +## @backstage/plugin-stack-overflow@0.1.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-search-react@1.5.2-next.0 + - @backstage/plugin-home@0.4.33-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/config@1.0.7 + - @backstage/theme@0.2.18 + - @backstage/plugin-search-common@1.2.2 + +## @backstage/plugin-stack-overflow-backend@0.1.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/plugin-search-common@1.2.2 + +## @backstage/plugin-stackstorm@0.1.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + +## @backstage/plugin-tech-insights@0.3.9-next.0 + +### Patch Changes + +- f538b9c5b83: The `Check` type now optionally includes the `failureMetadata` and `successMetadata` as returned by the `runChecks` call. +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + - @backstage/types@1.0.2 + - @backstage/plugin-tech-insights-common@0.2.10 + +## @backstage/plugin-tech-insights-backend@0.5.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/types@1.0.2 + - @backstage/plugin-tech-insights-common@0.2.10 + - @backstage/plugin-tech-insights-node@0.4.2-next.0 + +## @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/errors@1.1.5 + - @backstage/plugin-tech-insights-common@0.2.10 + - @backstage/plugin-tech-insights-node@0.4.2-next.0 + +## @backstage/plugin-tech-insights-node@0.4.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/types@1.0.2 + - @backstage/plugin-tech-insights-common@0.2.10 + +## @backstage/plugin-tech-radar@0.6.3-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/theme@0.2.18 + +## @backstage/plugin-techdocs@1.6.1-next.0 + +### Patch Changes + +- b2e182cdfa4: Fixes a UI bug in search result item which rendered the item text with incorrect font size and color +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-search-react@1.5.2-next.0 + - @backstage/plugin-techdocs-react@1.1.5-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/integration-react@1.1.12-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + - @backstage/plugin-search-common@1.2.2 + +## @backstage/plugin-techdocs-addons-test-utils@1.0.12-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/plugin-catalog@1.10.0-next.0 + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-app-api@1.7.0-next.0 + - @backstage/test-utils@1.3.0-next.0 + - @backstage/plugin-search-react@1.5.2-next.0 + - @backstage/plugin-techdocs@1.6.1-next.0 + - @backstage/plugin-techdocs-react@1.1.5-next.0 + - @backstage/integration-react@1.1.12-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/theme@0.2.18 + +## @backstage/plugin-techdocs-backend@1.6.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/plugin-catalog-common@1.0.12 + - @backstage/plugin-permission-common@0.7.4 + - @backstage/plugin-search-common@1.2.2 + - @backstage/plugin-techdocs-node@1.6.1-next.0 + +## @backstage/plugin-techdocs-module-addons-contrib@1.0.12-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-techdocs-react@1.1.5-next.0 + - @backstage/integration-react@1.1.12-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/integration@1.4.3 + - @backstage/theme@0.2.18 + +## @backstage/plugin-techdocs-node@1.6.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/integration-aws-node@0.1.2 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/plugin-search-common@1.2.2 + +## @backstage/plugin-techdocs-react@1.1.5-next.0 + +### Patch Changes + +- 7e0c7b09a47: Fix a bug that caused the header to not render when generating a document for the first time +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/config@1.0.7 + - @backstage/catalog-model@1.2.1 + - @backstage/version-bridge@1.0.3 + +## @backstage/plugin-todo@0.2.19-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + +## @backstage/plugin-todo-backend@0.1.41-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/plugin-catalog-node@1.3.5-next.0 + +## @backstage/plugin-user-settings@0.7.2-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-app-api@1.7.0-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + - @backstage/types@1.0.2 + +## @backstage/plugin-user-settings-backend@0.1.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/types@1.0.2 + - @backstage/plugin-auth-node@0.2.13-next.0 + +## @backstage/plugin-vault@0.1.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + +## @backstage/plugin-xcmetrics@0.2.37-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + +## example-app@0.2.82-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-api-docs@0.9.2-next.0 + - @backstage/plugin-scaffolder@1.13.0-next.0 + - @backstage/plugin-scaffolder-react@1.3.0-next.0 + - @backstage/plugin-entity-feedback@0.2.0-next.0 + - @backstage/plugin-tech-insights@0.3.9-next.0 + - @backstage/core-components@0.12.6-next.0 + - @backstage/app-defaults@1.3.0-next.0 + - @backstage/core-app-api@1.7.0-next.0 + - @backstage/plugin-search-react@1.5.2-next.0 + - @backstage/plugin-techdocs@1.6.1-next.0 + - @backstage/cli@0.22.6-next.0 + - @backstage/plugin-techdocs-react@1.1.5-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.0.12-next.0 + - @backstage/plugin-newrelic-dashboard@0.2.10-next.0 + - @backstage/plugin-apache-airflow@0.2.10-next.0 + - @backstage/plugin-catalog-import@0.9.7-next.0 + - @backstage/plugin-github-actions@0.5.17-next.0 + - @backstage/plugin-catalog-graph@0.2.29-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/plugin-code-coverage@0.2.10-next.0 + - @backstage/plugin-cost-insights@0.12.6-next.0 + - @backstage/plugin-user-settings@0.7.2-next.0 + - @backstage/plugin-azure-devops@0.2.8-next.0 + - @backstage/plugin-gcp-projects@0.3.36-next.0 + - @backstage/plugin-azure-sites@0.1.6-next.0 + - @backstage/plugin-cloudbuild@0.3.17-next.0 + - @backstage/plugin-kubernetes@0.7.10-next.0 + - @backstage/plugin-lighthouse@0.4.2-next.0 + - @backstage/plugin-tech-radar@0.6.3-next.0 + - @backstage/plugin-dynatrace@3.0.1-next.0 + - @backstage/plugin-gcalendar@0.3.13-next.0 + - @backstage/plugin-pagerduty@0.5.10-next.0 + - @backstage/plugin-shortcuts@0.3.9-next.0 + - @backstage/plugin-airbrake@0.3.17-next.0 + - @backstage/plugin-circleci@0.3.17-next.0 + - @backstage/plugin-graphiql@0.2.49-next.0 + - @backstage/plugin-newrelic@0.3.35-next.0 + - @backstage/plugin-explore@0.4.2-next.0 + - @backstage/plugin-jenkins@0.7.16-next.0 + - @backstage/plugin-rollbar@0.4.17-next.0 + - @backstage/plugin-badges@0.2.41-next.0 + - @backstage/plugin-search@1.1.2-next.0 + - @backstage/plugin-sentry@0.5.2-next.0 + - @backstage/plugin-kafka@0.3.17-next.0 + - @backstage/plugin-gocd@0.1.23-next.0 + - @backstage/plugin-home@0.4.33-next.0 + - @backstage/plugin-todo@0.2.19-next.0 + - @backstage/plugin-org@0.6.7-next.0 + - @internal/plugin-catalog-customized@0.0.9-next.0 + - @backstage/integration-react@1.1.12-next.0 + - @backstage/plugin-linguist@0.1.2-next.0 + - @backstage/plugin-microsoft-calendar@0.1.2-next.0 + - @backstage/plugin-playlist@0.1.8-next.0 + - @backstage/plugin-stack-overflow@0.1.13-next.0 + - @backstage/plugin-stackstorm@0.1.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/config@1.0.7 + - @backstage/plugin-permission-react@0.4.11 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + - @backstage/plugin-catalog-common@1.0.12 + - @backstage/plugin-linguist-common@0.1.0 + - @backstage/plugin-search-common@1.2.2 + +## example-backend@0.2.82-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.12.1-next.0 + - @backstage/plugin-kubernetes-backend@0.10.0-next.0 + - @backstage/plugin-entity-feedback-backend@0.1.2-next.0 + - @backstage/plugin-auth-backend@0.18.2-next.0 + - @backstage/plugin-catalog-backend@1.8.1-next.0 + - @backstage/plugin-graphql-backend@0.1.34-next.0 + - @backstage/backend-common@0.18.4-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.12-next.0 + - example-app@0.2.82-next.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/plugin-adr-backend@0.3.2-next.0 + - @backstage/plugin-app-backend@0.3.44-next.0 + - @backstage/plugin-auth-node@0.2.13-next.0 + - @backstage/plugin-azure-devops-backend@0.3.23-next.0 + - @backstage/plugin-azure-sites-backend@0.1.6-next.0 + - @backstage/plugin-badges-backend@0.1.38-next.0 + - @backstage/plugin-catalog-node@1.3.5-next.0 + - @backstage/plugin-code-coverage-backend@0.2.10-next.0 + - @backstage/plugin-events-backend@0.2.5-next.0 + - @backstage/plugin-events-node@0.2.5-next.0 + - @backstage/plugin-explore-backend@0.0.6-next.0 + - @backstage/plugin-jenkins-backend@0.1.34-next.0 + - @backstage/plugin-kafka-backend@0.2.37-next.0 + - @backstage/plugin-lighthouse-backend@0.1.2-next.0 + - @backstage/plugin-linguist-backend@0.2.1-next.0 + - @backstage/plugin-permission-backend@0.5.19-next.0 + - @backstage/plugin-permission-common@0.7.4 + - @backstage/plugin-permission-node@0.7.7-next.0 + - @backstage/plugin-playlist-backend@0.2.7-next.0 + - @backstage/plugin-proxy-backend@0.2.38-next.0 + - @backstage/plugin-rollbar-backend@0.1.41-next.0 + - @backstage/plugin-search-backend@1.2.5-next.0 + - @backstage/plugin-search-backend-module-elasticsearch@1.1.5-next.0 + - @backstage/plugin-search-backend-module-pg@0.5.5-next.0 + - @backstage/plugin-search-backend-node@1.1.5-next.0 + - @backstage/plugin-search-common@1.2.2 + - @backstage/plugin-tech-insights-backend@0.5.10-next.0 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.28-next.0 + - @backstage/plugin-tech-insights-node@0.4.2-next.0 + - @backstage/plugin-techdocs-backend@1.6.1-next.0 + - @backstage/plugin-todo-backend@0.1.41-next.0 + +## example-backend-next@0.0.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.12.1-next.0 + - @backstage/plugin-catalog-backend@1.8.1-next.0 + - @backstage/backend-defaults@0.1.9-next.0 + - @backstage/plugin-app-backend@0.3.44-next.0 + - @backstage/plugin-techdocs-backend@1.6.1-next.0 + - @backstage/plugin-todo-backend@0.1.41-next.0 + +## e2e-test@0.2.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.4.39-next.0 + - @backstage/cli-common@0.1.12 + - @backstage/errors@1.1.5 + +## techdocs-cli-embedded-app@0.2.81-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.10.0-next.0 + - @backstage/core-components@0.12.6-next.0 + - @backstage/app-defaults@1.3.0-next.0 + - @backstage/core-app-api@1.7.0-next.0 + - @backstage/test-utils@1.3.0-next.0 + - @backstage/plugin-techdocs@1.6.1-next.0 + - @backstage/cli@0.22.6-next.0 + - @backstage/plugin-techdocs-react@1.1.5-next.0 + - @backstage/integration-react@1.1.12-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/config@1.0.7 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + +## @internal/plugin-catalog-customized@0.0.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.10.0-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + +## @internal/plugin-todo-list@1.0.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/theme@0.2.18 + +## @internal/plugin-todo-list-backend@1.0.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/errors@1.1.5 + - @backstage/plugin-auth-node@0.2.13-next.0 diff --git a/microsite/.prettierignore b/microsite/.prettierignore index b52c4a85c3..65d3600479 100644 --- a/microsite/.prettierignore +++ b/microsite/.prettierignore @@ -1 +1,2 @@ +build .docusaurus diff --git a/microsite/README.md b/microsite/README.md index 723baa1a54..26c25dc175 100644 --- a/microsite/README.md +++ b/microsite/README.md @@ -1,6 +1,6 @@ # Backstage Documentation -This folder holds the service and configuration that runs Backstage's documentation hosted at https://backstage.io. +This folder holds the service and configuration that runs Backstage's documentation hosted at . It pulls content in from the [root `/docs`](../docs/) folder and builds it into the resulting HTML web site. @@ -20,13 +20,13 @@ Testing the web site locally is a great way to see what final website will look ## Installation -``` +```bash $ yarn install ``` ## Local Development -``` +```bash $ yarn start ``` @@ -34,7 +34,7 @@ This command starts a local development server and opens up a browser window. Mo ## Build -``` +```bash $ yarn build ``` @@ -107,30 +107,30 @@ For more information about blog posts, click [here](https://docusaurus.io/docs/e 1. Create the doc as a new markdown file in `/docs`, example `docs/newly-created-doc.md`: -```md ---- -id: newly-created-doc -title: This Doc Needs To Be Edited ---- + ```md + --- + id: newly-created-doc + title: This Doc Needs To Be Edited + --- -My new content here.. -``` + My new content here.. + ``` -1. Refer to that doc's ID in an existing sidebar in `website/sidebars.json`: +2. Refer to that doc's ID in an existing sidebar in `website/sidebars.json`: -```javascript -// Add newly-created-doc to the Getting Started category of docs -{ - "docs": { - "Getting Started": [ - "quick-start", - "newly-created-doc" // new doc here - ], - ... - }, - ... -} -``` + ```javascript + // Add newly-created-doc to the Getting Started category of docs + { + "docs": { + "Getting Started": [ + "quick-start", + "newly-created-doc" // new doc here + ], + ... + }, + ... + } + ``` For more information about adding new docs, click [here](https://docusaurus.io/docs/en/navigation) @@ -138,30 +138,30 @@ For more information about adding new docs, click [here](https://docusaurus.io/d 1. Make sure there is a header link to your blog in `website/siteConfig.js`: -`website/siteConfig.js` + `website/siteConfig.js` -```javascript -headerLinks: [ - ... - { blog: true, label: 'Blog' }, - ... -] -``` + ```javascript + headerLinks: [ + ... + { blog: true, label: 'Blog' }, + ... + ] + ``` 2. Create the blog post with the format `YYYY-MM-DD-My-Blog-Post-Title.md` in `website/blog`: -`website/blog/2018-05-21-New-Blog-Post.md` + `website/blog/2018-05-21-New-Blog-Post.md` -```markdown ---- -author: Frank Li -authorURL: https://twitter.com/foobarbaz -authorFBID: 503283835 -title: New Blog Post ---- + ```markdown + --- + author: Frank Li + authorURL: https://twitter.com/foobarbaz + authorFBID: 503283835 + title: New Blog Post + --- -Lorem Ipsum... -``` + Lorem Ipsum... + ``` For more information about blog posts, click [here](https://docusaurus.io/docs/en/adding-blog) @@ -169,43 +169,44 @@ For more information about blog posts, click [here](https://docusaurus.io/docs/e 1. Add links to docs, custom pages or external links by editing the `headerLinks` field of `website/siteConfig.js`: -`website/siteConfig.js` + `website/siteConfig.js` -```javascript -{ - headerLinks: [ - ... - /* you can add docs */ - { doc: 'my-examples', label: 'Examples' }, - /* you can add custom pages */ - { page: 'help', label: 'Help' }, - /* you can add external links */ - { href: 'https://github.com/facebook/docusaurus', label: 'GitHub' }, - ... - ], - ... -} -``` + ```javascript + { + headerLinks: [ + ... + /* you can add docs */ + { doc: 'my-examples', label: 'Examples' }, + /* you can add custom pages */ + { page: 'help', label: 'Help' }, + /* you can add external links */ + { href: 'https://github.com/facebook/docusaurus', label: 'GitHub' }, + ... + ], + ... + } + ``` For more information about the navigation bar, click [here](https://docusaurus.io/docs/en/navigation) ### Adding custom pages 1. Docusaurus uses React components to build pages. The components are saved as .js files in `website/pages/en`: -1. If you want your page to show up in your navigation header, you will need to update `website/siteConfig.js` to add to the `headerLinks` element: -`website/siteConfig.js` +2. If you want your page to show up in your navigation header, you will need to update `website/siteConfig.js` to add to the `headerLinks` element: -```javascript -{ - headerLinks: [ - ... - { page: 'my-new-custom-page', label: 'My New Custom Page' }, - ... - ], - ... -} -``` + `website/siteConfig.js` + + ```javascript + { + headerLinks: [ + ... + { page: 'my-new-custom-page', label: 'My New Custom Page' }, + ... + ], + ... + } + ``` Learn more about [Docusaurus custom pages](https://docusaurus.io/docs/en/custom-pages). @@ -216,4 +217,19 @@ Full documentation can be found on the [Docusaurus website](https://docusaurus.i ## Additional notes - If you want to make images zoomable on click, add the `data-zoomable` attribute to your `img` element. + - In a docs or blog `.md` file, convert `![This is image](/microsite/static/img/code.png)` syntax to `This is image` + +- Code block line highlighting uses [custom magic comments](https://docusaurus.io/docs/markdown-features/code-blocks#custom-magic-comments). Currently, we have the following magic comments: + - Highlight line(s) + - `highlight-next-line` + - `highlight-start` + - `highlight-end` + - Add line(s) + - `highlight-add-next-line` + - `highlight-add-start` + - `highlight-add-end` + - Remove line(s) + - `highlight-remove-next-line` + - `highlight-remove-start` + - `highlight-remove-end` diff --git a/microsite/blog/2023-03-15-backstage-turns-3.md b/microsite/blog/2023-03-15-backstage-turns-3.md new file mode 100644 index 0000000000..317cdc0c4d --- /dev/null +++ b/microsite/blog/2023-03-15-backstage-turns-3.md @@ -0,0 +1,84 @@ +--- +title: Backstage Turns Three! +author: Ben Lambert +authorURL: https://github.com/benjdlambert +authorImageURL: https://avatars.githubusercontent.com/u/3645856?v=4 +--- + +![backstage turns 3 header image](assets/2023-03-15/birthday.gif) + +**TL;DR** Spotify released Backstage into open source three years ago today. Since then, the community has grown by leaps and bounds to stretch across the globe (and the Discord server!). Now that Backstage is a threenager, the growing pains are real. So, on this birthday, we want to cover our collective efforts to make it easier to adopt and contribute to Backstage. + + + +## They grow up so fast, don’t they? + +Happy birthday, Backstage! Three years ago, Spotify released its homegrown developer portal into the wild after a small team collaborated on an internal Hack Week project. We’d had a lot of conversations with companies looking to build out something similar to what we’d been running for years, so our Hack Week sprint started as an experiment to see if the Backstage core plugins could be valuable in open source. + +It's cliché at this point — because we’ve said it a million times — but no one could have predicted what came next. + +In three short years, Backstage has grown to a Cloud Native Computing Foundation Incubating project, with more than 900 adopters and 1000+ contributors worldwide. Companies like CVS Health, Siemens, LinkedIn, REI, Vodafone, and Lego are building out their own developer portals from the Backstage framework and bringing their learnings to the project. + +A few more stats we love to see (mainly coming from the [project repo](https://github.com/backstage/backstage)): + +- 3k+ project forks +- 38k+ commits +- 12k+ PRs +- 15k+ total contributions +- 21k+ stars on GitHub +- 9k+ Discord members +- 100+ open source plugins in the [plugin marketplace](https://backstage.io/plugins) + +But, without a doubt, the best thing about the Backstage project is the people in this community. People who are curious, collaborative, and excited to share knowledge. People who’ll sift through Discord at all hours to answer questions and support one another. People who come from all over the world but share a common trait: being passionate about enabling developers to do their best work. + +Don’t take our word for it! Take a look at this birthday video we put together with a few community members. + +
+ +
+ +## The growing pains are real + +But it's not all sunshine and roses in Backstage-land. If Year 1 was about getting this community going and Year 2 was focused on maturing the platform, then Year 3 needs to address some of the inevitable growing pains a project undergoes as it gains ground. + +We hear two things pretty consistently from the community: + +- **Backstage is a steep learning curve:** Over the past three years, the project has grown in scope and breadth which can translate to complexity. This is especially true for newcomers looking to get their arms wrapped around the key concepts. +- **Backstage has barriers to adoption:** Backstage adopters tell us driving widespread adoption of their developer portal remains the biggest challenge they face. Adoption barriers can be technical but are often cultural. + +The maintainers and some of our most involved community members are actively tackling how we can make the Backstage onboarding process easier for contributors. There are also lots of ways the project could better support adopters on that journey and make adoption faster and smoother. + +We’re looking at everything from cleaning up documentation to opinionated catalog ingestors being discussed in both the Catalog and Adoption monthly SIGs (running meeting notes [here](https://docs.google.com/document/d/1xg57CDfX2R5jTGbbWANzifm2szEb664kuTwfEEvKgZU/) and [here](https://docs.google.com/document/d/1zeYSzXYgh897bxPQmwy2btOwCFlEjlUDLf00riySLRc)). A few priorities that we’ve already mapped out: + +- Make it easier to install, customize, and maintain Backstage +- Provide Golden Paths for adoption +- Improve the experience and the content on [backstage.io](https://backstage.io/docs/overview/what-is-backstage) + +Because there are now so many mature adopters — Spotify included — there’s so much knowledge on how to create a roadmap for adoption and use cases, how to roll out your developer portal to your teams and drive inner source contributions, how to measure and attribute developer productivity gains, etc. + +Our goal is to tap into the knowledge those adopters have gained and create more tangible resources for the entire community. But we can’t do it without help. And that’s where you come in! + +## Getting (more) involved + +We’re very grateful for the Backstage ride-or-dies: the contributors who show up to every community session, attend every SIG, and are always ready to jump in on any PR or issue. + +But one of the areas where we think the project could greatly improve (and better address some of the growing pains I mentioned above!) is more active contribution — both the total number of people contributing and what they’re contributing. + +We’ve already shared a bit on this but the maintainer team is starting to address this challenge by proposing the following three initiatives: + +- Introduce more steps in between first-time contributor and maintainer in the form of a contributor ladder (loosely based on the [CNCF Project Template](https://github.com/cncf/project-template/blob/main/CONTRIBUTOR_LADDER.md)). +- Change the ownership model, for example, divide the project up into several project areas, each covering particular parts of the project. +- Introduce a new process for large contributions in the form of Backstage Enhancement Proposals (BEPs). + +These two RFCs on [Updated Backstage Governance](https://github.com/backstage/backstage/issues/15317) and [Backstage Enhancement Proposals](https://github.com/backstage/backstage/issues/15318) remain open so feel free to read and join the discussion! Watch this space as we’ll share more on the go-forward governance and BEPs plan soon. + +But if you’re brand-new and just looking to get your feet wet, we’ve also [compiled some small steps](https://backstage.io/docs/getting-started/getting-involved/) you can take to get involved: + +- Report (or squash) bugs: Look through the GitHub issues for [bugs](https://github.com/backstage/backstage/labels/bug), [good first issues](https://github.com/backstage/backstage/labels/good%20first%20issue) or [help wanted](https://github.com/backstage/backstage/labels/help%20wanted) +- Build or suggest a plugin: The Backstage project grows with every new plugin that gets added +- Add non-code contributions: We welcome things that help the community at large, but may not fit into the scope of the core project +- Write documentation or improve the website: The current documentation and project site are pretty limited. Better content helps a lot of those growing pains. +- Contribute to Storybook: Help us [create new components](https://github.com/backstage/backstage/labels/help%20wanted) or improve stories for the existing ones +- Submit feedback: The best way to send feedback is to file [an issue](https://github.com/backstage/backstage/issues) with as much detail as possible +- Add your company to ADOPTERS: Adding your company to [ADOPTERS](https://github.com/backstage/backstage/blob/master/ADOPTERS.md) really helps the project, you can do this by filling out this [adopter form](https://form.typeform.com/to/zcOaKikB) diff --git a/microsite/blog/assets/2023-03-15/birthday.gif b/microsite/blog/assets/2023-03-15/birthday.gif new file mode 100644 index 0000000000..0c489bc536 Binary files /dev/null and b/microsite/blog/assets/2023-03-15/birthday.gif differ diff --git a/microsite/data/plugins/backstage-analytics-module-ga.yaml b/microsite/data/plugins/analytics-module-ga.yaml similarity index 100% rename from microsite/data/plugins/backstage-analytics-module-ga.yaml rename to microsite/data/plugins/analytics-module-ga.yaml diff --git a/microsite/data/plugins/backstage-plugin-api-linter.yaml b/microsite/data/plugins/api-linter.yaml similarity index 91% rename from microsite/data/plugins/backstage-plugin-api-linter.yaml rename to microsite/data/plugins/api-linter.yaml index ae2a451ea7..a68da228eb 100644 --- a/microsite/data/plugins/backstage-plugin-api-linter.yaml +++ b/microsite/data/plugins/api-linter.yaml @@ -1,5 +1,5 @@ --- -title: backstage-plugin-api-linter +title: API Linter author: Zalando authorUrl: https://github.com/zalando category: Linting diff --git a/microsite/data/plugins/cloudsmith.yaml b/microsite/data/plugins/cloudsmith.yaml index 650f0b253c..4a07318a67 100644 --- a/microsite/data/plugins/cloudsmith.yaml +++ b/microsite/data/plugins/cloudsmith.yaml @@ -1,6 +1,6 @@ --- title: Cloudsmith -author: Roadie +author: roadie.io authorUrl: https://roadie.io category: CI/CD description: Show Cloudsmith Repository stats, Quota, Audit logs and Security scans for specific repositories. diff --git a/microsite/data/plugins/github-pull-requests-board.yaml b/microsite/data/plugins/github-pull-requests-board.yaml index 09776eb468..9fe2570f91 100644 --- a/microsite/data/plugins/github-pull-requests-board.yaml +++ b/microsite/data/plugins/github-pull-requests-board.yaml @@ -1,5 +1,5 @@ --- -title: Github Pull Requests Board +title: GitHub Pull Requests Board author: DAZN authorUrl: https://engineering.dazn.com category: Source Control Mgmt diff --git a/microsite/data/plugins/backstage-plugin-ldap-auth.yml b/microsite/data/plugins/ldap-auth.yml similarity index 100% rename from microsite/data/plugins/backstage-plugin-ldap-auth.yml rename to microsite/data/plugins/ldap-auth.yml diff --git a/microsite/data/plugins/microsoft-calendar.yaml b/microsite/data/plugins/microsoft-calendar.yaml new file mode 100644 index 0000000000..183c991761 --- /dev/null +++ b/microsite/data/plugins/microsoft-calendar.yaml @@ -0,0 +1,15 @@ +title: Microsoft Calendar +author: StatusNeo +authorUrl: https://statusneo.com/ +category: Productivity +description: | + The plugin integrates with your Microsoft Calendar. + It displays all your calendars and events in it. +documentation: https://github.com/backstage/backstage/tree/master/plugins/microsoft-calendar +iconUrl: /img/outlook-statusneo.png +npmPackageName: '@backstage/plugin-microsoft-calendar' +tags: + - Microsoft + - calendar + - Management +addedDate: '2023-03-15' diff --git a/microsite/data/plugins/scaffolder-backend-roadie-aws.yaml b/microsite/data/plugins/scaffolder-backend-roadie-aws.yaml index e8e67dbdad..65808b9af2 100644 --- a/microsite/data/plugins/scaffolder-backend-roadie-aws.yaml +++ b/microsite/data/plugins/scaffolder-backend-roadie-aws.yaml @@ -1,9 +1,9 @@ --- -title: Scaffolder AWS cli actions +title: Scaffolder AWS CLI actions author: roadie.io authorUrl: https://roadie.io/?utm_source=backstage.io&utm_medium=marketplace&utm_campaign=scaffolder-aws category: Scaffolder -description: Here you can find some AWS cli actions +description: Scaffolder actions you can trigger for Amazon Web Services. documentation: https://github.com/RoadieHQ/roadie-backstage-plugins/blob/main/plugins/scaffolder-actions/scaffolder-backend-module-aws/README.md iconUrl: https://upload.wikimedia.org/wikipedia/commons/9/93/Amazon_Web_Services_Logo.svg npmPackageName: '@roadiehq/scaffolder-backend-module-aws' diff --git a/microsite/data/plugins/statusneo-github-plugin.yaml b/microsite/data/plugins/statusneo-github-plugin.yaml new file mode 100644 index 0000000000..9c56dd4ae4 --- /dev/null +++ b/microsite/data/plugins/statusneo-github-plugin.yaml @@ -0,0 +1,13 @@ +title: Statusneo GitHub Plugin +author: Statusneo +authorUrl: https://statusneo.com/ +category: GitHub +description: Provides status cards GitHub pull requests and GitHub actions. +documentation: https://github.com/StatusNeo/backstage-plugin-github +iconUrl: /img/github-statusneo.png +npmPackageName: '@statusneo/backstage-plugin-github' +tags: + - GitHub + - Monitoring + - Productivity +addedDate: '2023-02-15' diff --git a/microsite/data/plugins/vault.yaml b/microsite/data/plugins/vault.yaml index 29e20417d8..37d474371b 100644 --- a/microsite/data/plugins/vault.yaml +++ b/microsite/data/plugins/vault.yaml @@ -2,7 +2,7 @@ title: Vault author: Spread Group authorUrl: https://github.com/ivangonzalezacuna -category: Vault +category: Security description: Visualize a list of the secrets stored in your HashiCorp Vault instance. documentation: https://github.com/backstage/backstage/tree/master/plugins/vault iconUrl: /img/vault.png diff --git a/microsite/docusaurus.config.js b/microsite/docusaurus.config.js index 025c773a9c..549974a168 100644 --- a/microsite/docusaurus.config.js +++ b/microsite/docusaurus.config.js @@ -16,6 +16,11 @@ // @ts-check +/** @type{import('prism-react-renderer').PrismTheme} **/ +// @ts-ignore +const prismTheme = require('prism-react-renderer/themes/vsDark'); +prismTheme.plain.backgroundColor = '#232323'; + /** @type {import('@docusaurus/types').Config} */ module.exports = { title: 'Backstage Software Catalog and Developer Platform', @@ -55,7 +60,7 @@ module.exports = { path: 'blog', }, theme: { - customCss: 'src/css/customTheme.css', + customCss: 'src/theme/customTheme.scss', }, gtag: { trackingID: 'G-KSEVGGNCJW', @@ -158,7 +163,7 @@ module.exports = { position: 'left', }, { - to: 'docs/releases/v1.11.0', + to: 'docs/releases/v1.12.0', label: 'Releases', position: 'left', }, @@ -266,10 +271,11 @@ module.exports = { searchParameters: {}, }, prism: { + theme: prismTheme, magicComments: [ // Extend the default highlight class name { - className: 'theme-code-block-highlighted-line', + className: 'code-block-highlight-line', line: 'highlight-next-line', block: { start: 'highlight-start', end: 'highlight-end' }, }, diff --git a/microsite/package.json b/microsite/package.json index cb71d5a25a..70b1aa86ad 100644 --- a/microsite/package.json +++ b/microsite/package.json @@ -35,6 +35,7 @@ "@swc/core": "^1.3.36", "clsx": "^1.1.1", "docusaurus-plugin-sass": "^0.2.3", + "prism-react-renderer": "^1.3.5", "react": "^17.0.2", "react-dom": "^17.0.2", "sass": "^1.57.1", diff --git a/microsite/sidebars.json b/microsite/sidebars.json index ebb387f81c..09727685a0 100644 --- a/microsite/sidebars.json +++ b/microsite/sidebars.json @@ -1,6 +1,7 @@ { "releases": { "Release Notes": [ + "releases/v1.12.0", "releases/v1.11.0", "releases/v1.10.0", "releases/v1.9.0", diff --git a/microsite/src/components/bannerSection/bannerSection.module.scss b/microsite/src/components/bannerSection/bannerSection.module.scss index 2beabf9738..64f4967d11 100644 --- a/microsite/src/components/bannerSection/bannerSection.module.scss +++ b/microsite/src/components/bannerSection/bannerSection.module.scss @@ -1,5 +1,41 @@ +@use 'src/theme/variables'; + .bannerSection { + --diagonalBorderHeight: 40px; + display: block; + background: var(--ifm-background-color); + + @media (min-width: variables.$desktopUpBreakpoint) { + --diagonalBorderHeight: 80px; + } + + &:global(:is(.diagonalBorder, .diagonalBottomBorder)) { + padding-bottom: var(--diagonalBorderHeight); + + & + section { + margin-top: calc(var(--diagonalBorderHeight) * -1); + padding-top: var(--diagonalBorderHeight); + } + } + + &:global(.diagonalBorder) { + clip-path: polygon( + 0 var(--diagonalBorderHeight), + 100% 0, + 100% calc(100% - var(--diagonalBorderHeight)), + 0 100% + ); + } + + &:global(.diagonalBottomBorder) { + clip-path: polygon( + 0 0, + 100% 0, + 100% calc(100% - var(--diagonalBorderHeight)), + 0 100% + ); + } &:global(.greyBackground) { background: linear-gradient(90.49deg, #121212 15.36%, #282828 70.44%); diff --git a/microsite/src/components/bannerSection/bannerSection.tsx b/microsite/src/components/bannerSection/bannerSection.tsx index 64c8d246c8..5dc99eecf0 100644 --- a/microsite/src/components/bannerSection/bannerSection.tsx +++ b/microsite/src/components/bannerSection/bannerSection.tsx @@ -6,6 +6,8 @@ import bannerStyles from './bannerSection.module.scss'; export type IBannerSectionProps = PropsWithChildren<{ className?: string; greyBackground?: boolean; + diagonalBorder?: boolean; + diagonalBottomBorder?: boolean; greenGradientBackground?: boolean; greenBottomGradientBackground?: boolean; greenCallToActionGradientBackground?: boolean; @@ -15,6 +17,8 @@ export const BannerSection = ({ children, className, greyBackground = false, + diagonalBorder = false, + diagonalBottomBorder = false, greenGradientBackground = false, greenBottomGradientBackground = false, greenCallToActionGradientBackground = false, @@ -22,6 +26,8 @@ export const BannerSection = ({
{ return (
- + { - + @@ -199,7 +199,7 @@ const Community = () => { - + Community initiatives} > @@ -223,7 +223,7 @@ const Community = () => { - + Trainings and Certifications diff --git a/microsite/src/pages/demos/index.tsx b/microsite/src/pages/demos/index.tsx index 2ca77e5c89..1221c38a63 100644 --- a/microsite/src/pages/demos/index.tsx +++ b/microsite/src/pages/demos/index.tsx @@ -167,6 +167,8 @@ const Demos = () => { {demoItems.map((demoItem, index) => ( 0 && index < demoItems.length - 1} greyBackground={index % 2 === 0} className={demosStyles.banner} > diff --git a/microsite/src/pages/getting-involved/index.tsx b/microsite/src/pages/getting-involved/index.tsx new file mode 100644 index 0000000000..d838f5d25b --- /dev/null +++ b/microsite/src/pages/getting-involved/index.tsx @@ -0,0 +1,6 @@ +import React from 'react'; +import { Redirect } from '@docusaurus/router'; + +export default () => { + return ; +}; diff --git a/microsite/src/pages/home/_home.tsx b/microsite/src/pages/home/_home.tsx index ea22062d28..deb0d4cd6f 100644 --- a/microsite/src/pages/home/_home.tsx +++ b/microsite/src/pages/home/_home.tsx @@ -28,7 +28,7 @@ const HomePage = () => { return (
- + { - + { - +
{
- +

Learn more about the software catalog

@@ -196,7 +196,7 @@ const HomePage = () => {
- +
{
- +

Build your own software templates

@@ -260,7 +260,7 @@ const HomePage = () => {
- +
{
- +

Learn more about TechDocs

@@ -320,7 +320,7 @@ const HomePage = () => {
- +
{
- +

Learn more about Backstage Search

@@ -381,7 +381,7 @@ const HomePage = () => {
- + { - +

Learn more about the K8s plugin

@@ -437,7 +437,7 @@ const HomePage = () => {
- +
{
- +

Build a plugin

diff --git a/microsite/src/pages/home/home.module.scss b/microsite/src/pages/home/home.module.scss index 57f2b9acde..5877f7b5f5 100644 --- a/microsite/src/pages/home/home.module.scss +++ b/microsite/src/pages/home/home.module.scss @@ -1,4 +1,4 @@ -$desktopUpBreakpoint: 997px; +@use '../../theme/variables.scss'; .homePage { font-size: 1.25rem; @@ -70,7 +70,7 @@ $desktopUpBreakpoint: 997px; } .catalogContainer { - @media (min-width: $desktopUpBreakpoint) { + @media (min-width: variables.$desktopUpBreakpoint) { grid-template-columns: repeat(4, 1fr); picture { @@ -85,7 +85,7 @@ $desktopUpBreakpoint: 997px; } .softwareTemplatesContainer { - @media (min-width: $desktopUpBreakpoint) { + @media (min-width: variables.$desktopUpBreakpoint) { grid: repeat(2, auto) / repeat(4, 1fr); picture { diff --git a/microsite/src/pages/plugins/_pluginCard.tsx b/microsite/src/pages/plugins/_pluginCard.tsx index 99f27b865d..d6b4017db5 100644 --- a/microsite/src/pages/plugins/_pluginCard.tsx +++ b/microsite/src/pages/plugins/_pluginCard.tsx @@ -35,9 +35,7 @@ export const PluginCard = ({ by {author}

- - {category} - + {category} } body={

{description}

} diff --git a/microsite/src/pages/plugins/plugins.module.scss b/microsite/src/pages/plugins/plugins.module.scss index d21444583a..bb08c2fd33 100644 --- a/microsite/src/pages/plugins/plugins.module.scss +++ b/microsite/src/pages/plugins/plugins.module.scss @@ -30,4 +30,8 @@ display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); } + + :global(.fit-content) { + width: fit-content; + } } diff --git a/microsite/src/css/customTheme.css b/microsite/src/theme/customTheme.scss similarity index 86% rename from microsite/src/css/customTheme.css rename to microsite/src/theme/customTheme.scss index 4ba7f1df86..f216762418 100644 --- a/microsite/src/css/customTheme.css +++ b/microsite/src/theme/customTheme.scss @@ -75,4 +75,12 @@ border-left: 3px solid rgba(255, 0, 0, 0.5); } +.code-block-highlight-line { + background-color: rgba(255, 255, 255, 0.08); + display: block; + margin: 0 calc(-1 * var(--ifm-pre-padding)); + padding: 0 var(--ifm-pre-padding); + border-left: 3px solid rgb(255, 255, 255, 0.5); +} + /* #endregion */ diff --git a/microsite/src/theme/variables.scss b/microsite/src/theme/variables.scss new file mode 100644 index 0000000000..3d74e59c9c --- /dev/null +++ b/microsite/src/theme/variables.scss @@ -0,0 +1,2 @@ +$xlUpBreakpoint: 1441px; +$desktopUpBreakpoint: 997px; diff --git a/microsite/static/img/github-statusneo.png b/microsite/static/img/github-statusneo.png new file mode 100644 index 0000000000..927ace351a Binary files /dev/null and b/microsite/static/img/github-statusneo.png differ diff --git a/microsite/static/img/outlook-statusneo.png b/microsite/static/img/outlook-statusneo.png new file mode 100644 index 0000000000..99e3b6a0bc Binary files /dev/null and b/microsite/static/img/outlook-statusneo.png differ diff --git a/microsite/yarn.lock b/microsite/yarn.lock index 81b78f043b..38067f5214 100644 --- a/microsite/yarn.lock +++ b/microsite/yarn.lock @@ -2623,90 +2623,90 @@ __metadata: languageName: node linkType: hard -"@swc/core-darwin-arm64@npm:1.3.38": - version: 1.3.38 - resolution: "@swc/core-darwin-arm64@npm:1.3.38" +"@swc/core-darwin-arm64@npm:1.3.42": + version: 1.3.42 + resolution: "@swc/core-darwin-arm64@npm:1.3.42" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@swc/core-darwin-x64@npm:1.3.38": - version: 1.3.38 - resolution: "@swc/core-darwin-x64@npm:1.3.38" +"@swc/core-darwin-x64@npm:1.3.42": + version: 1.3.42 + resolution: "@swc/core-darwin-x64@npm:1.3.42" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@swc/core-linux-arm-gnueabihf@npm:1.3.38": - version: 1.3.38 - resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.38" +"@swc/core-linux-arm-gnueabihf@npm:1.3.42": + version: 1.3.42 + resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.42" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@swc/core-linux-arm64-gnu@npm:1.3.38": - version: 1.3.38 - resolution: "@swc/core-linux-arm64-gnu@npm:1.3.38" +"@swc/core-linux-arm64-gnu@npm:1.3.42": + version: 1.3.42 + resolution: "@swc/core-linux-arm64-gnu@npm:1.3.42" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-arm64-musl@npm:1.3.38": - version: 1.3.38 - resolution: "@swc/core-linux-arm64-musl@npm:1.3.38" +"@swc/core-linux-arm64-musl@npm:1.3.42": + version: 1.3.42 + resolution: "@swc/core-linux-arm64-musl@npm:1.3.42" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@swc/core-linux-x64-gnu@npm:1.3.38": - version: 1.3.38 - resolution: "@swc/core-linux-x64-gnu@npm:1.3.38" +"@swc/core-linux-x64-gnu@npm:1.3.42": + version: 1.3.42 + resolution: "@swc/core-linux-x64-gnu@npm:1.3.42" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-x64-musl@npm:1.3.38": - version: 1.3.38 - resolution: "@swc/core-linux-x64-musl@npm:1.3.38" +"@swc/core-linux-x64-musl@npm:1.3.42": + version: 1.3.42 + resolution: "@swc/core-linux-x64-musl@npm:1.3.42" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@swc/core-win32-arm64-msvc@npm:1.3.38": - version: 1.3.38 - resolution: "@swc/core-win32-arm64-msvc@npm:1.3.38" +"@swc/core-win32-arm64-msvc@npm:1.3.42": + version: 1.3.42 + resolution: "@swc/core-win32-arm64-msvc@npm:1.3.42" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@swc/core-win32-ia32-msvc@npm:1.3.38": - version: 1.3.38 - resolution: "@swc/core-win32-ia32-msvc@npm:1.3.38" +"@swc/core-win32-ia32-msvc@npm:1.3.42": + version: 1.3.42 + resolution: "@swc/core-win32-ia32-msvc@npm:1.3.42" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@swc/core-win32-x64-msvc@npm:1.3.38": - version: 1.3.38 - resolution: "@swc/core-win32-x64-msvc@npm:1.3.38" +"@swc/core-win32-x64-msvc@npm:1.3.42": + version: 1.3.42 + resolution: "@swc/core-win32-x64-msvc@npm:1.3.42" conditions: os=win32 & cpu=x64 languageName: node linkType: hard "@swc/core@npm:^1.3.36": - version: 1.3.38 - resolution: "@swc/core@npm:1.3.38" + version: 1.3.42 + resolution: "@swc/core@npm:1.3.42" dependencies: - "@swc/core-darwin-arm64": 1.3.38 - "@swc/core-darwin-x64": 1.3.38 - "@swc/core-linux-arm-gnueabihf": 1.3.38 - "@swc/core-linux-arm64-gnu": 1.3.38 - "@swc/core-linux-arm64-musl": 1.3.38 - "@swc/core-linux-x64-gnu": 1.3.38 - "@swc/core-linux-x64-musl": 1.3.38 - "@swc/core-win32-arm64-msvc": 1.3.38 - "@swc/core-win32-ia32-msvc": 1.3.38 - "@swc/core-win32-x64-msvc": 1.3.38 + "@swc/core-darwin-arm64": 1.3.42 + "@swc/core-darwin-x64": 1.3.42 + "@swc/core-linux-arm-gnueabihf": 1.3.42 + "@swc/core-linux-arm64-gnu": 1.3.42 + "@swc/core-linux-arm64-musl": 1.3.42 + "@swc/core-linux-x64-gnu": 1.3.42 + "@swc/core-linux-x64-musl": 1.3.42 + "@swc/core-win32-arm64-msvc": 1.3.42 + "@swc/core-win32-ia32-msvc": 1.3.42 + "@swc/core-win32-x64-msvc": 1.3.42 dependenciesMeta: "@swc/core-darwin-arm64": optional: true @@ -2728,7 +2728,7 @@ __metadata: optional: true "@swc/core-win32-x64-msvc": optional: true - checksum: c55d30e57638bcd21f788add8490c3f3e71bfe027aa5a8b153e1b1b9686ecddd6deeaaa6a6b17717c7eab4c1e2a232b465b6755b6c891506fc0d03139badfbf7 + checksum: 5c28c03ee6a4e1f630c4a519b56d7e23a0102f70fad977a3ab144a3da96231cf4849e473cdc9ee7be6b9266ba0838d0bc0b6b3575a75540f302befe96cc9606e languageName: node linkType: hard @@ -3738,6 +3738,7 @@ __metadata: docusaurus-plugin-sass: ^0.2.3 js-yaml: ^4.1.0 prettier: ^2.6.2 + prism-react-renderer: ^1.3.5 react: ^17.0.2 react-dom: ^17.0.2 replace: ^1.2.2 @@ -8558,11 +8559,11 @@ __metadata: linkType: hard "prettier@npm:^2.6.2": - version: 2.8.4 - resolution: "prettier@npm:2.8.4" + version: 2.8.6 + resolution: "prettier@npm:2.8.6" bin: prettier: bin-prettier.js - checksum: c173064bf3df57b6d93d19aa98753b9b9dd7657212e33b41ada8e2e9f9884066bb9ca0b4005b89b3ab137efffdf8fbe0b462785aba20364798ff4303aadda57e + checksum: 8ac94fa67aec0e65743ea15ebf954ef2f1e52638abd129dc04e8b49e8bb3224c0233c98df6b5c98efd31bd2a43866590486559438ee4ead09dc81be389068572 languageName: node linkType: hard @@ -9437,15 +9438,15 @@ __metadata: linkType: hard "sass@npm:^1.57.1": - version: 1.58.3 - resolution: "sass@npm:1.58.3" + version: 1.59.3 + resolution: "sass@npm:1.59.3" dependencies: chokidar: ">=3.0.0 <4.0.0" immutable: ^4.0.0 source-map-js: ">=0.6.2 <2.0.0" bin: sass: sass.js - checksum: 35a2b98c037ef80fdc93c9b0be846e6ccc7d75596351a37ee79c397e66666d0a754c52c4696e746c0aff32327471e185343ca349e998a58340411adc9d0489a5 + checksum: 839b5282cdf7d0ba3fdbfb605277dd584a8c40fa3e3e58ad905d64cd812acfb82ff0a4072d4981673db884ee61505472ff07c5c5a8a497f16ba013b183ba6473 languageName: node linkType: hard @@ -10889,8 +10890,8 @@ __metadata: linkType: hard "webpack@npm:^5.73.0": - version: 5.75.0 - resolution: "webpack@npm:5.75.0" + version: 5.76.2 + resolution: "webpack@npm:5.76.2" dependencies: "@types/eslint-scope": ^3.7.3 "@types/estree": ^0.0.51 @@ -10921,7 +10922,7 @@ __metadata: optional: true bin: webpack: bin/webpack.js - checksum: 2bcc5f3c195f375944e8af2f00bf2feea39cb9fda5f763b0d1b00077f1c51783db25c94d3fae96a07dead9fa085e6ae7474417e5ab31719c9776ea5969ceb83a + checksum: 86db98299a175c371031449c26077e87b33acd8f45de7f7945ed4b9b37c8ca11bc5169af9c44743efccd4d55e08042a3aa3a3bc42aff831309a0821ffbcd395e languageName: node linkType: hard diff --git a/package.json b/package.json index e4cb3ef1d3..8550a72a97 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "@types/react": "^17", "@types/react-dom": "^17" }, - "version": "1.12.0", + "version": "1.13.0-next.0", "dependencies": { "@backstage/errors": "workspace:^", "@manypkg/get-packages": "^1.1.3" diff --git a/packages/app-defaults/CHANGELOG.md b/packages/app-defaults/CHANGELOG.md index e388b3e4ad..b2d85cea1a 100644 --- a/packages/app-defaults/CHANGELOG.md +++ b/packages/app-defaults/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/app-defaults +## 1.3.0-next.0 + +### Minor Changes + +- 7908d72e033: Introduce a new global config parameter, `auth.enableExperimentalRedirectFlow`. When enabled, auth will happen with an in-window redirect flow rather than through a popup window. + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-app-api@1.7.0-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/plugin-permission-react@0.4.11 + - @backstage/theme@0.2.18 + ## 1.2.1 ### Patch Changes diff --git a/packages/app-defaults/package.json b/packages/app-defaults/package.json index 31fb64a079..d4540bfd1d 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.2.1", + "version": "1.3.0-next.0", "publishConfig": { "access": "public", "main": "dist/index.esm.js", diff --git a/packages/app-defaults/src/defaults/apis.ts b/packages/app-defaults/src/defaults/apis.ts index d3ebddfb84..3a552c25c7 100644 --- a/packages/app-defaults/src/defaults/apis.ts +++ b/packages/app-defaults/src/defaults/apis.ts @@ -130,6 +130,7 @@ export const apis = [ }, factory: ({ discoveryApi, oauthRequestApi, configApi }) => GoogleAuth.create({ + configApi, discoveryApi, oauthRequestApi, environment: configApi.getOptionalString('auth.environment'), @@ -144,6 +145,7 @@ export const apis = [ }, factory: ({ discoveryApi, oauthRequestApi, configApi }) => MicrosoftAuth.create({ + configApi, discoveryApi, oauthRequestApi, environment: configApi.getOptionalString('auth.environment'), @@ -158,6 +160,7 @@ export const apis = [ }, factory: ({ discoveryApi, oauthRequestApi, configApi }) => GithubAuth.create({ + configApi, discoveryApi, oauthRequestApi, defaultScopes: ['read:user'], @@ -173,6 +176,7 @@ export const apis = [ }, factory: ({ discoveryApi, oauthRequestApi, configApi }) => OktaAuth.create({ + configApi, discoveryApi, oauthRequestApi, environment: configApi.getOptionalString('auth.environment'), @@ -187,6 +191,7 @@ export const apis = [ }, factory: ({ discoveryApi, oauthRequestApi, configApi }) => GitlabAuth.create({ + configApi, discoveryApi, oauthRequestApi, environment: configApi.getOptionalString('auth.environment'), @@ -201,6 +206,7 @@ export const apis = [ }, factory: ({ discoveryApi, oauthRequestApi, configApi }) => OneLoginAuth.create({ + configApi, discoveryApi, oauthRequestApi, environment: configApi.getOptionalString('auth.environment'), @@ -215,6 +221,7 @@ export const apis = [ }, factory: ({ discoveryApi, oauthRequestApi, configApi }) => BitbucketAuth.create({ + configApi, discoveryApi, oauthRequestApi, defaultScopes: ['team'], @@ -226,9 +233,11 @@ export const apis = [ deps: { discoveryApi: discoveryApiRef, oauthRequestApi: oauthRequestApiRef, + configApi: configApiRef, }, - factory: ({ discoveryApi, oauthRequestApi }) => + factory: ({ discoveryApi, oauthRequestApi, configApi }) => BitbucketServerAuth.create({ + configApi, discoveryApi, oauthRequestApi, defaultScopes: ['REPO_READ'], @@ -243,6 +252,7 @@ export const apis = [ }, factory: ({ discoveryApi, oauthRequestApi, configApi }) => { return AtlassianAuth.create({ + configApi, discoveryApi, oauthRequestApi, environment: configApi.getOptionalString('auth.environment'), diff --git a/packages/app/CHANGELOG.md b/packages/app/CHANGELOG.md index 4b24b827b4..7c0a558a86 100644 --- a/packages/app/CHANGELOG.md +++ b/packages/app/CHANGELOG.md @@ -1,5 +1,74 @@ # example-app +## 0.2.82-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-api-docs@0.9.2-next.0 + - @backstage/plugin-scaffolder@1.13.0-next.0 + - @backstage/plugin-scaffolder-react@1.3.0-next.0 + - @backstage/plugin-entity-feedback@0.2.0-next.0 + - @backstage/plugin-tech-insights@0.3.9-next.0 + - @backstage/core-components@0.12.6-next.0 + - @backstage/app-defaults@1.3.0-next.0 + - @backstage/core-app-api@1.7.0-next.0 + - @backstage/plugin-search-react@1.5.2-next.0 + - @backstage/plugin-techdocs@1.6.1-next.0 + - @backstage/cli@0.22.6-next.0 + - @backstage/plugin-techdocs-react@1.1.5-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.0.12-next.0 + - @backstage/plugin-newrelic-dashboard@0.2.10-next.0 + - @backstage/plugin-apache-airflow@0.2.10-next.0 + - @backstage/plugin-catalog-import@0.9.7-next.0 + - @backstage/plugin-github-actions@0.5.17-next.0 + - @backstage/plugin-catalog-graph@0.2.29-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/plugin-code-coverage@0.2.10-next.0 + - @backstage/plugin-cost-insights@0.12.6-next.0 + - @backstage/plugin-user-settings@0.7.2-next.0 + - @backstage/plugin-azure-devops@0.2.8-next.0 + - @backstage/plugin-gcp-projects@0.3.36-next.0 + - @backstage/plugin-azure-sites@0.1.6-next.0 + - @backstage/plugin-cloudbuild@0.3.17-next.0 + - @backstage/plugin-kubernetes@0.7.10-next.0 + - @backstage/plugin-lighthouse@0.4.2-next.0 + - @backstage/plugin-tech-radar@0.6.3-next.0 + - @backstage/plugin-dynatrace@3.0.1-next.0 + - @backstage/plugin-gcalendar@0.3.13-next.0 + - @backstage/plugin-pagerduty@0.5.10-next.0 + - @backstage/plugin-shortcuts@0.3.9-next.0 + - @backstage/plugin-airbrake@0.3.17-next.0 + - @backstage/plugin-circleci@0.3.17-next.0 + - @backstage/plugin-graphiql@0.2.49-next.0 + - @backstage/plugin-newrelic@0.3.35-next.0 + - @backstage/plugin-explore@0.4.2-next.0 + - @backstage/plugin-jenkins@0.7.16-next.0 + - @backstage/plugin-rollbar@0.4.17-next.0 + - @backstage/plugin-badges@0.2.41-next.0 + - @backstage/plugin-search@1.1.2-next.0 + - @backstage/plugin-sentry@0.5.2-next.0 + - @backstage/plugin-kafka@0.3.17-next.0 + - @backstage/plugin-gocd@0.1.23-next.0 + - @backstage/plugin-home@0.4.33-next.0 + - @backstage/plugin-todo@0.2.19-next.0 + - @backstage/plugin-org@0.6.7-next.0 + - @internal/plugin-catalog-customized@0.0.9-next.0 + - @backstage/integration-react@1.1.12-next.0 + - @backstage/plugin-linguist@0.1.2-next.0 + - @backstage/plugin-microsoft-calendar@0.1.2-next.0 + - @backstage/plugin-playlist@0.1.8-next.0 + - @backstage/plugin-stack-overflow@0.1.13-next.0 + - @backstage/plugin-stackstorm@0.1.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/config@1.0.7 + - @backstage/plugin-permission-react@0.4.11 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + - @backstage/plugin-catalog-common@1.0.12 + - @backstage/plugin-linguist-common@0.1.0 + - @backstage/plugin-search-common@1.2.2 + ## 0.2.81 ### Patch Changes diff --git a/packages/app/package.json b/packages/app/package.json index a5a420c621..5902184f89 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "example-app", - "version": "0.2.81", + "version": "0.2.82-next.0", "private": true, "backstage": { "role": "frontend" @@ -72,7 +72,7 @@ "@internal/plugin-catalog-customized": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "@octokit/rest": "^19.0.3", "@oriflame/backstage-plugin-score-card": "^0.6.0", "@roadiehq/backstage-plugin-buildkite": "^2.0.8", diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx index 4dacbbc007..1ee6978a87 100644 --- a/packages/app/src/App.tsx +++ b/packages/app/src/App.tsx @@ -27,7 +27,7 @@ import { RELATION_PROVIDES_API, } from '@backstage/catalog-model'; import { createApp } from '@backstage/app-defaults'; -import { AppRouter, FlatRoutes } from '@backstage/core-app-api'; +import { AppRouter, FeatureFlagged, FlatRoutes } from '@backstage/core-app-api'; import { AlertDisplay, OAuthRequestDialog, @@ -117,10 +117,13 @@ const app = createApp({ // Custom icon example alert: AlarmIcon, }, - // Example of application level feature flag - // featureFlags: [ - // { name: 'tech-radar', description: 'Enables the tech radar plugin' }, - // ], + featureFlags: [ + { + name: 'scaffolder-next-preview', + description: 'Preview the new Scaffolder Next', + pluginId: '', + }, + ], components: { SignInPage: props => { return ( @@ -208,49 +211,53 @@ const routes = ( - - entity?.metadata?.tags?.includes('recommended') ?? false, - }, - ]} - /> - } - > - - - - - - - - - entity?.metadata?.tags?.includes('recommended') ?? false, - }, - ]} - /> - } - > - - - - - - - + + + entity?.metadata?.tags?.includes('recommended') ?? false, + }, + ]} + /> + } + > + + + + + + + + + + + entity?.metadata?.tags?.includes('recommended') ?? false, + }, + ]} + /> + } + > + + + + + + + + } /> ) => ( - + diff --git a/packages/backend-app-api/CHANGELOG.md b/packages/backend-app-api/CHANGELOG.md index 1e587b94a3..ed9deb5037 100644 --- a/packages/backend-app-api/CHANGELOG.md +++ b/packages/backend-app-api/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/backend-app-api +## 0.4.2-next.0 + +### Patch Changes + +- 8cce2205a39: Register unhandled rejection and uncaught exception handlers to avoid backend crashes. +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/cli-common@0.1.12 + - @backstage/config-loader@1.1.9 + - @backstage/errors@1.1.5 + - @backstage/types@1.0.2 + - @backstage/plugin-auth-node@0.2.13-next.0 + - @backstage/plugin-permission-node@0.7.7-next.0 + ## 0.4.1 ### Patch Changes diff --git a/packages/backend-app-api/package.json b/packages/backend-app-api/package.json index 8ed273b451..dda56af96c 100644 --- a/packages/backend-app-api/package.json +++ b/packages/backend-app-api/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-app-api", "description": "Core API used by Backstage backend apps", - "version": "0.4.1", + "version": "0.4.2-next.0", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/backend-app-api/src/wiring/BackendInitializer.ts b/packages/backend-app-api/src/wiring/BackendInitializer.ts index 2a8fa1e720..b2c62c2122 100644 --- a/packages/backend-app-api/src/wiring/BackendInitializer.ts +++ b/packages/backend-app-api/src/wiring/BackendInitializer.ts @@ -165,6 +165,25 @@ export class BackendInitializer { ); await registerInit.init.func(deps); } + + // Once the backend is started, any uncaught errors or unhandled rejections are caught + // and logged, in order to avoid crashing the entire backend on local failures. + if (process.env.NODE_ENV !== 'test') { + const rootLogger = await this.#serviceHolder.get( + coreServices.rootLogger, + 'root', + ); + process.on('unhandledRejection', (reason: Error) => { + rootLogger + ?.child({ type: 'unhandledRejection' }) + ?.error('Unhandled rejection', reason); + }); + process.on('uncaughtException', error => { + rootLogger + ?.child({ type: 'uncaughtException' }) + ?.error('Uncaught exception', error); + }); + } } #resolveInitOrder(registerInits: Array) { diff --git a/packages/backend-common/CHANGELOG.md b/packages/backend-common/CHANGELOG.md index 8d73268bc1..3ec4fe5837 100644 --- a/packages/backend-common/CHANGELOG.md +++ b/packages/backend-common/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/backend-common +## 0.18.4-next.0 + +### Patch Changes + +- 420164593cf: Improve GitlabUrlReader to only load requested sub-path +- Updated dependencies + - @backstage/backend-app-api@0.4.2-next.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/integration-aws-node@0.1.2 + - @backstage/backend-dev-utils@0.1.1 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/cli-common@0.1.12 + - @backstage/config-loader@1.1.9 + - @backstage/errors@1.1.5 + - @backstage/types@1.0.2 + ## 0.18.3 ### Patch Changes diff --git a/packages/backend-common/package.json b/packages/backend-common/package.json index 5d54e5ae12..3f96d5f4ce 100644 --- a/packages/backend-common/package.json +++ b/packages/backend-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-common", "description": "Common functionality library for Backstage backends", - "version": "0.18.3", + "version": "0.18.4-next.0", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/backend-common/src/reading/GitlabUrlReader.test.ts b/packages/backend-common/src/reading/GitlabUrlReader.test.ts index d926b2be9b..5af4faf7e5 100644 --- a/packages/backend-common/src/reading/GitlabUrlReader.test.ts +++ b/packages/backend-common/src/reading/GitlabUrlReader.test.ts @@ -556,6 +556,10 @@ describe('GitlabUrlReader', () => { path.resolve(__dirname, '__fixtures__/gitlab-archive.tar.gz'), ); + const archiveSubPathBuffer = fs.readFileSync( + path.resolve(__dirname, '__fixtures__/gitlab-subpath-archive.tar.gz'), + ); + const projectGitlabApiResponse = { id: 11111111, default_branch: 'main', @@ -566,21 +570,34 @@ describe('GitlabUrlReader', () => { id: 'sha123abc', }, ]; + const commitsOfSubPathGitlabApiResponse = [ + { + id: 'sha456abc', + }, + ]; beforeEach(() => { worker.use( rest.get( 'https://gitlab.com/api/v4/projects/backstage%2Fmock/repository/archive', - (_, res, ctx) => - res( + (req, res, ctx) => { + const filepath = req.url.searchParams.get('path'); + let filename = 'mock-main-sha123abc.zip'; + let body = archiveBuffer; + if (filepath === 'docs') { + filename = 'gitlab-subpath-archive.tar.gz'; + body = archiveSubPathBuffer; + } + return res( ctx.status(200), ctx.set('Content-Type', 'application/zip'), ctx.set( 'content-disposition', - 'attachment; filename="mock-main-sha123abc.zip"', + `attachment; filename="${filename}"`, ), - ctx.body(archiveBuffer), - ), + ctx.body(body), + ); + }, ), rest.get( 'https://gitlab.com/api/v4/projects/backstage%2Fmock', @@ -596,6 +613,14 @@ describe('GitlabUrlReader', () => { (req, res, ctx) => { const refName = req.url.searchParams.get('ref_name'); if (refName === 'main') { + const filepath = req.url.searchParams.get('path'); + if (filepath === 'docs') { + return res( + ctx.status(200), + ctx.set('Content-Type', 'application/json'), + ctx.json(commitsOfSubPathGitlabApiResponse), + ); + } return res( ctx.status(200), ctx.set('Content-Type', 'application/json'), @@ -622,6 +647,21 @@ describe('GitlabUrlReader', () => { ); }); + it('load only relevant path', async () => { + const result = await gitlabProcessor.search( + 'https://gitlab.com/backstage/mock/tree/main/docs/**/index.*', + ); + + expect(result.etag).toBe('sha456abc'); + expect(result.files.length).toBe(1); + expect(result.files[0].url).toBe( + 'https://gitlab.com/backstage/mock/tree/main/docs/index.md', + ); + await expect(result.files[0].content()).resolves.toEqual( + Buffer.from('# Test Subpath\n'), + ); + }); + it('throws NotModifiedError when same etag', async () => { await expect( gitlabProcessor.search( diff --git a/packages/backend-common/src/reading/GitlabUrlReader.ts b/packages/backend-common/src/reading/GitlabUrlReader.ts index df8441c1f7..ab59c19b16 100644 --- a/packages/backend-common/src/reading/GitlabUrlReader.ts +++ b/packages/backend-common/src/reading/GitlabUrlReader.ts @@ -26,7 +26,6 @@ import parseGitUrl from 'git-url-parse'; import { Minimatch } from 'minimatch'; import { Readable } from 'stream'; import { NotFoundError, NotModifiedError } from '@backstage/errors'; -import { stripFirstDirectoryFromPath } from './tree/util'; import { ReadTreeResponseFactory, ReaderFactory, @@ -163,7 +162,7 @@ export class GitlabUrlReader implements UrlReader { // ref is an empty string if no branch is set in provided url to readTree. const branch = ref || projectGitlabResponseJson.default_branch; - // Fetch the latest commit that modifies the the filepath in the provided or default branch + // Fetch the latest commit that modifies the filepath in the provided or default branch // to compare against the provided sha. const commitsReqParams = new URLSearchParams(); commitsReqParams.set('ref_name', branch); @@ -200,11 +199,16 @@ export class GitlabUrlReader implements UrlReader { throw new NotModifiedError(); } + const archiveReqParams = new URLSearchParams(); + archiveReqParams.set('sha', branch); + if (!!filepath) { + archiveReqParams.set('path', filepath); + } // https://docs.gitlab.com/ee/api/repositories.html#get-file-archive const archiveGitLabResponse = await fetch( `${this.integration.config.apiBaseUrl}/projects/${encodeURIComponent( repoFullName, - )}/repository/archive?sha=${branch}`, + )}/repository/archive?${archiveReqParams.toString()}`, { ...getGitLabRequestOptions(this.integration.config), // TODO(freben): The signal cast is there because pre-3.x versions of @@ -234,31 +238,54 @@ export class GitlabUrlReader implements UrlReader { async search(url: string, options?: SearchOptions): Promise { const { filepath } = parseGitUrl(url); + const staticPart = this.getStaticPart(filepath); const matcher = new Minimatch(filepath); - - // TODO(freben): For now, read the entire repo and filter through that. In - // a future improvement, we could be smart and try to deduce that non-glob - // prefixes (like for filepaths such as some-prefix/**/a.yaml) can be used - // to get just that part of the repo. - const treeUrl = trimEnd(url.replace(filepath, ''), '/'); - + const treeUrl = trimEnd(url.replace(filepath, staticPart), `/`); + const pathPrefix = staticPart ? `${staticPart}/` : ''; const tree = await this.readTree(treeUrl, { etag: options?.etag, signal: options?.signal, - filter: path => matcher.match(stripFirstDirectoryFromPath(path)), + filter: path => matcher.match(`${pathPrefix}${path}`), }); - const files = await tree.files(); + const files = await tree.files(); return { etag: tree.etag, files: files.map(file => ({ - url: this.integration.resolveUrl({ url: `/${file.path}`, base: url }), + url: this.integration.resolveUrl({ + url: `/${pathPrefix}${file.path}`, + base: url, + }), content: file.content, lastModifiedAt: file.lastModifiedAt, })), }; } + /** + * This function splits the input globPattern string into segments using the path separator /. It then iterates over + * the segments from the end of the array towards the beginning, checking if the concatenated string up to that + * segment matches the original globPattern using the minimatch function. If a match is found, it continues iterating. + * If no match is found, it returns the concatenated string up to the current segment, which is the static part of the + * glob pattern. + * + * E.g. `catalog/foo/*.yaml` will return `catalog/foo`. + * + * @param globPattern the glob pattern + * @private + */ + private getStaticPart(globPattern: string) { + const segments = globPattern.split('/'); + let i = segments.length; + while ( + i > 0 && + new Minimatch(segments.slice(0, i).join('/')).match(globPattern) + ) { + i--; + } + return segments.slice(0, i).join('/'); + } + toString() { const { host, token } = this.integration.config; return `gitlab{host=${host},authed=${Boolean(token)}}`; diff --git a/packages/backend-common/src/reading/__fixtures__/gitlab-subpath-archive.tar.gz b/packages/backend-common/src/reading/__fixtures__/gitlab-subpath-archive.tar.gz new file mode 100644 index 0000000000..c41714b452 Binary files /dev/null and b/packages/backend-common/src/reading/__fixtures__/gitlab-subpath-archive.tar.gz differ diff --git a/packages/backend-defaults/CHANGELOG.md b/packages/backend-defaults/CHANGELOG.md index edfc39bd91..01afac257b 100644 --- a/packages/backend-defaults/CHANGELOG.md +++ b/packages/backend-defaults/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/backend-defaults +## 0.1.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-app-api@0.4.2-next.0 + - @backstage/backend-common@0.18.4-next.0 + - @backstage/backend-plugin-api@0.5.1-next.0 + ## 0.1.8 ### Patch Changes diff --git a/packages/backend-defaults/package.json b/packages/backend-defaults/package.json index 2759c3c089..2f9655384e 100644 --- a/packages/backend-defaults/package.json +++ b/packages/backend-defaults/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-defaults", "description": "Backend defaults used by Backstage backend apps", - "version": "0.1.8", + "version": "0.1.9-next.0", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/backend-next/CHANGELOG.md b/packages/backend-next/CHANGELOG.md index e51c65963d..39af1fa1c3 100644 --- a/packages/backend-next/CHANGELOG.md +++ b/packages/backend-next/CHANGELOG.md @@ -1,5 +1,17 @@ # example-backend-next +## 0.0.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.12.1-next.0 + - @backstage/plugin-catalog-backend@1.8.1-next.0 + - @backstage/backend-defaults@0.1.9-next.0 + - @backstage/plugin-app-backend@0.3.44-next.0 + - @backstage/plugin-techdocs-backend@1.6.1-next.0 + - @backstage/plugin-todo-backend@0.1.41-next.0 + ## 0.0.9 ### Patch Changes diff --git a/packages/backend-next/package.json b/packages/backend-next/package.json index 14ec71f352..bed4f10975 100644 --- a/packages/backend-next/package.json +++ b/packages/backend-next/package.json @@ -1,6 +1,6 @@ { "name": "example-backend-next", - "version": "0.0.9", + "version": "0.0.10-next.0", "main": "dist/index.cjs.js", "types": "src/index.ts", "license": "Apache-2.0", @@ -29,6 +29,11 @@ "@backstage/plugin-app-backend": "workspace:^", "@backstage/plugin-catalog-backend": "workspace:^", "@backstage/plugin-scaffolder-backend": "workspace:^", + "@backstage/plugin-search-backend": "workspace:^", + "@backstage/plugin-search-backend-module-catalog": "workspace:^", + "@backstage/plugin-search-backend-module-explore": "workspace:^", + "@backstage/plugin-search-backend-module-techdocs": "workspace:^", + "@backstage/plugin-search-backend-node": "workspace:^", "@backstage/plugin-techdocs-backend": "workspace:^", "@backstage/plugin-todo-backend": "workspace:^" }, diff --git a/packages/backend-next/src/index.ts b/packages/backend-next/src/index.ts index 8f8984b192..e3cbbd53b8 100644 --- a/packages/backend-next/src/index.ts +++ b/packages/backend-next/src/index.ts @@ -14,18 +14,35 @@ * limitations under the License. */ -import { catalogPlugin } from '@backstage/plugin-catalog-backend/alpha'; -import { catalogModuleTemplateKind } from '@backstage/plugin-scaffolder-backend/alpha'; import { createBackend } from '@backstage/backend-defaults'; import { appPlugin } from '@backstage/plugin-app-backend/alpha'; import { todoPlugin } from '@backstage/plugin-todo-backend'; import { techdocsPlugin } from '@backstage/plugin-techdocs-backend/alpha'; +import { catalogPlugin } from '@backstage/plugin-catalog-backend/alpha'; +import { catalogModuleTemplateKind } from '@backstage/plugin-scaffolder-backend/alpha'; +import { searchPlugin } from '@backstage/plugin-search-backend/alpha'; +import { searchModuleCatalogCollator } from '@backstage/plugin-search-backend-module-catalog/alpha'; +import { searchModuleTechDocsCollator } from '@backstage/plugin-search-backend-module-techdocs/alpha'; +import { searchModuleExploreCollator } from '@backstage/plugin-search-backend-module-explore/alpha'; const backend = createBackend(); +backend.add(appPlugin({ appPackageName: 'example-app' })); + +// Todo +backend.add(todoPlugin()); + +// Techdocs +backend.add(techdocsPlugin()); + +// Catalog backend.add(catalogPlugin()); backend.add(catalogModuleTemplateKind()); -backend.add(appPlugin({ appPackageName: 'example-app' })); -backend.add(todoPlugin()); -backend.add(techdocsPlugin()); + +// Search +backend.add(searchPlugin()); +backend.add(searchModuleCatalogCollator()); +backend.add(searchModuleTechDocsCollator()); +backend.add(searchModuleExploreCollator()); + backend.start(); diff --git a/packages/backend-plugin-api/CHANGELOG.md b/packages/backend-plugin-api/CHANGELOG.md index dd78ffaca1..f3cb679fce 100644 --- a/packages/backend-plugin-api/CHANGELOG.md +++ b/packages/backend-plugin-api/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/backend-plugin-api +## 0.5.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.0.7 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/types@1.0.2 + - @backstage/plugin-auth-node@0.2.13-next.0 + - @backstage/plugin-permission-common@0.7.4 + ## 0.5.0 ### Minor Changes diff --git a/packages/backend-plugin-api/package.json b/packages/backend-plugin-api/package.json index cc155fe546..6566772f2f 100644 --- a/packages/backend-plugin-api/package.json +++ b/packages/backend-plugin-api/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-plugin-api", "description": "Core API used by Backstage backend plugins", - "version": "0.5.0", + "version": "0.5.1-next.0", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/backend-tasks/CHANGELOG.md b/packages/backend-tasks/CHANGELOG.md index dea40d399b..7d2540d83a 100644 --- a/packages/backend-tasks/CHANGELOG.md +++ b/packages/backend-tasks/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/backend-tasks +## 0.5.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/errors@1.1.5 + - @backstage/types@1.0.2 + ## 0.5.0 ### Minor Changes diff --git a/packages/backend-tasks/package.json b/packages/backend-tasks/package.json index 5042ff735a..43553cd740 100644 --- a/packages/backend-tasks/package.json +++ b/packages/backend-tasks/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-tasks", "description": "Common distributed task management library for Backstage backends", - "version": "0.5.0", + "version": "0.5.1-next.0", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/backend-test-utils/CHANGELOG.md b/packages/backend-test-utils/CHANGELOG.md index 529c92d423..a1f4e76ea2 100644 --- a/packages/backend-test-utils/CHANGELOG.md +++ b/packages/backend-test-utils/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/backend-test-utils +## 0.1.36-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-app-api@0.4.2-next.0 + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/types@1.0.2 + - @backstage/plugin-auth-node@0.2.13-next.0 + ## 0.1.35 ### Patch Changes diff --git a/packages/backend-test-utils/package.json b/packages/backend-test-utils/package.json index 80135ad4a9..05195f98aa 100644 --- a/packages/backend-test-utils/package.json +++ b/packages/backend-test-utils/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-test-utils", "description": "Test helpers library for Backstage backends", - "version": "0.1.35", + "version": "0.1.36-next.0", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/backend/CHANGELOG.md b/packages/backend/CHANGELOG.md index 7ead0abeb6..fd9247bb44 100644 --- a/packages/backend/CHANGELOG.md +++ b/packages/backend/CHANGELOG.md @@ -1,5 +1,56 @@ # example-backend +## 0.2.82-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.12.1-next.0 + - @backstage/plugin-kubernetes-backend@0.10.0-next.0 + - @backstage/plugin-entity-feedback-backend@0.1.2-next.0 + - @backstage/plugin-auth-backend@0.18.2-next.0 + - @backstage/plugin-catalog-backend@1.8.1-next.0 + - @backstage/plugin-graphql-backend@0.1.34-next.0 + - @backstage/backend-common@0.18.4-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.12-next.0 + - example-app@0.2.82-next.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/plugin-adr-backend@0.3.2-next.0 + - @backstage/plugin-app-backend@0.3.44-next.0 + - @backstage/plugin-auth-node@0.2.13-next.0 + - @backstage/plugin-azure-devops-backend@0.3.23-next.0 + - @backstage/plugin-azure-sites-backend@0.1.6-next.0 + - @backstage/plugin-badges-backend@0.1.38-next.0 + - @backstage/plugin-catalog-node@1.3.5-next.0 + - @backstage/plugin-code-coverage-backend@0.2.10-next.0 + - @backstage/plugin-events-backend@0.2.5-next.0 + - @backstage/plugin-events-node@0.2.5-next.0 + - @backstage/plugin-explore-backend@0.0.6-next.0 + - @backstage/plugin-jenkins-backend@0.1.34-next.0 + - @backstage/plugin-kafka-backend@0.2.37-next.0 + - @backstage/plugin-lighthouse-backend@0.1.2-next.0 + - @backstage/plugin-linguist-backend@0.2.1-next.0 + - @backstage/plugin-permission-backend@0.5.19-next.0 + - @backstage/plugin-permission-common@0.7.4 + - @backstage/plugin-permission-node@0.7.7-next.0 + - @backstage/plugin-playlist-backend@0.2.7-next.0 + - @backstage/plugin-proxy-backend@0.2.38-next.0 + - @backstage/plugin-rollbar-backend@0.1.41-next.0 + - @backstage/plugin-search-backend@1.2.5-next.0 + - @backstage/plugin-search-backend-module-elasticsearch@1.1.5-next.0 + - @backstage/plugin-search-backend-module-pg@0.5.5-next.0 + - @backstage/plugin-search-backend-node@1.1.5-next.0 + - @backstage/plugin-search-common@1.2.2 + - @backstage/plugin-tech-insights-backend@0.5.10-next.0 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.28-next.0 + - @backstage/plugin-tech-insights-node@0.4.2-next.0 + - @backstage/plugin-techdocs-backend@1.6.1-next.0 + - @backstage/plugin-todo-backend@0.1.41-next.0 + ## 0.2.81 ### Patch Changes diff --git a/packages/backend/package.json b/packages/backend/package.json index 54dbe640df..22da65099f 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -1,6 +1,6 @@ { "name": "example-backend", - "version": "0.2.81", + "version": "0.2.82-next.0", "main": "dist/index.cjs.js", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/backend/src/plugins/kubernetes.ts b/packages/backend/src/plugins/kubernetes.ts index 3bc7a5dcbe..3bc6648862 100644 --- a/packages/backend/src/plugins/kubernetes.ts +++ b/packages/backend/src/plugins/kubernetes.ts @@ -27,6 +27,7 @@ export default async function createPlugin( logger: env.logger, config: env.config, catalogApi, + permissions: env.permissions, }).build(); return router; } diff --git a/packages/backend/src/plugins/scaffolder.ts b/packages/backend/src/plugins/scaffolder.ts index d079b64c28..813092c9b9 100644 --- a/packages/backend/src/plugins/scaffolder.ts +++ b/packages/backend/src/plugins/scaffolder.ts @@ -34,5 +34,6 @@ export default async function createPlugin( reader: env.reader, identity: env.identity, scheduler: env.scheduler, + permissionApi: env.permissions, }); } diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index 6903e61425..e88e554b70 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/cli +## 0.22.6-next.0 + +### Patch Changes + +- b9839d7135c: Fixed backend start command on Windows by removing the use of platform dependent path joins. +- c07c3b7364b: Add `onboard` command. While still in development, this command aims to guide users in setting up their Backstage App. +- Updated dependencies + - @backstage/eslint-plugin@0.1.3-next.0 + - @backstage/config@1.0.7 + - @backstage/release-manifests@0.0.9 + - @backstage/cli-common@0.1.12 + - @backstage/config-loader@1.1.9 + - @backstage/errors@1.1.5 + - @backstage/types@1.0.2 + ## 0.22.4 ### Patch Changes diff --git a/packages/cli/asset-types/asset-types.d.ts b/packages/cli/asset-types/asset-types.d.ts index 9bd158bb8e..a1c053dc54 100644 --- a/packages/cli/asset-types/asset-types.d.ts +++ b/packages/cli/asset-types/asset-types.d.ts @@ -40,6 +40,11 @@ declare module '*.jpeg' { export default src; } +declare module '*.md' { + const src: string; + export default src; +} + declare module '*.png' { const src: string; export default src; diff --git a/packages/cli/package.json b/packages/cli/package.json index fd7f9a20c1..707a9a1f6e 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/cli", "description": "CLI for developing Backstage plugins and apps", - "version": "0.22.4", + "version": "0.22.6-next.0", "publishConfig": { "access": "public" }, @@ -39,6 +39,7 @@ "@backstage/types": "workspace:^", "@esbuild-kit/cjs-loader": "^2.4.1", "@manypkg/get-packages": "^1.1.3", + "@octokit/oauth-app": "^4.2.0", "@octokit/request": "^6.0.0", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.7", "@rollup/plugin-commonjs": "^23.0.0", diff --git a/packages/cli/src/commands/index.ts b/packages/cli/src/commands/index.ts index ddec5c6a4a..ba11a53cfd 100644 --- a/packages/cli/src/commands/index.ts +++ b/packages/cli/src/commands/index.ts @@ -25,6 +25,13 @@ const configOption = [ Array(), ] as const; +export function registerOnboardCommand(program: Command) { + program + .command('onboard', { hidden: true }) + .description('Get help setting up your Backstage App.') + .action(lazy(() => import('./onboard').then(m => m.command))); +} + export function registerRepoCommand(program: Command) { const command = program .command('repo [command]') @@ -360,6 +367,7 @@ export function registerCommands(program: Command) { registerRepoCommand(program); registerScriptCommand(program); registerMigrateCommand(program); + registerOnboardCommand(program); program .command('versions:bump') diff --git a/packages/cli/src/commands/onboard/README.md b/packages/cli/src/commands/onboard/README.md new file mode 100644 index 0000000000..0fb4d22666 --- /dev/null +++ b/packages/cli/src/commands/onboard/README.md @@ -0,0 +1,22 @@ +# onboard + +## Local dev + +# Create a new app + +```bash +cd .. +npx @backstage/create-app +cd new-backstage-app + +# Run the modded cli in the new app + +../RELATIVE_PATH_TO_PROJECT/backstage/packages/cli/bin/backstage-cli onboard +? Do you want to set up Authentication for this project? (Y/n) +... + +# Try the app with the new changes + +yarn dev + +``` diff --git a/packages/cli/src/commands/onboard/auth/index.ts b/packages/cli/src/commands/onboard/auth/index.ts new file mode 100644 index 0000000000..0f4537b110 --- /dev/null +++ b/packages/cli/src/commands/onboard/auth/index.ts @@ -0,0 +1,63 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import inquirer from 'inquirer'; +import { Task } from '../../../lib/tasks'; +import { github, Answers as GitHubAnswers } from './providers/github'; +import { gitlab, Answers as GitLabAnswers } from './providers/gitlab'; + +export { type GitHubAnswers, type GitLabAnswers }; + +export async function auth(): Promise<{ + provider: string; + answers: GitHubAnswers | GitLabAnswers; +}> { + const answers = await inquirer.prompt<{ + provider: string; + }>([ + { + type: 'list', + name: 'provider', + message: 'Please select an authentication provider:', + choices: ['GitHub', 'GitLab'], + }, + ]); + + const { provider } = answers; + + let providerAnswers; + switch (provider) { + case 'GitHub': { + providerAnswers = await github(); + break; + } + case 'GitLab': { + providerAnswers = await gitlab(); + break; + } + default: + throw new Error(`Provider ${provider} not implemented yet.`); + } + + Task.log(); + Task.log(`Done setting up ${provider} Authentication!`); + Task.log(); + + return { + provider, + answers: providerAnswers, + }; +} diff --git a/packages/cli/src/commands/onboard/auth/patch.ts b/packages/cli/src/commands/onboard/auth/patch.ts new file mode 100644 index 0000000000..d004eeb157 --- /dev/null +++ b/packages/cli/src/commands/onboard/auth/patch.ts @@ -0,0 +1,43 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as fs from 'fs-extra'; +import * as path from 'path'; +import * as differ from 'diff'; +import { PATCH_FOLDER } from '../files'; +import { findPaths } from '@backstage/cli-common'; + +/* eslint-disable-next-line no-restricted-syntax */ +const { targetRoot } = findPaths(__dirname); + +export const patch = async (patchFile: string) => { + const patchContent = await fs.readFile( + path.join(PATCH_FOLDER, patchFile), + 'utf8', + ); + const targetName = patchContent.split('\n')[0].replace('--- a', ''); + const targetFile = path.join(targetRoot, targetName); + const oldContent = await fs.readFile(targetFile, 'utf8'); + const newContent = differ.applyPatch(oldContent, patchContent); + if (!newContent) { + throw new Error( + `Patch ${patchFile} was not applied correctly. + Did you change ${targetName} manually before running this command?`, + ); + } + + return await fs.writeFile(targetFile, newContent, 'utf8'); +}; diff --git a/packages/cli/src/commands/onboard/auth/patches/01-github.Add-SignInPage.patch b/packages/cli/src/commands/onboard/auth/patches/01-github.Add-SignInPage.patch new file mode 100644 index 0000000000..db9f5228e8 --- /dev/null +++ b/packages/cli/src/commands/onboard/auth/patches/01-github.Add-SignInPage.patch @@ -0,0 +1,25 @@ +--- a/packages/app/src/App.tsx ++++ b/packages/app/src/App.tsx +@@ -30 +30,5 @@ import { Root } from './components/Root'; +-import { AlertDisplay, OAuthRequestDialog } from '@backstage/core-components'; ++import { ++ AlertDisplay, ++ OAuthRequestDialog, ++ SignInPage, ++} from '@backstage/core-components'; +@@ -35,0 +40 @@ import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common/ ++import { githubAuthApiRef } from '@backstage/core-plugin-api'; +@@ -38,0 +44,14 @@ const app = createApp({ ++ components: { ++ SignInPage: props => ( ++ ++ ), ++ }, \ No newline at end of file diff --git a/packages/cli/src/commands/onboard/auth/patches/02-gitlab.Add-SignInPage.patch b/packages/cli/src/commands/onboard/auth/patches/02-gitlab.Add-SignInPage.patch new file mode 100644 index 0000000000..da849220b8 --- /dev/null +++ b/packages/cli/src/commands/onboard/auth/patches/02-gitlab.Add-SignInPage.patch @@ -0,0 +1,25 @@ +--- a/packages/app/src/App.tsx ++++ b/packages/app/src/App.tsx +@@ -30 +30,5 @@ import { Root } from './components/Root'; +-import { AlertDisplay, OAuthRequestDialog } from '@backstage/core-components'; ++import { ++ AlertDisplay, ++ OAuthRequestDialog, ++ SignInPage, ++} from '@backstage/core-components'; +@@ -35,0 +40 @@ import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common/ ++import { gitlabAuthApiRef } from '@backstage/core-plugin-api'; +@@ -38,0 +44,14 @@ const app = createApp({ ++ components: { ++ SignInPage: props => ( ++ ++ ), ++ }, \ No newline at end of file diff --git a/packages/cli/src/commands/onboard/auth/patches/03-gitlab.Change-signIn-resolver.patch b/packages/cli/src/commands/onboard/auth/patches/03-gitlab.Change-signIn-resolver.patch new file mode 100644 index 0000000000..7a69669674 --- /dev/null +++ b/packages/cli/src/commands/onboard/auth/patches/03-gitlab.Change-signIn-resolver.patch @@ -0,0 +1,5 @@ +--- a/packages/backend/src/plugins/auth.ts ++++ b/packages/backend/src/plugins/auth.ts +@@ -38 +38 @@ export default async function createPlugin( +- github: providers.github.create({ ++ gitlab: providers.gitlab.create({ \ No newline at end of file diff --git a/packages/cli/src/commands/onboard/auth/providers/github.ts b/packages/cli/src/commands/onboard/auth/providers/github.ts new file mode 100644 index 0000000000..36c6b02038 --- /dev/null +++ b/packages/cli/src/commands/onboard/auth/providers/github.ts @@ -0,0 +1,147 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { OAuthApp } from '@octokit/oauth-app'; +import chalk from 'chalk'; +import * as fs from 'fs-extra'; +import inquirer from 'inquirer'; +import { Task } from '../../../../lib/tasks'; +import { updateConfigFile } from '../../config'; +import { APP_CONFIG_FILE, PATCH_FOLDER } from '../../files'; +import { patch } from '../patch'; + +export type Answers = { + clientSecret: string; + clientId: string; + hasEnterprise: boolean; + enterpriseInstanceUrl?: string; +}; + +const validateCredentials = async (clientId: string, clientSecret: string) => { + try { + const app = new OAuthApp({ + clientId, + clientSecret, + }); + await app.createToken({ + code: '%NOT-VALID-CODE%', + }); + } catch (error) { + // @octokit/request returns a error.response object when a request is rejected. + // We can check it to see what kind of error we received. + + // If error.response is successful we can double-check that the error itself was due to the bad code. + // If that's the case then we can assume that the client id and secret exists as we otherwise would + // have gotten a 400/404. + if ( + error.response.status !== 200 && + error.response.data.error !== 'bad_verification_code' + ) { + throw new Error(`Validating GitHub Credentials failed.`); + } + } +}; + +const getConfig = (answers: Answers) => { + const { clientId, clientSecret, hasEnterprise, enterpriseInstanceUrl } = + answers; + + return { + auth: { + providers: { + github: { + development: { + clientId, + clientSecret, + ...(hasEnterprise && { + enterpriseInstanceUrl, + }), + }, + }, + }, + }, + }; +}; + +export const github = async (): Promise => { + Task.log(` + To add GitHub authentication, you must create an OAuth App from the GitHub developer settings: ${chalk.blue( + 'https://github.com/settings/developers', + )} + The Homepage URL should point to Backstage's frontend, while the Authorization callback URL will point to the auth backend. + + Settings for local development: + ${chalk.cyan(` + Homepage URL: http://localhost:3000 + Authorization callback URL: http://localhost:7007/api/auth/github/handler/frame`)} + + You can find the full documentation page here: ${chalk.blue( + 'https://backstage.io/docs/auth/github/provider', + )} + `); + + const answers = await inquirer.prompt([ + { + type: 'input', + name: 'clientId', + message: 'What is your Client Id?', + validate: (input: string) => (input.length ? true : false), + }, + { + type: 'input', + name: 'clientSecret', + message: 'What is your Client Secret?', + validate: (input: string) => (input.length ? true : false), + }, + { + type: 'confirm', + name: 'hasEnterprise', + message: 'Are you using GitHub Enterprise?', + }, + { + type: 'input', + name: 'enterpriseInstanceUrl', + message: 'What is your URL for GitHub Enterprise?', + when: ({ hasEnterprise }) => hasEnterprise, + validate: (input: string) => Boolean(new URL(input)), + }, + ]); + + const { clientId, clientSecret } = answers; + const config = getConfig(answers); + + Task.log('Setting up GitHub Authentication for you...'); + + await Task.forItem( + 'Validating', + 'credentials', + async () => await validateCredentials(clientId, clientSecret), + ); + await Task.forItem( + 'Updating', + APP_CONFIG_FILE, + async () => await updateConfigFile(APP_CONFIG_FILE, config), + ); + + const patches = await fs.readdir(PATCH_FOLDER); + for (const patchFile of patches.filter(p => p.includes('github'))) { + await Task.forItem('Patching', patchFile, async () => { + await patch(patchFile); + }); + } + + return answers; +}; diff --git a/packages/cli/src/commands/onboard/auth/providers/gitlab.ts b/packages/cli/src/commands/onboard/auth/providers/gitlab.ts new file mode 100644 index 0000000000..bc5491111c --- /dev/null +++ b/packages/cli/src/commands/onboard/auth/providers/gitlab.ts @@ -0,0 +1,115 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import chalk from 'chalk'; +import * as fs from 'fs-extra'; +import inquirer from 'inquirer'; +import { Task } from '../../../../lib/tasks'; +import { updateConfigFile } from '../../config'; +import { APP_CONFIG_FILE, PATCH_FOLDER } from '../../files'; +import { patch } from '../patch'; + +const getConfig = (answers: Answers) => { + const { clientId, clientSecret, hasAudience, audience } = answers; + + return { + auth: { + providers: { + gitlab: { + development: { + clientId, + clientSecret, + ...(hasAudience && { + audience, + }), + }, + }, + }, + }, + }; +}; + +export type Answers = { + clientSecret: string; + clientId: string; + hasAudience: boolean; + audience?: string; +}; + +export const gitlab = async (): Promise => { + Task.log(` + To add GitLab authentication, you must create an Application from the GitLab Settings: ${chalk.blue( + 'https://gitlab.com/-/profile/applications', + )} + The Redirect URI should point to your Backstage backend auth handler. + + Settings for local development: + ${chalk.cyan(` + Name: Backstage (or your custom app name) + Redirect URI: http://localhost:7007/api/auth/gitlab/handler/frame + Scopes: read_api and read_user`)} + + You can find the full documentation page here: ${chalk.blue( + 'https://backstage.io/docs/auth/gitlab/provider', + )} + `); + + const answers = await inquirer.prompt([ + { + type: 'input', + name: 'clientId', + message: 'What is your Application Id?', + validate: (input: string) => (input.length ? true : false), + }, + { + type: 'input', + name: 'clientSecret', + message: 'What is your Application Secret?', + validate: (input: string) => (input.length ? true : false), + }, + { + type: 'confirm', + name: 'hasAudience', + message: 'Do you have a self-hosted instance of GitLab?', + }, + { + type: 'input', + name: 'audience', + message: 'What is the URL for your GitLab instance?', + when: ({ hasAudience }) => hasAudience, + validate: (input: string) => Boolean(new URL(input)), + }, + ]); + + const config = getConfig(answers); + + Task.log('Setting up GitLab Authentication for you...'); + + await Task.forItem( + 'Updating', + APP_CONFIG_FILE, + async () => await updateConfigFile(APP_CONFIG_FILE, config), + ); + + const patches = await fs.readdir(PATCH_FOLDER); + for (const patchFile of patches.filter(p => p.includes('gitlab'))) { + await Task.forItem('Patching', patchFile, async () => { + await patch(patchFile); + }); + } + + return answers; +}; diff --git a/packages/cli/src/commands/onboard/command.ts b/packages/cli/src/commands/onboard/command.ts new file mode 100644 index 0000000000..5cf25953ab --- /dev/null +++ b/packages/cli/src/commands/onboard/command.ts @@ -0,0 +1,69 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import chalk from 'chalk'; +import inquirer from 'inquirer'; +import { Task } from '../../lib/tasks'; +import { auth } from './auth'; +import { integrations } from './integrations'; + +export async function command(): Promise { + const answers = await inquirer.prompt<{ + shouldSetupAuth: boolean; + shouldSetupScaffolder: boolean; + }>([ + { + type: 'confirm', + name: 'shouldSetupAuth', + message: 'Do you want to set up Authentication for this project?', + default: true, + }, + { + type: 'confirm', + name: 'shouldSetupScaffolder', + message: 'Do you want to use Software Templates in this project?', + default: true, + }, + ]); + + const { shouldSetupAuth, shouldSetupScaffolder } = answers; + + let providerInfo; + if (shouldSetupAuth) { + providerInfo = await auth(); + } + + if (shouldSetupScaffolder) { + await integrations(providerInfo); + } + + if (!shouldSetupAuth && !shouldSetupScaffolder) { + Task.log( + chalk.yellow( + 'If you change your mind, feel free to re-run this command.', + ), + ); + return; + } + + Task.log(); + Task.log( + `You can now start your app with ${chalk.inverse( + chalk.italic('yarn dev'), + )}`, + ); + Task.log(); +} diff --git a/packages/cli/src/commands/onboard/config.ts b/packages/cli/src/commands/onboard/config.ts new file mode 100644 index 0000000000..cce3119fcc --- /dev/null +++ b/packages/cli/src/commands/onboard/config.ts @@ -0,0 +1,45 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as fs from 'fs-extra'; +import yaml from 'yaml'; + +const readYaml = async (file: string) => { + return yaml.parse(await fs.readFile(file, 'utf8')); +}; + +export const updateConfigFile = async (file: string, config: T) => { + const staticContent = + '# Backstage override configuration for your local development environment \n'; + + const content = fs.existsSync(file) + ? yaml.stringify( + { ...(await readYaml(file)), ...config }, + { + indent: 2, + }, + ) + : staticContent.concat( + yaml.stringify( + { ...config }, + { + indent: 2, + }, + ), + ); + + return await fs.writeFile(file, content, 'utf8'); +}; diff --git a/packages/cli/src/commands/onboard/files.ts b/packages/cli/src/commands/onboard/files.ts new file mode 100644 index 0000000000..17f8a0f85e --- /dev/null +++ b/packages/cli/src/commands/onboard/files.ts @@ -0,0 +1,30 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { findPaths } from '@backstage/cli-common'; +import * as path from 'path'; + +/* eslint-disable-next-line no-restricted-syntax */ +const { targetRoot, ownDir } = findPaths(__dirname); +export const APP_CONFIG_FILE = path.join(targetRoot, 'app-config.local.yaml'); +export const PATCH_FOLDER = path.join( + ownDir, + 'src', + 'commands', + 'onboard', + 'auth', + 'patches', +); diff --git a/packages/cli/src/commands/onboard/index.ts b/packages/cli/src/commands/onboard/index.ts new file mode 100644 index 0000000000..4c23ea6e48 --- /dev/null +++ b/packages/cli/src/commands/onboard/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { command } from './command'; diff --git a/packages/cli/src/commands/onboard/integrations/github.ts b/packages/cli/src/commands/onboard/integrations/github.ts new file mode 100644 index 0000000000..a0538c7ace --- /dev/null +++ b/packages/cli/src/commands/onboard/integrations/github.ts @@ -0,0 +1,136 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import chalk from 'chalk'; +import inquirer from 'inquirer'; +import { Task } from '../../../lib/tasks'; +import { updateConfigFile } from '../config'; +import { APP_CONFIG_FILE } from '../files'; +import { GitHubAnswers } from '../auth'; + +type Answers = { + hasEnterprise: boolean; + enterpriseInstanceUrl: string; + apiBaseUrl: string; +}; + +const getConfig = ({ + hasEnterprise, + apiBaseUrl, + host, + token, +}: { + hasEnterprise: boolean; + apiBaseUrl: string; + host: string; + token: string; +}) => ({ + integrations: { + github: [ + { + host, + token, + ...(hasEnterprise && { + apiBaseUrl, + }), + }, + ], + }, +}); + +export const github = async (providerAnswers?: GitHubAnswers) => { + // TODO(tudi2d): Is GitHub Enterprise a valid setup if there is no Authentication? + const answers = await inquirer.prompt([ + { + type: 'confirm', + name: 'hasEnterprise', + message: 'Are you using GitHub Enterprise?', + when: () => typeof providerAnswers === 'undefined', + }, + { + type: 'input', + name: 'enterpriseInstanceUrl', + message: 'What is your URL for GitHub Enterprise?', + when: ({ hasEnterprise }) => hasEnterprise, + validate: (input: string) => Boolean(new URL(input)), + }, + { + type: 'input', + name: 'apiBaseUrl', + message: 'What is your GitHub Enterprise API path?', + default: '/api/v3', + when: ({ hasEnterprise }) => + hasEnterprise || providerAnswers?.hasEnterprise, + // TODO(tudi2d): Fetch API using OAuth Token if Auth was set up + }, + ]); + + const host = new URL( + providerAnswers?.enterpriseInstanceUrl ?? + answers?.enterpriseInstanceUrl ?? + 'http://github.com', + ); + + Task.log(` + To create new repositories in GitHub using Software Templates you first need to create a personal access token: ${chalk.blue( + `${host.origin}/settings/tokens/new`, + )} + + Select the following scopes: + + Reading software components:${chalk.cyan(` + - "repo"`)} + + Reading organization data:${chalk.cyan(` + - "read:org" + - "read:user" + - "user:email"`)} + + Publishing software templates:${chalk.cyan(` + - "repo" + - "workflow" (if templates include GitHub workflows) + `)} + + You can find the full documentation page here: ${chalk.blue( + 'https://backstage.io/docs/integrations/github/locations', + )} + `); + + const { token } = await inquirer.prompt<{ token: string }>([ + { + type: 'input', + name: 'token', + message: + 'Please insert your personal access token to setup the GitHub Integration', + // TODO(tudi2d): validate + }, + ]); + + const config = getConfig({ + hasEnterprise: providerAnswers?.hasEnterprise ?? answers.hasEnterprise, + apiBaseUrl: host.origin + answers.apiBaseUrl, + host: host.hostname, + token, + }); + + Task.log('Setting up Software Templates using GitHub integration for you...'); + + await Task.forItem( + 'Updating', + APP_CONFIG_FILE, + async () => await updateConfigFile(APP_CONFIG_FILE, config), + ); +}; diff --git a/packages/cli/src/commands/onboard/integrations/index.ts b/packages/cli/src/commands/onboard/integrations/index.ts new file mode 100644 index 0000000000..5cb2f95b38 --- /dev/null +++ b/packages/cli/src/commands/onboard/integrations/index.ts @@ -0,0 +1,75 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import inquirer from 'inquirer'; +import { Task } from '../../../lib/tasks'; +import { GitHubAnswers, GitLabAnswers } from '../auth'; +import { github } from './github'; + +enum Integration { + GITHUB = 'GitHub', +} + +const Integrations: Integration[] = [Integration.GITHUB]; + +export async function integrations(providerInfo?: { + provider: string; + answers: GitHubAnswers | GitLabAnswers; +}): Promise { + const answers = await inquirer.prompt<{ + integration?: Integration; + shouldUsePreviousProvider: boolean; + }>([ + { + type: 'confirm', + name: 'shouldUsePreviousProvider', + message: `Do you want to keep using ${providerInfo?.provider} as your provider when setting up Software Templates?`, + when: () => + providerInfo?.provider && + Object.values(Integrations).includes( + providerInfo!.provider as Integration, + ), + }, + { + // TODO(tudi2d): Let's start with one, but it should be multiple choice in the future + type: 'list', + name: 'integration', + message: 'Please select an integration provider:', + choices: Integrations, + when: ({ shouldUsePreviousProvider }) => !shouldUsePreviousProvider, + }, + ]); + + if (answers.shouldUsePreviousProvider) { + answers.integration = providerInfo!.provider as Integration; + } + + switch (answers.integration) { + case Integration.GITHUB: { + const providerAnswers = + providerInfo?.provider === 'GitHub' + ? (providerInfo!.answers as GitHubAnswers) + : undefined; + await github(providerAnswers); + break; + } + default: + } + + Task.log(); + Task.log(`Done setting up ${answers.integration} Integration!`); + Task.log(); +} diff --git a/packages/cli/src/lib/builder/config.ts b/packages/cli/src/lib/builder/config.ts index ecd755d05b..3e61dd113a 100644 --- a/packages/cli/src/lib/builder/config.ts +++ b/packages/cli/src/lib/builder/config.ts @@ -132,6 +132,7 @@ export async function makeRollupConfigs( /\.woff$/, /\.woff2$/, /\.ttf$/, + /\.md$/, ], }), json(), diff --git a/packages/cli/src/lib/bundler/config.ts b/packages/cli/src/lib/bundler/config.ts index 01f323a082..6fc7482dce 100644 --- a/packages/cli/src/lib/bundler/config.ts +++ b/packages/cli/src/lib/bundler/config.ts @@ -15,7 +15,7 @@ */ import fs from 'fs-extra'; -import { resolve as resolvePath, join as joinPath } from 'path'; +import { resolve as resolvePath, posix as posixPath } from 'path'; import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'; import HtmlWebpackPlugin from 'html-webpack-plugin'; import ModuleScopePlugin from 'react-dev-utils/ModuleScopePlugin'; @@ -236,7 +236,7 @@ export async function createBackendConfig( const { packages } = await getPackages(cliPaths.targetDir); const localPackageEntryPoints = packages.flatMap(p => { const entryPoints = readEntryPoints((p as ExtendedPackage).packageJson); - return entryPoints.map(e => joinPath(p.packageJson.name, e.mount)); + return entryPoints.map(e => posixPath.join(p.packageJson.name, e.mount)); }); const moduleDirs = packages.map(p => resolvePath(p.dir, 'node_modules')); // See frontend config diff --git a/packages/cli/templates/default-plugin/package.json.hbs b/packages/cli/templates/default-plugin/package.json.hbs index de42f3cdef..10f893d7dc 100644 --- a/packages/cli/templates/default-plugin/package.json.hbs +++ b/packages/cli/templates/default-plugin/package.json.hbs @@ -33,7 +33,7 @@ "@backstage/theme": "{{versionQuery '@backstage/theme'}}", "@material-ui/core": "{{versionQuery '@material-ui/core' '4.12.2'}}", "@material-ui/icons": "{{versionQuery '@material-ui/icons' '4.9.1'}}", - "@material-ui/lab": "{{versionQuery '@material-ui/lab' '4.0.0-alpha.57'}}", + "@material-ui/lab": "{{versionQuery '@material-ui/lab' '4.0.0-alpha.61'}}", "react-use": "{{versionQuery 'react-use' '17.2.4'}}" }, "peerDependencies": { diff --git a/packages/core-app-api/CHANGELOG.md b/packages/core-app-api/CHANGELOG.md index 2f54b5d041..af0ca61ef0 100644 --- a/packages/core-app-api/CHANGELOG.md +++ b/packages/core-app-api/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/core-app-api +## 1.7.0-next.0 + +### Minor Changes + +- 7908d72e033: Introduce a new global config parameter, `auth.enableExperimentalRedirectFlow`. When enabled, auth will happen with an in-window redirect flow rather than through a popup window. + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.5.0 + - @backstage/config@1.0.7 + - @backstage/types@1.0.2 + - @backstage/version-bridge@1.0.3 + ## 1.6.0 ### Minor Changes diff --git a/packages/core-app-api/api-report.md b/packages/core-app-api/api-report.md index 37f7a98de0..d7e4a22873 100644 --- a/packages/core-app-api/api-report.md +++ b/packages/core-app-api/api-report.md @@ -25,6 +25,7 @@ import { bitbucketAuthApiRef } from '@backstage/core-plugin-api'; import { bitbucketServerAuthApiRef } from '@backstage/core-plugin-api'; import { ComponentType } from 'react'; import { Config } from '@backstage/config'; +import { ConfigApi } from '@backstage/core-plugin-api'; import { ConfigReader } from '@backstage/config'; import { DiscoveryApi } from '@backstage/core-plugin-api'; import { ErrorApi } from '@backstage/core-plugin-api'; @@ -264,6 +265,7 @@ export type AuthApiCreateOptions = { discoveryApi: DiscoveryApi; environment?: string; provider?: AuthProviderInfo; + configApi?: ConfigApi; }; // @public @@ -533,6 +535,7 @@ export class OneLoginAuth { // @public export type OneLoginAuthCreateOptions = { + configApi?: ConfigApi; discoveryApi: DiscoveryApi; oauthRequestApi: OAuthRequestApi; environment?: string; diff --git a/packages/core-app-api/config.d.ts b/packages/core-app-api/config.d.ts index ae876f7fe0..2de1d96114 100644 --- a/packages/core-app-api/config.d.ts +++ b/packages/core-app-api/config.d.ts @@ -115,4 +115,11 @@ export interface Config { */ environment?: string; }; + + /** + $ Enable redirect authentication flow type, instead of a popup for authentication + * default value: 'false' + * @visibility frontend + */ + enableExperimentalRedirectFlow?: boolean; } diff --git a/packages/core-app-api/package.json b/packages/core-app-api/package.json index c9ae2abc25..a2239301f2 100644 --- a/packages/core-app-api/package.json +++ b/packages/core-app-api/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/core-app-api", "description": "Core app API used by Backstage apps", - "version": "1.6.0", + "version": "1.7.0-next.0", "publishConfig": { "access": "public", "main": "dist/index.esm.js", diff --git a/packages/core-app-api/src/apis/implementations/auth/atlassian/AtlassianAuth.ts b/packages/core-app-api/src/apis/implementations/auth/atlassian/AtlassianAuth.ts index 07ebefca28..3477eec361 100644 --- a/packages/core-app-api/src/apis/implementations/auth/atlassian/AtlassianAuth.ts +++ b/packages/core-app-api/src/apis/implementations/auth/atlassian/AtlassianAuth.ts @@ -32,6 +32,7 @@ const DEFAULT_PROVIDER = { export default class AtlassianAuth { static create(options: OAuthApiCreateOptions): typeof atlassianAuthApiRef.T { const { + configApi, discoveryApi, environment = 'development', provider = DEFAULT_PROVIDER, @@ -39,6 +40,7 @@ export default class AtlassianAuth { } = options; return OAuth2.create({ + configApi, discoveryApi, oauthRequestApi, provider, diff --git a/packages/core-app-api/src/apis/implementations/auth/bitbucket/BitbucketAuth.test.ts b/packages/core-app-api/src/apis/implementations/auth/bitbucket/BitbucketAuth.test.ts index f4bd7cbe85..1335808280 100644 --- a/packages/core-app-api/src/apis/implementations/auth/bitbucket/BitbucketAuth.test.ts +++ b/packages/core-app-api/src/apis/implementations/auth/bitbucket/BitbucketAuth.test.ts @@ -17,6 +17,7 @@ import MockOAuthApi from '../../OAuthRequestApi/MockOAuthApi'; import { UrlPatternDiscovery } from '../../DiscoveryApi'; import BitbucketAuth from './BitbucketAuth'; +import { MockConfigApi } from '@backstage/test-utils'; const getSession = jest.fn(); @@ -32,6 +33,8 @@ describe('BitbucketAuth', () => { jest.resetAllMocks(); }); + const configApi = new MockConfigApi({}); + it.each([ ['team api write_repository', ['team', 'api', 'write_repository']], ['read_repository sudo', ['read_repository', 'sudo']], @@ -39,6 +42,7 @@ describe('BitbucketAuth', () => { const gitlabAuth = BitbucketAuth.create({ oauthRequestApi: new MockOAuthApi(), discoveryApi: UrlPatternDiscovery.compile('http://example.com'), + configApi: configApi, }); gitlabAuth.getAccessToken(scope); diff --git a/packages/core-app-api/src/apis/implementations/auth/bitbucket/BitbucketAuth.ts b/packages/core-app-api/src/apis/implementations/auth/bitbucket/BitbucketAuth.ts index 7c5d4f3fc0..7a9f1bc094 100644 --- a/packages/core-app-api/src/apis/implementations/auth/bitbucket/BitbucketAuth.ts +++ b/packages/core-app-api/src/apis/implementations/auth/bitbucket/BitbucketAuth.ts @@ -47,6 +47,7 @@ const DEFAULT_PROVIDER = { export default class BitbucketAuth { static create(options: OAuthApiCreateOptions): typeof bitbucketAuthApiRef.T { const { + configApi, discoveryApi, environment = 'development', provider = DEFAULT_PROVIDER, @@ -55,6 +56,7 @@ export default class BitbucketAuth { } = options; return OAuth2.create({ + configApi, discoveryApi, oauthRequestApi, provider, diff --git a/packages/core-app-api/src/apis/implementations/auth/bitbucketServer/BitbucketServerAuth.test.ts b/packages/core-app-api/src/apis/implementations/auth/bitbucketServer/BitbucketServerAuth.test.ts index 32e7755a00..5631a9a886 100644 --- a/packages/core-app-api/src/apis/implementations/auth/bitbucketServer/BitbucketServerAuth.test.ts +++ b/packages/core-app-api/src/apis/implementations/auth/bitbucketServer/BitbucketServerAuth.test.ts @@ -17,6 +17,7 @@ import MockOAuthApi from '../../OAuthRequestApi/MockOAuthApi'; import { UrlPatternDiscovery } from '../../DiscoveryApi'; import BitbucketServerAuth from './BitbucketServerAuth'; +import { MockConfigApi } from '@backstage/test-utils'; const getSession = jest.fn(); @@ -40,7 +41,10 @@ describe('BitbucketServerAuth', () => { ['PROJECT_ADMIN', 'REPO_READ', 'ACCOUNT_WRITE'], ], ])(`should normalize scopes correctly - %p`, (scope, scopes) => { + const configApi = new MockConfigApi({}); + const bitbucketServerAuth = BitbucketServerAuth.create({ + configApi: configApi, oauthRequestApi: new MockOAuthApi(), discoveryApi: UrlPatternDiscovery.compile('http://example.com'), }); diff --git a/packages/core-app-api/src/apis/implementations/auth/bitbucketServer/BitbucketServerAuth.ts b/packages/core-app-api/src/apis/implementations/auth/bitbucketServer/BitbucketServerAuth.ts index dc50eff6ab..b25deffb93 100644 --- a/packages/core-app-api/src/apis/implementations/auth/bitbucketServer/BitbucketServerAuth.ts +++ b/packages/core-app-api/src/apis/implementations/auth/bitbucketServer/BitbucketServerAuth.ts @@ -48,6 +48,7 @@ export default class BitbucketServerAuth { options: OAuthApiCreateOptions, ): typeof bitbucketServerAuthApiRef.T { const { + configApi, discoveryApi, environment = 'development', provider = DEFAULT_PROVIDER, @@ -56,6 +57,7 @@ export default class BitbucketServerAuth { } = options; return OAuth2.create({ + configApi, discoveryApi, oauthRequestApi, provider, diff --git a/packages/core-app-api/src/apis/implementations/auth/github/GithubAuth.test.ts b/packages/core-app-api/src/apis/implementations/auth/github/GithubAuth.test.ts index ea7b4ac688..fc77754f6f 100644 --- a/packages/core-app-api/src/apis/implementations/auth/github/GithubAuth.test.ts +++ b/packages/core-app-api/src/apis/implementations/auth/github/GithubAuth.test.ts @@ -17,6 +17,7 @@ import { UrlPatternDiscovery } from '../../DiscoveryApi'; import MockOAuthApi from '../../OAuthRequestApi/MockOAuthApi'; import GithubAuth from './GithubAuth'; +import { MockConfigApi } from '@backstage/test-utils'; const getSession = jest.fn(); @@ -32,8 +33,11 @@ describe('GithubAuth', () => { jest.resetAllMocks(); }); + const configApi = new MockConfigApi({}); + it('should forward access token request to session manager', async () => { const githubAuth = GithubAuth.create({ + configApi: configApi, oauthRequestApi: new MockOAuthApi(), discoveryApi: UrlPatternDiscovery.compile('http://example.com'), }); diff --git a/packages/core-app-api/src/apis/implementations/auth/github/GithubAuth.ts b/packages/core-app-api/src/apis/implementations/auth/github/GithubAuth.ts index 7efe4e95c6..943dfa7da4 100644 --- a/packages/core-app-api/src/apis/implementations/auth/github/GithubAuth.ts +++ b/packages/core-app-api/src/apis/implementations/auth/github/GithubAuth.ts @@ -32,6 +32,7 @@ const DEFAULT_PROVIDER = { export default class GithubAuth { static create(options: OAuthApiCreateOptions): typeof githubAuthApiRef.T { const { + configApi, discoveryApi, environment = 'development', provider = DEFAULT_PROVIDER, @@ -40,6 +41,7 @@ export default class GithubAuth { } = options; return OAuth2.create({ + configApi, discoveryApi, oauthRequestApi, provider, diff --git a/packages/core-app-api/src/apis/implementations/auth/gitlab/GitlabAuth.test.ts b/packages/core-app-api/src/apis/implementations/auth/gitlab/GitlabAuth.test.ts index 3346af9b7c..6dde0c0334 100644 --- a/packages/core-app-api/src/apis/implementations/auth/gitlab/GitlabAuth.test.ts +++ b/packages/core-app-api/src/apis/implementations/auth/gitlab/GitlabAuth.test.ts @@ -17,6 +17,7 @@ import MockOAuthApi from '../../OAuthRequestApi/MockOAuthApi'; import { UrlPatternDiscovery } from '../../DiscoveryApi'; import GitlabAuth from './GitlabAuth'; +import { MockConfigApi } from '@backstage/test-utils'; const getSession = jest.fn(); @@ -39,7 +40,10 @@ describe('GitlabAuth', () => { ], ['read_repository sudo', ['read_repository', 'sudo']], ])(`should normalize scopes correctly - %p`, (scope, scopes) => { + const configApi = new MockConfigApi({}); + const gitlabAuth = GitlabAuth.create({ + configApi: configApi, oauthRequestApi: new MockOAuthApi(), discoveryApi: UrlPatternDiscovery.compile('http://example.com'), }); diff --git a/packages/core-app-api/src/apis/implementations/auth/gitlab/GitlabAuth.ts b/packages/core-app-api/src/apis/implementations/auth/gitlab/GitlabAuth.ts index 00085de8ac..c39f5a6e23 100644 --- a/packages/core-app-api/src/apis/implementations/auth/gitlab/GitlabAuth.ts +++ b/packages/core-app-api/src/apis/implementations/auth/gitlab/GitlabAuth.ts @@ -32,6 +32,7 @@ const DEFAULT_PROVIDER = { export default class GitlabAuth { static create(options: OAuthApiCreateOptions): typeof gitlabAuthApiRef.T { const { + configApi, discoveryApi, environment = 'development', provider = DEFAULT_PROVIDER, @@ -40,6 +41,7 @@ export default class GitlabAuth { } = options; return OAuth2.create({ + configApi, discoveryApi, oauthRequestApi, provider, diff --git a/packages/core-app-api/src/apis/implementations/auth/google/GoogleAuth.test.ts b/packages/core-app-api/src/apis/implementations/auth/google/GoogleAuth.test.ts index f8a1c3a1f5..7897eef42e 100644 --- a/packages/core-app-api/src/apis/implementations/auth/google/GoogleAuth.test.ts +++ b/packages/core-app-api/src/apis/implementations/auth/google/GoogleAuth.test.ts @@ -17,6 +17,7 @@ import GoogleAuth from './GoogleAuth'; import MockOAuthApi from '../../OAuthRequestApi/MockOAuthApi'; import { UrlPatternDiscovery } from '../../DiscoveryApi'; +import { MockConfigApi } from '@backstage/test-utils'; const PREFIX = 'https://www.googleapis.com/auth/'; @@ -58,7 +59,10 @@ describe('GoogleAuth', () => { [`${PREFIX}profile`, [`${PREFIX}profile`]], [`${PREFIX}openid`, [`${PREFIX}openid`]], ])(`should normalize scopes correctly - %p`, (scope, scopes) => { + const configApi = new MockConfigApi({}); + const googleAuth = GoogleAuth.create({ + configApi: configApi, oauthRequestApi: new MockOAuthApi(), discoveryApi: UrlPatternDiscovery.compile('http://example.com'), }); diff --git a/packages/core-app-api/src/apis/implementations/auth/google/GoogleAuth.ts b/packages/core-app-api/src/apis/implementations/auth/google/GoogleAuth.ts index 8a528f4511..f4674ab64f 100644 --- a/packages/core-app-api/src/apis/implementations/auth/google/GoogleAuth.ts +++ b/packages/core-app-api/src/apis/implementations/auth/google/GoogleAuth.ts @@ -34,6 +34,7 @@ const SCOPE_PREFIX = 'https://www.googleapis.com/auth/'; export default class GoogleAuth { static create(options: OAuthApiCreateOptions): typeof googleAuthApiRef.T { const { + configApi, discoveryApi, oauthRequestApi, environment = 'development', @@ -46,6 +47,7 @@ export default class GoogleAuth { } = options; return OAuth2.create({ + configApi, discoveryApi, oauthRequestApi, provider, diff --git a/packages/core-app-api/src/apis/implementations/auth/microsoft/MicrosoftAuth.ts b/packages/core-app-api/src/apis/implementations/auth/microsoft/MicrosoftAuth.ts index be5776609d..30cfde7c6e 100644 --- a/packages/core-app-api/src/apis/implementations/auth/microsoft/MicrosoftAuth.ts +++ b/packages/core-app-api/src/apis/implementations/auth/microsoft/MicrosoftAuth.ts @@ -32,6 +32,7 @@ const DEFAULT_PROVIDER = { export default class MicrosoftAuth { static create(options: OAuthApiCreateOptions): typeof microsoftAuthApiRef.T { const { + configApi, environment = 'development', provider = DEFAULT_PROVIDER, oauthRequestApi, @@ -46,6 +47,7 @@ export default class MicrosoftAuth { } = options; return OAuth2.create({ + configApi, discoveryApi, oauthRequestApi, provider, diff --git a/packages/core-app-api/src/apis/implementations/auth/oauth2/OAuth2.test.ts b/packages/core-app-api/src/apis/implementations/auth/oauth2/OAuth2.test.ts index 63070120ef..6f941379a7 100644 --- a/packages/core-app-api/src/apis/implementations/auth/oauth2/OAuth2.test.ts +++ b/packages/core-app-api/src/apis/implementations/auth/oauth2/OAuth2.test.ts @@ -17,6 +17,7 @@ import OAuth2 from './OAuth2'; import MockOAuthApi from '../../OAuthRequestApi/MockOAuthApi'; import { UrlPatternDiscovery } from '../../DiscoveryApi'; +import { MockConfigApi } from '@backstage/test-utils'; const theFuture = new Date(Date.now() + 3600000); const thePast = new Date(Date.now() - 10); @@ -34,12 +35,15 @@ jest.mock('../../../../lib/AuthSessionManager', () => ({ }, })); +const configApi = new MockConfigApi({}); + describe('OAuth2', () => { it('should get refreshed access token', async () => { getSession = jest.fn().mockResolvedValue({ providerInfo: { accessToken: 'access-token', expiresAt: theFuture }, }); const oauth2 = OAuth2.create({ + configApi: configApi, scopeTransform: scopeTransform, oauthRequestApi: new MockOAuthApi(), discoveryApi: UrlPatternDiscovery.compile('http://example.com'), @@ -58,6 +62,7 @@ describe('OAuth2', () => { providerInfo: { accessToken: 'access-token', expiresAt: theFuture }, }); const oauth2 = OAuth2.create({ + configApi: configApi, scopeTransform: scopes => scopes.map(scope => `my-prefix/${scope}`), oauthRequestApi: new MockOAuthApi(), discoveryApi: UrlPatternDiscovery.compile('http://example.com'), @@ -75,7 +80,9 @@ describe('OAuth2', () => { getSession = jest.fn().mockResolvedValue({ providerInfo: { idToken: 'id-token', expiresAt: theFuture }, }); + const oauth2 = OAuth2.create({ + configApi: configApi, scopeTransform: scopeTransform, oauthRequestApi: new MockOAuthApi(), discoveryApi: UrlPatternDiscovery.compile('http://example.com'), @@ -94,6 +101,7 @@ describe('OAuth2', () => { providerInfo: { idToken: 'id-token', expiresAt: theFuture }, }); const oauth2 = OAuth2.create({ + configApi: configApi, scopeTransform: scopes => scopes.map(scope => `my-prefix/${scope}`), oauthRequestApi: new MockOAuthApi(), discoveryApi: UrlPatternDiscovery.compile('http://example.com'), @@ -121,6 +129,7 @@ describe('OAuth2', () => { }) .mockRejectedValue(error); const oauth2 = OAuth2.create({ + configApi: configApi, scopeTransform: scopes => scopes.map(scope => `my-prefix/${scope}`), oauthRequestApi: new MockOAuthApi(), discoveryApi: UrlPatternDiscovery.compile('http://example.com'), @@ -155,6 +164,7 @@ describe('OAuth2', () => { }, }); const oauth2 = OAuth2.create({ + configApi: configApi, scopeTransform: scopes => scopes.map(scope => `my-prefix/${scope}`), oauthRequestApi: new MockOAuthApi(), discoveryApi: UrlPatternDiscovery.compile('http://example.com'), diff --git a/packages/core-app-api/src/apis/implementations/auth/oauth2/OAuth2.ts b/packages/core-app-api/src/apis/implementations/auth/oauth2/OAuth2.ts index 6f88178415..44bd5269ea 100644 --- a/packages/core-app-api/src/apis/implementations/auth/oauth2/OAuth2.ts +++ b/packages/core-app-api/src/apis/implementations/auth/oauth2/OAuth2.ts @@ -72,6 +72,7 @@ export default class OAuth2 { static create(options: OAuth2CreateOptions) { const { + configApi, discoveryApi, environment = 'development', provider = DEFAULT_PROVIDER, @@ -81,6 +82,7 @@ export default class OAuth2 } = options; const connector = new DefaultAuthConnector({ + configApi, discoveryApi, environment, provider, diff --git a/packages/core-app-api/src/apis/implementations/auth/okta/OktaAuth.test.ts b/packages/core-app-api/src/apis/implementations/auth/okta/OktaAuth.test.ts index 6489b326ff..5e7370a947 100644 --- a/packages/core-app-api/src/apis/implementations/auth/okta/OktaAuth.test.ts +++ b/packages/core-app-api/src/apis/implementations/auth/okta/OktaAuth.test.ts @@ -17,6 +17,7 @@ import OktaAuth from './OktaAuth'; import MockOAuthApi from '../../OAuthRequestApi/MockOAuthApi'; import { UrlPatternDiscovery } from '../../DiscoveryApi'; +import { MockConfigApi } from '@backstage/test-utils'; const PREFIX = 'okta.'; @@ -50,7 +51,9 @@ describe('OktaAuth', () => { [`${PREFIX}profile`, [`${PREFIX}profile`]], [`${PREFIX}openid`, [`${PREFIX}openid`]], ])(`should normalize scopes correctly - %p`, (scope, scopes) => { + const configApi = new MockConfigApi({}); const auth = OktaAuth.create({ + configApi: configApi, oauthRequestApi: new MockOAuthApi(), discoveryApi: UrlPatternDiscovery.compile('http://example.com'), }); diff --git a/packages/core-app-api/src/apis/implementations/auth/okta/OktaAuth.ts b/packages/core-app-api/src/apis/implementations/auth/okta/OktaAuth.ts index 42c0ddd0ed..c1921a8f93 100644 --- a/packages/core-app-api/src/apis/implementations/auth/okta/OktaAuth.ts +++ b/packages/core-app-api/src/apis/implementations/auth/okta/OktaAuth.ts @@ -44,6 +44,7 @@ const OKTA_SCOPE_PREFIX: string = 'okta.'; export default class OktaAuth { static create(options: OAuthApiCreateOptions): typeof oktaAuthApiRef.T { const { + configApi, discoveryApi, environment = 'development', provider = DEFAULT_PROVIDER, @@ -52,6 +53,7 @@ export default class OktaAuth { } = options; return OAuth2.create({ + configApi, discoveryApi, oauthRequestApi, provider, diff --git a/packages/core-app-api/src/apis/implementations/auth/onelogin/OneLoginAuth.ts b/packages/core-app-api/src/apis/implementations/auth/onelogin/OneLoginAuth.ts index ea9e2cad28..d8f54e7e50 100644 --- a/packages/core-app-api/src/apis/implementations/auth/onelogin/OneLoginAuth.ts +++ b/packages/core-app-api/src/apis/implementations/auth/onelogin/OneLoginAuth.ts @@ -18,6 +18,7 @@ import { oneloginAuthApiRef, OAuthRequestApi, AuthProviderInfo, + ConfigApi, DiscoveryApi, } from '@backstage/core-plugin-api'; import { OAuth2 } from '../oauth2'; @@ -27,6 +28,7 @@ import { OAuth2 } from '../oauth2'; * @public */ export type OneLoginAuthCreateOptions = { + configApi?: ConfigApi; discoveryApi: DiscoveryApi; oauthRequestApi: OAuthRequestApi; environment?: string; @@ -61,6 +63,7 @@ export default class OneLoginAuth { options: OneLoginAuthCreateOptions, ): typeof oneloginAuthApiRef.T { const { + configApi, discoveryApi, environment = 'development', provider = DEFAULT_PROVIDER, @@ -68,6 +71,7 @@ export default class OneLoginAuth { } = options; return OAuth2.create({ + configApi, discoveryApi, oauthRequestApi, provider, diff --git a/packages/core-app-api/src/apis/implementations/auth/types.ts b/packages/core-app-api/src/apis/implementations/auth/types.ts index 55d6c19098..7a74fd3a3b 100644 --- a/packages/core-app-api/src/apis/implementations/auth/types.ts +++ b/packages/core-app-api/src/apis/implementations/auth/types.ts @@ -16,6 +16,7 @@ import { AuthProviderInfo, + ConfigApi, DiscoveryApi, OAuthRequestApi, } from '@backstage/core-plugin-api'; @@ -37,4 +38,5 @@ export type AuthApiCreateOptions = { discoveryApi: DiscoveryApi; environment?: string; provider?: AuthProviderInfo; + configApi?: ConfigApi; }; diff --git a/packages/core-app-api/src/app/types.ts b/packages/core-app-api/src/app/types.ts index 75b8fb2a34..3d9005b0c0 100644 --- a/packages/core-app-api/src/app/types.ts +++ b/packages/core-app-api/src/app/types.ts @@ -45,7 +45,7 @@ export type BootErrorPageProps = { */ export type SignInPageProps = { /** - * Set the IdentityApi on successful sign in. This should only be called once. + * Set the IdentityApi on successful sign-in. This should only be called once. */ onSignInSuccess(identityApi: IdentityApi): void; }; diff --git a/packages/core-app-api/src/lib/AuthConnector/DefaultAuthConnector.test.ts b/packages/core-app-api/src/lib/AuthConnector/DefaultAuthConnector.test.ts index 2b132e09cd..51da9cbfb5 100644 --- a/packages/core-app-api/src/lib/AuthConnector/DefaultAuthConnector.test.ts +++ b/packages/core-app-api/src/lib/AuthConnector/DefaultAuthConnector.test.ts @@ -21,6 +21,8 @@ import { UrlPatternDiscovery } from '../../apis'; import { setupRequestMockHandlers } from '@backstage/test-utils'; import { setupServer } from 'msw/node'; import { rest } from 'msw'; +import { ConfigReader } from '@backstage/config'; +import { ConfigApi } from '@backstage/core-plugin-api'; jest.mock('../loginPopup', () => { return { @@ -28,6 +30,10 @@ jest.mock('../loginPopup', () => { }; }); +const configApi: ConfigApi = new ConfigReader({ + enableExperimentalRedirectFlow: false, +}); + const defaultOptions = { discoveryApi: UrlPatternDiscovery.compile('http://my-host/api/{{pluginId}}'), environment: 'production', @@ -42,6 +48,7 @@ const defaultOptions = { scopes: new Set(res.scopes.split(' ')), expiresAt: new Date(Date.now() + expiresInSeconds * 1000), }), + configApi: configApi, }; describe('DefaultAuthConnector', () => { @@ -131,7 +138,7 @@ describe('DefaultAuthConnector', () => { expect(popupSpy).toHaveBeenCalledTimes(1); expect(popupSpy.mock.calls[0][0]).toMatchObject({ - url: 'http://my-host/api/auth/my-provider/start?scope=a%20b&origin=http%3A%2F%2Flocalhost&env=production', + url: 'http://my-host/api/auth/my-provider/start?scope=a%20b&origin=http%3A%2F%2Flocalhost&flow=popup&env=production', }); await expect(sessionPromise).resolves.toEqual({ @@ -179,7 +186,7 @@ describe('DefaultAuthConnector', () => { expect(popupSpy).toHaveBeenCalledTimes(1); expect(popupSpy.mock.calls[0][0]).toMatchObject({ - url: 'http://my-host/api/auth/my-provider/start?scope=-ab-&origin=http%3A%2F%2Flocalhost&env=production', + url: 'http://my-host/api/auth/my-provider/start?scope=-ab-&origin=http%3A%2F%2Flocalhost&flow=popup&env=production', }); }); }); diff --git a/packages/core-app-api/src/lib/AuthConnector/DefaultAuthConnector.ts b/packages/core-app-api/src/lib/AuthConnector/DefaultAuthConnector.ts index 988c9f17b1..f2c35b0ba3 100644 --- a/packages/core-app-api/src/lib/AuthConnector/DefaultAuthConnector.ts +++ b/packages/core-app-api/src/lib/AuthConnector/DefaultAuthConnector.ts @@ -13,16 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - import { - OAuthRequester, - OAuthRequestApi, AuthProviderInfo, + ConfigApi, DiscoveryApi, + OAuthRequestApi, + OAuthRequester, } from '@backstage/core-plugin-api'; import { showLoginPopup } from '../loginPopup'; import { AuthConnector, CreateSessionOptions } from './types'; +let warned = false; + type Options = { /** * DiscoveryApi instance used to locate the auth backend endpoint. @@ -49,6 +51,10 @@ type Options = { * Function used to transform an auth response into the session type. */ sessionTransform?(response: any): AuthSession | Promise; + /** + * ConfigApi instance used to configure authentication flow of pop-up or redirect. + */ + configApi?: ConfigApi; }; function defaultJoinScopes(scopes: Set) { @@ -69,9 +75,10 @@ export class DefaultAuthConnector private readonly joinScopesFunc: (scopes: Set) => string; private readonly authRequester: OAuthRequester; private readonly sessionTransform: (response: any) => Promise; - + private readonly enableExperimentalRedirectFlow: boolean; constructor(options: Options) { const { + configApi, discoveryApi, environment, provider, @@ -80,9 +87,26 @@ export class DefaultAuthConnector sessionTransform = id => id, } = options; + if (!warned && !configApi) { + // eslint-disable-next-line no-console + console.warn( + 'DEPRECATION WARNING: Authentication providers require a configApi instance to configure the authentication flow. Please provide one to the authentication provider constructor.', + ); + warned = true; + } + + this.enableExperimentalRedirectFlow = configApi + ? configApi.getOptionalBoolean('enableExperimentalRedirectFlow') ?? false + : false; + this.authRequester = oauthRequestApi.createAuthRequester({ provider, - onAuthRequest: scopes => this.showPopup(scopes), + onAuthRequest: async scopes => { + if (!this.enableExperimentalRedirectFlow) { + return this.showPopup(scopes); + } + return this.executeRedirect(scopes); + }, }); this.discoveryApi = discoveryApi; @@ -94,6 +118,9 @@ export class DefaultAuthConnector async createSession(options: CreateSessionOptions): Promise { if (options.instantPopup) { + if (this.enableExperimentalRedirectFlow) { + return this.executeRedirect(options.scopes); + } return this.showPopup(options.scopes); } return this.authRequester(options.scopes); @@ -155,6 +182,7 @@ export class DefaultAuthConnector const popupUrl = await this.buildUrl('/start', { scope, origin: window.location.origin, + flow: 'popup', }); const payload = await showLoginPopup({ @@ -168,6 +196,19 @@ export class DefaultAuthConnector return await this.sessionTransform(payload); } + private async executeRedirect(scopes: Set): Promise { + const scope = this.joinScopesFunc(scopes); + // redirect to auth api + window.location.href = await this.buildUrl('/start', { + scope, + origin: window.location.origin, + redirectUrl: window.location.href, + flow: 'redirect', + }); + // return a promise that never resolves + return new Promise(() => {}); + } + private async buildUrl( path: string, query?: { [key: string]: string | boolean | undefined }, diff --git a/packages/core-app-api/src/lib/AuthSessionManager/RefreshingAuthSessionManager.ts b/packages/core-app-api/src/lib/AuthSessionManager/RefreshingAuthSessionManager.ts index d31f5e29bf..67d83bb36a 100644 --- a/packages/core-app-api/src/lib/AuthSessionManager/RefreshingAuthSessionManager.ts +++ b/packages/core-app-api/src/lib/AuthSessionManager/RefreshingAuthSessionManager.ts @@ -93,7 +93,7 @@ export class RefreshingAuthSessionManager implements SessionManager { // // We skip this check if an instant login popup is requested, as we need to // stay in a synchronous call stack from the user interaction. The downside - // is that that the user will sometimes be requested to log in even if they + // is that the user will sometimes be requested to log in even if they // already had an existing session. if (!this.currentSession && !options.instantPopup) { try { diff --git a/packages/core-components/CHANGELOG.md b/packages/core-components/CHANGELOG.md index a7ca828bb3..b8e29342dc 100644 --- a/packages/core-components/CHANGELOG.md +++ b/packages/core-components/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/core-components +## 0.12.6-next.0 + +### Patch Changes + +- 7908d72e033: Introduce a new global config parameter, `auth.enableExperimentalRedirectFlow`. When enabled, auth will happen with an in-window redirect flow rather than through a popup window. +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- 7245e744ab1: Fixed the font color on `BackstageHeaderLabel` to respect the active page theme. +- Updated dependencies + - @backstage/core-plugin-api@1.5.0 + - @backstage/config@1.0.7 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + - @backstage/version-bridge@1.0.3 + ## 0.12.5 ### Patch Changes diff --git a/packages/core-components/package.json b/packages/core-components/package.json index 77e91aa751..e210219ef3 100644 --- a/packages/core-components/package.json +++ b/packages/core-components/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/core-components", "description": "Core components used by Backstage plugins and apps", - "version": "0.12.5", + "version": "0.12.6-next.0", "publishConfig": { "access": "public", "main": "dist/index.esm.js", @@ -40,7 +40,7 @@ "@material-table/core": "^3.1.0", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "@react-hookz/web": "^20.0.0", "@types/react-sparklines": "^1.7.0", "@types/react-text-truncate": "^0.14.0", diff --git a/packages/core-components/src/components/OAuthRequestDialog/OAuthRequestDialog.tsx b/packages/core-components/src/components/OAuthRequestDialog/OAuthRequestDialog.tsx index 02b1afe4a1..0159d8f503 100644 --- a/packages/core-components/src/components/OAuthRequestDialog/OAuthRequestDialog.tsx +++ b/packages/core-components/src/components/OAuthRequestDialog/OAuthRequestDialog.tsx @@ -24,7 +24,11 @@ import Button from '@material-ui/core/Button'; import React, { useMemo, useState } from 'react'; import useObservable from 'react-use/lib/useObservable'; import LoginRequestListItem from './LoginRequestListItem'; -import { useApi, oauthRequestApiRef } from '@backstage/core-plugin-api'; +import { + useApi, + configApiRef, + oauthRequestApiRef, +} from '@backstage/core-plugin-api'; import Typography from '@material-ui/core/Typography'; export type OAuthRequestDialogClassKey = @@ -58,6 +62,11 @@ export function OAuthRequestDialog(_props: {}) { const classes = useStyles(); const [busy, setBusy] = useState(false); const oauthRequestApi = useApi(oauthRequestApiRef); + const configApi = useApi(configApiRef); + + const authRedirect = + configApi.getOptionalBoolean('enableExperimentalRedirectFlow') ?? false; + const requests = useObservable( useMemo(() => oauthRequestApi.authRequest$(), [oauthRequestApi]), [], @@ -83,6 +92,11 @@ export function OAuthRequestDialog(_props: {}) { Login Required + {authRedirect ? ( + + This will trigger a http redirect to OAuth Login. + + ) : null} diff --git a/packages/core-components/src/layout/HeaderLabel/HeaderLabel.tsx b/packages/core-components/src/layout/HeaderLabel/HeaderLabel.tsx index e3b6299f85..0ea2e163a7 100644 --- a/packages/core-components/src/layout/HeaderLabel/HeaderLabel.tsx +++ b/packages/core-components/src/layout/HeaderLabel/HeaderLabel.tsx @@ -14,8 +14,9 @@ * limitations under the License. */ +import { BackstageTheme } from '@backstage/theme'; import Grid from '@material-ui/core/Grid'; -import { makeStyles } from '@material-ui/core/styles'; +import { alpha, makeStyles } from '@material-ui/core/styles'; import Typography from '@material-ui/core/Typography'; import React from 'react'; import { Link } from '../../components/Link'; @@ -23,13 +24,13 @@ import { Link } from '../../components/Link'; /** @public */ export type HeaderLabelClassKey = 'root' | 'label' | 'value'; -const useStyles = makeStyles( +const useStyles = makeStyles( theme => ({ root: { textAlign: 'left', }, label: { - color: theme.palette.common.white, + color: theme.page.fontColor, fontWeight: theme.typography.fontWeightBold, letterSpacing: 0, fontSize: theme.typography.fontSize, @@ -37,7 +38,7 @@ const useStyles = makeStyles( lineHeight: 1, }, value: { - color: 'rgba(255, 255, 255, 0.8)', + color: alpha(theme.page.fontColor, 0.8), fontSize: theme.typography.fontSize, lineHeight: 1, }, @@ -50,9 +51,16 @@ type HeaderLabelContentProps = { className: string; }; -const HeaderLabelContent = ({ value, className }: HeaderLabelContentProps) => ( - {value} -); +const HeaderLabelContent = ({ value, className }: HeaderLabelContentProps) => { + return ( + + {value} + + ); +}; type HeaderLabelProps = { label: string; diff --git a/packages/core-components/src/layout/SignInPage/commonProvider.tsx b/packages/core-components/src/layout/SignInPage/commonProvider.tsx index 8f426a3907..1827981e6f 100644 --- a/packages/core-components/src/layout/SignInPage/commonProvider.tsx +++ b/packages/core-components/src/layout/SignInPage/commonProvider.tsx @@ -29,17 +29,24 @@ import { GridItem } from './styles'; import { ForwardedError } from '@backstage/errors'; import { UserIdentity } from './UserIdentity'; -const Component: ProviderComponent = ({ config, onSignInSuccess }) => { +const Component: ProviderComponent = ({ + config, + onSignInStarted, + onSignInSuccess, + onSignInFailure, +}) => { const { apiRef, title, message } = config as SignInProviderConfig; const authApi = useApi(apiRef); const errorApi = useApi(errorApiRef); const handleLogin = async () => { try { + onSignInStarted(); const identityResponse = await authApi.getBackstageIdentity({ instantPopup: true, }); if (!identityResponse) { + onSignInFailure(); throw new Error( `The ${title} provider is not configured to support sign-in`, ); @@ -55,6 +62,7 @@ const Component: ProviderComponent = ({ config, onSignInSuccess }) => { }), ); } catch (error) { + onSignInFailure(); errorApi.post(new ForwardedError('Login failed', error)); } }; diff --git a/packages/core-components/src/layout/SignInPage/customProvider.tsx b/packages/core-components/src/layout/SignInPage/customProvider.tsx index 101c74d3cd..ad02715447 100644 --- a/packages/core-components/src/layout/SignInPage/customProvider.tsx +++ b/packages/core-components/src/layout/SignInPage/customProvider.tsx @@ -61,7 +61,7 @@ const asInputRef = (renderResult: UseFormRegisterReturn) => { }; }; -const Component: ProviderComponent = ({ onSignInSuccess }) => { +const Component: ProviderComponent = ({ onSignInStarted, onSignInSuccess }) => { const classes = useFormStyles(); const { register, handleSubmit, formState } = useForm({ mode: 'onChange', @@ -70,6 +70,7 @@ const Component: ProviderComponent = ({ onSignInSuccess }) => { const { errors } = formState; const handleResult = ({ userId, idToken }: Data) => { + onSignInStarted(); onSignInSuccess( UserIdentity.fromLegacy({ userId, diff --git a/packages/core-components/src/layout/SignInPage/guestProvider.tsx b/packages/core-components/src/layout/SignInPage/guestProvider.tsx index b2370a98d5..5393c1ea89 100644 --- a/packages/core-components/src/layout/SignInPage/guestProvider.tsx +++ b/packages/core-components/src/layout/SignInPage/guestProvider.tsx @@ -22,7 +22,7 @@ import { GridItem } from './styles'; import { ProviderComponent, ProviderLoader, SignInProvider } from './types'; import { GuestUserIdentity } from './GuestUserIdentity'; -const Component: ProviderComponent = ({ onSignInSuccess }) => ( +const Component: ProviderComponent = ({ onSignInStarted, onSignInSuccess }) => ( ( diff --git a/packages/core-components/src/layout/SignInPage/providers.tsx b/packages/core-components/src/layout/SignInPage/providers.tsx index 23d6c95b3c..e456a6948b 100644 --- a/packages/core-components/src/layout/SignInPage/providers.tsx +++ b/packages/core-components/src/layout/SignInPage/providers.tsx @@ -134,6 +134,7 @@ export const useSignInProviders = ( .loader(apiHolder, provider.config?.apiRef!) .then(result => { if (didCancel) { + localStorage.removeItem(PROVIDER_STORAGE_KEY); return; } if (result) { @@ -143,10 +144,10 @@ export const useSignInProviders = ( } }) .catch(error => { + localStorage.removeItem(PROVIDER_STORAGE_KEY); if (didCancel) { return; } - localStorage.removeItem(PROVIDER_STORAGE_KEY); errorApi.post(error); setLoading(false); }); @@ -172,16 +173,27 @@ export const useSignInProviders = ( const { Component } = provider.components; const handleSignInSuccess = (result: IdentityApi) => { - localStorage.setItem(PROVIDER_STORAGE_KEY, provider.id); - handleWrappedResult(result); }; + const handleSignInStarted = () => { + localStorage.setItem( + PROVIDER_STORAGE_KEY, + provider?.config?.id || provider.id, + ); + }; + + const handleSignInFailure = () => { + localStorage.removeItem(PROVIDER_STORAGE_KEY); + }; + return ( ); }), diff --git a/packages/core-components/src/layout/SignInPage/types.ts b/packages/core-components/src/layout/SignInPage/types.ts index 8a0430a27d..a7e1ca62c2 100644 --- a/packages/core-components/src/layout/SignInPage/types.ts +++ b/packages/core-components/src/layout/SignInPage/types.ts @@ -35,8 +35,21 @@ export type SignInProviderConfig = { /** @public */ export type IdentityProviders = ('guest' | 'custom' | SignInProviderConfig)[]; +/** + * Invoked when the sign-in process has failed. + */ +export type onSignInFailure = () => void; +/** + * Invoked when the sign-in process has started. + */ +export type onSignInStarted = () => void; + export type ProviderComponent = ComponentType< - SignInPageProps & { config: SignInProviderConfig } + SignInPageProps & { + config: SignInProviderConfig; + onSignInStarted(): void; + onSignInFailure(): void; + } >; export type ProviderLoader = ( diff --git a/packages/create-app/CHANGELOG.md b/packages/create-app/CHANGELOG.md index 2639ba9a59..3ce499d386 100644 --- a/packages/create-app/CHANGELOG.md +++ b/packages/create-app/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/create-app +## 0.4.39-next.0 + +### Patch Changes + +- Bumped create-app version. +- Updated dependencies + - @backstage/cli-common@0.1.12 + ## 0.4.38 ### Patch Changes diff --git a/packages/create-app/package.json b/packages/create-app/package.json index 9f797f5d8c..264ca6e017 100644 --- a/packages/create-app/package.json +++ b/packages/create-app/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/create-app", "description": "A CLI that helps you create your own Backstage app", - "version": "0.4.38", + "version": "0.4.39-next.0", "publishConfig": { "access": "public" }, diff --git a/packages/create-app/templates/default-app/packages/backend/src/plugins/scaffolder.ts b/packages/create-app/templates/default-app/packages/backend/src/plugins/scaffolder.ts index ef46f07870..fd424a3257 100644 --- a/packages/create-app/templates/default-app/packages/backend/src/plugins/scaffolder.ts +++ b/packages/create-app/templates/default-app/packages/backend/src/plugins/scaffolder.ts @@ -17,5 +17,6 @@ export default async function createPlugin( reader: env.reader, catalogClient, identity: env.identity, + permissionApi: env.permissions, }); } diff --git a/packages/dev-utils/CHANGELOG.md b/packages/dev-utils/CHANGELOG.md index 3c6fbaefd5..e151728a1b 100644 --- a/packages/dev-utils/CHANGELOG.md +++ b/packages/dev-utils/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/dev-utils +## 1.0.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/app-defaults@1.3.0-next.0 + - @backstage/core-app-api@1.7.0-next.0 + - @backstage/test-utils@1.3.0-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/integration-react@1.1.12-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + ## 1.0.13 ### Patch Changes diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json index d8559535d8..0568a44472 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.13", + "version": "1.0.14-next.0", "publishConfig": { "access": "public", "main": "dist/index.esm.js", diff --git a/packages/e2e-test/CHANGELOG.md b/packages/e2e-test/CHANGELOG.md index 2f7c5d0704..a3c5ffa88e 100644 --- a/packages/e2e-test/CHANGELOG.md +++ b/packages/e2e-test/CHANGELOG.md @@ -1,5 +1,14 @@ # e2e-test +## 0.2.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.4.39-next.0 + - @backstage/cli-common@0.1.12 + - @backstage/errors@1.1.5 + ## 0.2.1 ### Patch Changes diff --git a/packages/e2e-test/package.json b/packages/e2e-test/package.json index d2c11a7e15..833c5a1eca 100644 --- a/packages/e2e-test/package.json +++ b/packages/e2e-test/package.json @@ -1,7 +1,7 @@ { "name": "e2e-test", "description": "E2E test for verifying Backstage packages", - "version": "0.2.1", + "version": "0.2.2-next.0", "private": true, "backstage": { "role": "cli" diff --git a/packages/eslint-plugin/CHANGELOG.md b/packages/eslint-plugin/CHANGELOG.md index 49cf9b5df5..5a3b5dc5c4 100644 --- a/packages/eslint-plugin/CHANGELOG.md +++ b/packages/eslint-plugin/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/eslint-plugin +## 0.1.3-next.0 + +### Patch Changes + +- 911c25de59c: Add support for auto-fixing missing imports detected by the `no-undeclared-imports` rule. + ## 0.1.2 ### Patch Changes diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index feb03921fd..5a37dcc871 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/eslint-plugin", "description": "Backstage ESLint plugin", - "version": "0.1.2", + "version": "0.1.3-next.0", "publishConfig": { "access": "public" }, diff --git a/packages/integration-react/CHANGELOG.md b/packages/integration-react/CHANGELOG.md index 06568497df..02a8c9b7e4 100644 --- a/packages/integration-react/CHANGELOG.md +++ b/packages/integration-react/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/integration-react +## 1.1.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/theme@0.2.18 + ## 1.1.11 ### Patch Changes diff --git a/packages/integration-react/package.json b/packages/integration-react/package.json index 681542a313..39a8a9908a 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.11", + "version": "1.1.12-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,7 +30,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "react-use": "^17.2.4" }, "peerDependencies": { diff --git a/packages/repo-tools/CHANGELOG.md b/packages/repo-tools/CHANGELOG.md index c7577cb711..5893c3d87c 100644 --- a/packages/repo-tools/CHANGELOG.md +++ b/packages/repo-tools/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/repo-tools +## 0.1.4-next.0 + +### Patch Changes + +- 9129ca8cabb: Log API report instructions when api-report is missing. +- Updated dependencies + - @backstage/cli-common@0.1.12 + - @backstage/errors@1.1.5 + ## 0.1.3 ### Patch Changes diff --git a/packages/repo-tools/package.json b/packages/repo-tools/package.json index 35ea6165d3..fb1d0c4af8 100644 --- a/packages/repo-tools/package.json +++ b/packages/repo-tools/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/repo-tools", "description": "CLI for Backstage repo tooling ", - "version": "0.1.3", + "version": "0.1.4-next.0", "publishConfig": { "access": "public" }, diff --git a/packages/repo-tools/src/commands/api-reports/api-extractor.ts b/packages/repo-tools/src/commands/api-reports/api-extractor.ts index 1fe7602617..8194ede7a4 100644 --- a/packages/repo-tools/src/commands/api-reports/api-extractor.ts +++ b/packages/repo-tools/src/commands/api-reports/api-extractor.ts @@ -487,6 +487,9 @@ export async function runApiExtraction({ showVerboseMessages: false, showDiagnostics: false, messageCallback(message) { + if (message.text.includes('The API report file is missing')) { + shouldLogInstructions = true; + } if ( message.text.includes( 'You have changed the public API signature for this project.', @@ -506,7 +509,11 @@ export async function runApiExtraction({ // This release tag validation makes sure that the release tag of known entry points match expectations. // The root index entrypoint is only allowed @public exports, while /alpha and /beta only allow @alpha and @beta. - if (validateReleaseTags && !usesExperimentalTypeBuild) { + if ( + validateReleaseTags && + !usesExperimentalTypeBuild && + fs.pathExistsSync(extractorConfig.reportFilePath) + ) { if (['index', 'alpha', 'beta'].includes(name)) { const report = await fs.readFile( extractorConfig.reportFilePath, diff --git a/packages/techdocs-cli-embedded-app/CHANGELOG.md b/packages/techdocs-cli-embedded-app/CHANGELOG.md index 4b74967ddf..e1c03b9f9c 100644 --- a/packages/techdocs-cli-embedded-app/CHANGELOG.md +++ b/packages/techdocs-cli-embedded-app/CHANGELOG.md @@ -1,5 +1,24 @@ # techdocs-cli-embedded-app +## 0.2.81-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.10.0-next.0 + - @backstage/core-components@0.12.6-next.0 + - @backstage/app-defaults@1.3.0-next.0 + - @backstage/core-app-api@1.7.0-next.0 + - @backstage/test-utils@1.3.0-next.0 + - @backstage/plugin-techdocs@1.6.1-next.0 + - @backstage/cli@0.22.6-next.0 + - @backstage/plugin-techdocs-react@1.1.5-next.0 + - @backstage/integration-react@1.1.12-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/config@1.0.7 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + ## 0.2.80 ### Patch Changes diff --git a/packages/techdocs-cli-embedded-app/package.json b/packages/techdocs-cli-embedded-app/package.json index 4400ff082d..eab13938f4 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.80", + "version": "0.2.81-next.0", "private": true, "backstage": { "role": "frontend" diff --git a/packages/techdocs-cli/CHANGELOG.md b/packages/techdocs-cli/CHANGELOG.md index 3467fe86a5..9c1aaee26a 100644 --- a/packages/techdocs-cli/CHANGELOG.md +++ b/packages/techdocs-cli/CHANGELOG.md @@ -1,5 +1,17 @@ # @techdocs/cli +## 1.4.1-next.0 + +### Patch Changes + +- b348420a804: Adding global-agent to enable the ability to publish through a proxy +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/catalog-model@1.2.1 + - @backstage/cli-common@0.1.12 + - @backstage/plugin-techdocs-node@1.6.1-next.0 + ## 1.4.0 ### Minor Changes diff --git a/packages/techdocs-cli/README.md b/packages/techdocs-cli/README.md index ae296d2c26..85c0075946 100644 --- a/packages/techdocs-cli/README.md +++ b/packages/techdocs-cli/README.md @@ -40,6 +40,14 @@ yarn start yarn techdocs-cli:dev [...options] ``` +### Connecting behind a proxy + +```sh +# Prior to executing the techdocs-cli command +export GLOBAL_AGENT_HTTPS_PROXY=${HTTP_PROXY} +export GLOBAL_AGENT_NO_PROXY=${NO_PROXY} +``` + ### Using an example docs project For the purpose of local development, we have created an example documentation project. You are of course also free to create your own local test site - all it takes is a `docs/index.md` and an `mkdocs.yml` in a directory. diff --git a/packages/techdocs-cli/package.json b/packages/techdocs-cli/package.json index d18213d490..c8929f3d6a 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.4.0", + "version": "1.4.1-next.0", "publishConfig": { "access": "public" }, @@ -69,6 +69,7 @@ "commander": "^9.1.0", "dockerode": "^3.3.1", "fs-extra": "^10.0.1", + "global-agent": "^3.0.0", "http-proxy": "^1.18.1", "react-dev-utils": "^12.0.0-next.60", "serve-handler": "^6.1.3", diff --git a/packages/test-utils/CHANGELOG.md b/packages/test-utils/CHANGELOG.md index 2d0f57cf12..382cce8c09 100644 --- a/packages/test-utils/CHANGELOG.md +++ b/packages/test-utils/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/test-utils +## 1.3.0-next.0 + +### Minor Changes + +- 7908d72e033: Introduce a new global config parameter, `auth.enableExperimentalRedirectFlow`. When enabled, auth will happen with an in-window redirect flow rather than through a popup window. + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.7.0-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/config@1.0.7 + - @backstage/plugin-permission-react@0.4.11 + - @backstage/theme@0.2.18 + - @backstage/types@1.0.2 + - @backstage/plugin-permission-common@0.7.4 + ## 1.2.6 ### Patch Changes diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index 7bd93443e9..7670d43cbd 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/test-utils", "description": "Utilities to test Backstage plugins and apps.", - "version": "1.2.6", + "version": "1.3.0-next.0", "publishConfig": { "access": "public" }, diff --git a/packages/test-utils/src/testUtils/defaultApis.ts b/packages/test-utils/src/testUtils/defaultApis.ts index 1ff10bfe6f..2231d28cd0 100644 --- a/packages/test-utils/src/testUtils/defaultApis.ts +++ b/packages/test-utils/src/testUtils/defaultApis.ts @@ -89,6 +89,7 @@ export const defaultApis = [ }, factory: ({ discoveryApi, oauthRequestApi, configApi }) => GoogleAuth.create({ + configApi, discoveryApi, oauthRequestApi, environment: configApi.getOptionalString('auth.environment'), @@ -103,6 +104,7 @@ export const defaultApis = [ }, factory: ({ discoveryApi, oauthRequestApi, configApi }) => MicrosoftAuth.create({ + configApi, discoveryApi, oauthRequestApi, environment: configApi.getOptionalString('auth.environment'), @@ -117,6 +119,7 @@ export const defaultApis = [ }, factory: ({ discoveryApi, oauthRequestApi, configApi }) => GithubAuth.create({ + configApi, discoveryApi, oauthRequestApi, defaultScopes: ['read:user'], @@ -132,6 +135,7 @@ export const defaultApis = [ }, factory: ({ discoveryApi, oauthRequestApi, configApi }) => OktaAuth.create({ + configApi, discoveryApi, oauthRequestApi, environment: configApi.getOptionalString('auth.environment'), @@ -146,6 +150,7 @@ export const defaultApis = [ }, factory: ({ discoveryApi, oauthRequestApi, configApi }) => GitlabAuth.create({ + configApi, discoveryApi, oauthRequestApi, environment: configApi.getOptionalString('auth.environment'), @@ -160,6 +165,7 @@ export const defaultApis = [ }, factory: ({ discoveryApi, oauthRequestApi, configApi }) => OneLoginAuth.create({ + configApi, discoveryApi, oauthRequestApi, environment: configApi.getOptionalString('auth.environment'), @@ -174,6 +180,7 @@ export const defaultApis = [ }, factory: ({ discoveryApi, oauthRequestApi, configApi }) => BitbucketAuth.create({ + configApi, discoveryApi, oauthRequestApi, defaultScopes: ['team'], @@ -189,6 +196,7 @@ export const defaultApis = [ }, factory: ({ discoveryApi, oauthRequestApi, configApi }) => { return AtlassianAuth.create({ + configApi, discoveryApi, oauthRequestApi, environment: configApi.getOptionalString('auth.environment'), diff --git a/plugins/adr-backend/CHANGELOG.md b/plugins/adr-backend/CHANGELOG.md index c74dbd116a..53fb3b9f8d 100644 --- a/plugins/adr-backend/CHANGELOG.md +++ b/plugins/adr-backend/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-adr-backend +## 0.3.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/plugin-adr-common@0.2.7 + - @backstage/plugin-search-common@1.2.2 + ## 0.3.1 ### Patch Changes diff --git a/plugins/adr-backend/package.json b/plugins/adr-backend/package.json index e759373e6c..fb0c211284 100644 --- a/plugins/adr-backend/package.json +++ b/plugins/adr-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-adr-backend", - "version": "0.3.1", + "version": "0.3.2-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/adr-backend/src/index.ts b/plugins/adr-backend/src/index.ts index 5cc8f50b72..89c88ab3e7 100644 --- a/plugins/adr-backend/src/index.ts +++ b/plugins/adr-backend/src/index.ts @@ -15,7 +15,7 @@ */ /** - * ADR backend plugin + * Architecture Decision Records backend plugin. * * @packageDocumentation */ diff --git a/plugins/adr/CHANGELOG.md b/plugins/adr/CHANGELOG.md index b5942d88a4..f67ab9bc20 100644 --- a/plugins/adr/CHANGELOG.md +++ b/plugins/adr/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-adr +## 0.4.2-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-search-react@1.5.2-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/integration-react@1.1.12-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + - @backstage/plugin-adr-common@0.2.7 + - @backstage/plugin-search-common@1.2.2 + ## 0.4.1 ### Patch Changes diff --git a/plugins/adr/package.json b/plugins/adr/package.json index 7b636f4b1a..453ff62792 100644 --- a/plugins/adr/package.json +++ b/plugins/adr/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-adr", - "version": "0.4.1", + "version": "0.4.2-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,7 +33,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "react-markdown": "^8.0.0", "react-use": "^17.2.4", "remark-gfm": "^3.0.1" diff --git a/plugins/adr/src/index.ts b/plugins/adr/src/index.ts index f24b3ac531..f405621c4a 100644 --- a/plugins/adr/src/index.ts +++ b/plugins/adr/src/index.ts @@ -15,7 +15,7 @@ */ /** - * ADR frontend plugin + * Architecture Decision Records frontend plugin. * * @packageDocumentation */ diff --git a/plugins/airbrake-backend/CHANGELOG.md b/plugins/airbrake-backend/CHANGELOG.md index df44bfa651..29771be91c 100644 --- a/plugins/airbrake-backend/CHANGELOG.md +++ b/plugins/airbrake-backend/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-airbrake-backend +## 0.2.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + ## 0.2.16 ### Patch Changes diff --git a/plugins/airbrake-backend/package.json b/plugins/airbrake-backend/package.json index a292f05a14..fa3c29c022 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.16", + "version": "0.2.17-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/airbrake/CHANGELOG.md b/plugins/airbrake/CHANGELOG.md index 3efe9aabcd..e0efd2802b 100644 --- a/plugins/airbrake/CHANGELOG.md +++ b/plugins/airbrake/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-airbrake +## 0.3.17-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/test-utils@1.3.0-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/dev-utils@1.0.14-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + ## 0.3.16 ### Patch Changes diff --git a/plugins/airbrake/package.json b/plugins/airbrake/package.json index 6fb594951b..8249410795 100644 --- a/plugins/airbrake/package.json +++ b/plugins/airbrake/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-airbrake", - "version": "0.3.16", + "version": "0.3.17-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,7 +31,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "react-use": "^17.2.4" }, "peerDependencies": { diff --git a/plugins/airbrake/src/index.ts b/plugins/airbrake/src/index.ts index 717d544dc9..6f189e36b8 100644 --- a/plugins/airbrake/src/index.ts +++ b/plugins/airbrake/src/index.ts @@ -15,7 +15,7 @@ */ /** - * The Airbrake plugin provides connectivity between Backstage and Airbrake (https://airbrake.io/). + * The Airbrake plugin provides connectivity between Backstage and {@link https://airbrake.io/ | Airbrake}. * * @packageDocumentation */ diff --git a/plugins/allure/CHANGELOG.md b/plugins/allure/CHANGELOG.md index 2e4346de7d..27a470ce2c 100644 --- a/plugins/allure/CHANGELOG.md +++ b/plugins/allure/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-allure +## 0.1.33-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + ## 0.1.32 ### Patch Changes diff --git a/plugins/allure/package.json b/plugins/allure/package.json index d76a4d455b..986fc62f17 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.32", + "version": "0.1.33-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,7 +30,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "react-use": "^17.2.4" }, "peerDependencies": { diff --git a/plugins/analytics-module-ga/CHANGELOG.md b/plugins/analytics-module-ga/CHANGELOG.md index 6a896c5447..b05b09ab78 100644 --- a/plugins/analytics-module-ga/CHANGELOG.md +++ b/plugins/analytics-module-ga/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-analytics-module-ga +## 0.1.28-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/config@1.0.7 + - @backstage/theme@0.2.18 + ## 0.1.27 ### Patch Changes diff --git a/plugins/analytics-module-ga/README.md b/plugins/analytics-module-ga/README.md index d6e2642e2b..6fdfc91306 100644 --- a/plugins/analytics-module-ga/README.md +++ b/plugins/analytics-module-ga/README.md @@ -236,7 +236,7 @@ make and test changes is to do the following: Code for the isolated version of the plugin can be found inside the [/dev](./dev) directory. Changes to the plugin are hot-reloaded. -#### Recommended Dev Config +### Recommended Dev Config Paste this into your `app-config.local.yaml` while developing this plugin: diff --git a/plugins/analytics-module-ga/api-report.md b/plugins/analytics-module-ga/api-report.md index 557f472f71..f28c919f33 100644 --- a/plugins/analytics-module-ga/api-report.md +++ b/plugins/analytics-module-ga/api-report.md @@ -25,6 +25,4 @@ export class GoogleAnalytics implements AnalyticsApi { }, ): GoogleAnalytics; } - -// (No @packageDocumentation comment for this package) ``` diff --git a/plugins/analytics-module-ga/package.json b/plugins/analytics-module-ga/package.json index fa5ee74367..f77807b138 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.27", + "version": "0.1.28-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -28,7 +28,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "react-ga": "^3.3.0", "react-use": "^17.2.4" }, diff --git a/plugins/analytics-module-ga/src/index.ts b/plugins/analytics-module-ga/src/index.ts index fca8d91658..7b96c761fb 100644 --- a/plugins/analytics-module-ga/src/index.ts +++ b/plugins/analytics-module-ga/src/index.ts @@ -14,5 +14,11 @@ * limitations under the License. */ +/** + * Analytics Module plugin for Google Analytics. + * + * @packageDocumentation + */ + export { analyticsModuleGA } from './plugin'; export * from './apis/implementations/AnalyticsApi'; diff --git a/plugins/apache-airflow/CHANGELOG.md b/plugins/apache-airflow/CHANGELOG.md index 58348fbc56..6386aee20b 100644 --- a/plugins/apache-airflow/CHANGELOG.md +++ b/plugins/apache-airflow/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-apache-airflow +## 0.2.10-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-plugin-api@1.5.0 + ## 0.2.9 ### Patch Changes diff --git a/plugins/apache-airflow/package.json b/plugins/apache-airflow/package.json index 9856b4608a..ab732c8129 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.9", + "version": "0.2.10-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -26,7 +26,7 @@ "@backstage/core-plugin-api": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "cross-fetch": "^3.1.5", "qs": "^6.10.1", "react-use": "^17.2.4" diff --git a/plugins/api-docs/CHANGELOG.md b/plugins/api-docs/CHANGELOG.md index 8735ac91f8..2c850a0cb3 100644 --- a/plugins/api-docs/CHANGELOG.md +++ b/plugins/api-docs/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-api-docs +## 0.9.2-next.0 + +### Patch Changes + +- ca50c3bbea1: Corrected styling of nested objects in AsyncAPI to avoid inappropriate uppercase text transformation of nested objects. +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/plugin-catalog@1.10.0-next.0 + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + ## 0.9.1 ### Patch Changes diff --git a/plugins/api-docs/dev/asyncapi-example-api.yaml b/plugins/api-docs/dev/asyncapi-example-api.yaml index 725811d0cc..3895006979 100644 --- a/plugins/api-docs/dev/asyncapi-example-api.yaml +++ b/plugins/api-docs/dev/asyncapi-example-api.yaml @@ -133,6 +133,8 @@ spec: description: Light intensity measured in lumens. sentAt: $ref: "#/components/schemas/sentAt" + sentBy: + $ref: "#/components/schemas/sentBy" turnOnOffPayload: type: object properties: @@ -144,6 +146,8 @@ spec: description: Whether to turn on or off the light. sentAt: $ref: "#/components/schemas/sentAt" + sentBy: + $ref: "#/components/schemas/sentBy" dimLightPayload: type: object properties: @@ -154,10 +158,25 @@ spec: maximum: 100 sentAt: $ref: "#/components/schemas/sentAt" + sentBy: + $ref: "#/components/schemas/sentBy" sentAt: type: string format: date-time description: Date and time when the message was sent. + sentBy: + type: object + description: Description of the message sender. + properties: + name: + type: string + description: Name of the sender. + type: + type: string + description: Type of the sender. + enum: + - user + - machine securitySchemes: apiKey: diff --git a/plugins/api-docs/package.json b/plugins/api-docs/package.json index 3e1fa380c3..8e24c3ccea 100644 --- a/plugins/api-docs/package.json +++ b/plugins/api-docs/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-api-docs", "description": "A Backstage plugin that helps represent API entities in the frontend", - "version": "0.9.1", + "version": "0.9.2-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -41,7 +41,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "graphiql": "^1.8.8", "graphql": "^16.0.0", "graphql-ws": "^5.4.1", diff --git a/plugins/api-docs/src/components/AsyncApiDefinitionWidget/AsyncApiDefinition.tsx b/plugins/api-docs/src/components/AsyncApiDefinitionWidget/AsyncApiDefinition.tsx index fd8948828c..64452b7191 100644 --- a/plugins/api-docs/src/components/AsyncApiDefinitionWidget/AsyncApiDefinition.tsx +++ b/plugins/api-docs/src/components/AsyncApiDefinitionWidget/AsyncApiDefinition.tsx @@ -76,6 +76,8 @@ const useStyles = makeStyles((theme: BackstageTheme) => ({ ...theme.typography.button, borderRadius: theme.shape.borderRadius, color: theme.palette.primary.main, + // override whatever may be in the theme's typography to ensure consistency with asyncapi + textTransform: 'inherit', }, '& a': { color: theme.palette.link, diff --git a/plugins/apollo-explorer/CHANGELOG.md b/plugins/apollo-explorer/CHANGELOG.md index 8771768cc1..6a7ec3d0f2 100644 --- a/plugins/apollo-explorer/CHANGELOG.md +++ b/plugins/apollo-explorer/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-apollo-explorer +## 0.1.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/theme@0.2.18 + ## 0.1.9 ### Patch Changes diff --git a/plugins/apollo-explorer/api-report.md b/plugins/apollo-explorer/api-report.md index 1d3b41eac1..66cc473d0b 100644 --- a/plugins/apollo-explorer/api-report.md +++ b/plugins/apollo-explorer/api-report.md @@ -40,6 +40,4 @@ export const apolloExplorerPlugin: BackstagePlugin< {}, {} >; - -// (No @packageDocumentation comment for this package) ``` diff --git a/plugins/apollo-explorer/package.json b/plugins/apollo-explorer/package.json index 746f29d393..81ac0f02b9 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.9", + "version": "0.1.10-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -28,7 +28,6 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "^4.0.0-alpha.57", "react-use": "^17.2.4", "use-deep-compare-effect": "^1.8.1" }, diff --git a/plugins/apollo-explorer/src/index.ts b/plugins/apollo-explorer/src/index.ts index 6d07535fc3..565557e79f 100644 --- a/plugins/apollo-explorer/src/index.ts +++ b/plugins/apollo-explorer/src/index.ts @@ -13,4 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +/** + * Integrates Apollo Explorer graphs as a tool to browse GraphQL API endpoints inside Backstage. + * + * @packageDocumentation + */ export { apolloExplorerPlugin, ApolloExplorerPage } from './plugin'; diff --git a/plugins/app-backend/CHANGELOG.md b/plugins/app-backend/CHANGELOG.md index 6de2196bb6..85873f3ddb 100644 --- a/plugins/app-backend/CHANGELOG.md +++ b/plugins/app-backend/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-app-backend +## 0.3.44-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/config-loader@1.1.9 + - @backstage/types@1.0.2 + ## 0.3.43 ### Patch Changes diff --git a/plugins/app-backend/package.json b/plugins/app-backend/package.json index 2c24657363..79a9c70ca5 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.43", + "version": "0.3.44-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/auth-backend/CHANGELOG.md b/plugins/auth-backend/CHANGELOG.md index 69fe145e82..3a68d5a495 100644 --- a/plugins/auth-backend/CHANGELOG.md +++ b/plugins/auth-backend/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-auth-backend +## 0.18.2-next.0 + +### Patch Changes + +- d8f774c30df: Enforce the secret visibility of certificates and client secrets in the auth backend. Also, document all known options for each auth plugin. +- 7908d72e033: Introduce a new global config parameter, `auth.enableExperimentalRedirectFlow`. When enabled, auth will happen with an in-window redirect flow rather than through a popup window. +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/types@1.0.2 + - @backstage/plugin-auth-node@0.2.13-next.0 + ## 0.18.1 ### Patch Changes diff --git a/plugins/auth-backend/api-report.md b/plugins/auth-backend/api-report.md index 63aa060875..7515083c09 100644 --- a/plugins/auth-backend/api-report.md +++ b/plugins/auth-backend/api-report.md @@ -398,6 +398,8 @@ export type OAuthState = { env: string; origin?: string; scope?: string; + redirectUrl?: string; + flow?: string; }; // @public diff --git a/plugins/auth-backend/config.d.ts b/plugins/auth-backend/config.d.ts index 5aff9df90a..8d76ca8bf5 100644 --- a/plugins/auth-backend/config.d.ts +++ b/plugins/auth-backend/config.d.ts @@ -62,30 +62,72 @@ export interface Config { */ providers?: { google?: { - [authEnv: string]: { [key: string]: string }; + [authEnv: string]: { + clientId: string; + /** + * @visibility secret + */ + clientSecret: string; + callbackUrl?: string; + }; }; github?: { - [authEnv: string]: { [key: string]: string }; + [authEnv: string]: { + clientId: string; + /** + * @visibility secret + */ + clientSecret: string; + callbackUrl?: string; + enterpriseInstanceUrl?: string; + }; }; gitlab?: { - [authEnv: string]: { [key: string]: string }; + [authEnv: string]: { + clientId: string; + /** + * @visibility secret + */ + clientSecret: string; + audience?: string; + callbackUrl?: string; + }; }; saml?: { entryPoint: string; logoutUrl?: string; issuer: string; + /** + * @visibility secret + */ cert: string; audience?: string; + /** + * @visibility secret + */ privateKey?: string; authnContext?: string[]; identifierFormat?: string; + /** + * @visibility secret + */ decryptionPvk?: string; signatureAlgorithm?: 'sha256' | 'sha512'; digestAlgorithm?: string; acceptedClockSkewMs?: number; }; okta?: { - [authEnv: string]: { [key: string]: string }; + [authEnv: string]: { + clientId: string; + /** + * @visibility secret + */ + clientSecret: string; + audience: string; + authServerId?: string; + idp?: string; + callbackUrl?: string; + }; }; oauth2?: { [authEnv: string]: { @@ -101,19 +143,56 @@ export interface Config { }; }; oidc?: { - [authEnv: string]: { [key: string]: string }; + [authEnv: string]: { + clientId: string; + /** + * @visibility secret + */ + clientSecret: string; + callbackUrl?: string; + metadataUrl: string; + scope?: string; + prompt?: string; + }; }; auth0?: { - [authEnv: string]: { [key: string]: string }; + [authEnv: string]: { + clientId: string; + /** + * @visibility secret + */ + clientSecret: string; + domain: string; + callbackUrl?: string; + audience?: string; + connection?: string; + connectionScope?: string; + }; }; microsoft?: { - [authEnv: string]: { [key: string]: string }; + [authEnv: string]: { + clientId: string; + /** + * @visibility secret + */ + clientSecret: string; + tenantId: string; + callbackUrl?: string; + }; }; onelogin?: { - [authEnv: string]: { [key: string]: string }; + [authEnv: string]: { + clientId: string; + /** + * @visibility secret + */ + clientSecret: string; + issuer: string; + callbackUrl?: string; + }; }; awsalb?: { - issuer?: string; + iss?: string; region: string; }; cfaccess?: { diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json index 3c0fe10a5b..83a9a55906 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.18.1", + "version": "0.18.2-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/auth-backend/src/lib/oauth/OAuthAdapter.test.ts b/plugins/auth-backend/src/lib/oauth/OAuthAdapter.test.ts index e0d4f0e051..1b6653d97e 100644 --- a/plugins/auth-backend/src/lib/oauth/OAuthAdapter.test.ts +++ b/plugins/auth-backend/src/lib/oauth/OAuthAdapter.test.ts @@ -83,56 +83,10 @@ describe('OAuthAdapter', () => { callbackUrl: 'http://domain.org/auth/test-provider/handler/frame', }; - it('sets the correct headers in start', async () => { - const oauthProvider = new OAuthAdapter( - providerInstance, - oAuthProviderOptions, - ); - const mockRequest = { - query: { - scope: 'user', - env: 'development', - }, - } as unknown as express.Request; + const defaultState = { nonce: 'nonce', env: 'development' }; - const mockResponse = { - cookie: jest.fn().mockReturnThis(), - end: jest.fn().mockReturnThis(), - setHeader: jest.fn().mockReturnThis(), - statusCode: jest.fn().mockReturnThis(), - } as unknown as express.Response; - - await oauthProvider.start(mockRequest, mockResponse); - // nonce cookie checks - expect(mockResponse.cookie).toHaveBeenCalledTimes(1); - expect(mockResponse.cookie).toHaveBeenCalledWith( - `${oAuthProviderOptions.providerId}-nonce`, - expect.any(String), - expect.objectContaining({ - httpOnly: true, - path: '/auth/test-provider/handler', - maxAge: TEN_MINUTES_MS, - domain: 'domain.org', - sameSite: 'lax', - secure: false, - }), - ); - // redirect checks - expect(mockResponse.setHeader).toHaveBeenCalledTimes(2); - expect(mockResponse.setHeader).toHaveBeenCalledWith('Location', '/url'); - expect(mockResponse.setHeader).toHaveBeenCalledWith('Content-Length', '0'); - expect(mockResponse.statusCode).toEqual(301); - expect(mockResponse.end).toHaveBeenCalledTimes(1); - }); - - it('sets the refresh cookie if refresh is enabled', async () => { - const oauthProvider = new OAuthAdapter(providerInstance, { - ...oAuthProviderOptions, - isOriginAllowed: () => false, - }); - - const state = { nonce: 'nonce', env: 'development' }; - const mockRequest = { + const createEncodedQueryMockRequest = (state: any) => { + return { cookies: { 'test-provider-nonce': 'nonce', }, @@ -140,12 +94,69 @@ describe('OAuthAdapter', () => { state: encodeState(state), }, } as unknown as express.Request; + }; - const mockResponse = { - cookie: jest.fn().mockReturnThis(), - setHeader: jest.fn().mockReturnThis(), - end: jest.fn().mockReturnThis(), - } as unknown as express.Response; + const mockResponse = { + cookie: jest.fn().mockReturnThis(), + end: jest.fn().mockReturnThis(), + setHeader: jest.fn().mockReturnThis(), + statusCode: jest.fn().mockReturnThis(), + redirect: jest.fn().mockReturnThis(), + status: jest.fn().mockReturnThis(), + json: jest.fn().mockReturnThis(), + } as unknown as express.Response; + + const mockStartRequest = { + query: { + scope: 'user', + env: 'development', + }, + } as unknown as express.Request; + + const expectedStartAuthCookieData = { + httpOnly: true, + path: '/auth/test-provider/handler', + maxAge: TEN_MINUTES_MS, + domain: 'domain.org', + sameSite: 'lax', + secure: false, + }; + + it('sets the correct headers in start', async () => { + const oauthProvider = new OAuthAdapter( + providerInstance, + oAuthProviderOptions, + ); + + await oauthProvider.start(mockStartRequest, mockResponse); + // nonce cookie checks + expect(mockResponse.cookie).toHaveBeenCalledTimes(1); + expect(mockResponse.cookie).toHaveBeenCalledWith( + `${oAuthProviderOptions.providerId}-nonce`, + expect.any(String), + expect.objectContaining(expectedStartAuthCookieData), + ); + expect(mockResponse.setHeader).toHaveBeenCalledTimes(2); + expect(mockResponse.setHeader).toHaveBeenCalledWith('Location', '/url'); + expect(mockResponse.setHeader).toHaveBeenCalledWith('Content-Length', '0'); + expect(mockResponse.statusCode).toEqual(301); + expect(mockResponse.end).toHaveBeenCalledTimes(1); + expect(mockResponse.redirect).not.toHaveBeenCalled(); + }); + + const refreshCookieData = { + ...expectedStartAuthCookieData, + path: '/auth/test-provider', + maxAge: THOUSAND_DAYS_MS, + }; + + it('sets the refresh cookie if refresh is enabled', async () => { + const oauthProvider = new OAuthAdapter(providerInstance, { + ...oAuthProviderOptions, + isOriginAllowed: () => false, + }); + + const mockRequest = createEncodedQueryMockRequest(defaultState); await oauthProvider.frameHandler(mockRequest, mockResponse); expect(mockCookieConfigurer).toHaveBeenCalledTimes(1); @@ -153,15 +164,26 @@ describe('OAuthAdapter', () => { expect(mockResponse.cookie).toHaveBeenCalledWith( expect.stringContaining('test-provider-refresh-token'), expect.stringContaining('token'), - expect.objectContaining({ - httpOnly: true, - path: '/auth/test-provider', - maxAge: THOUSAND_DAYS_MS, - domain: 'domain.org', - secure: false, - sameSite: 'lax', - }), + expect.objectContaining(refreshCookieData), ); + expect(mockResponse.redirect).not.toHaveBeenCalled(); + }); + + it('sets the refresh cookie if refresh is enabled with redirect', async () => { + const oauthProvider = new OAuthAdapter(providerInstance, { + ...oAuthProviderOptions, + isOriginAllowed: () => false, + }); + + const state = { + ...defaultState, + redirectUrl: 'http://localhost:3000', + flow: 'redirect', + }; + const mockRequest = createEncodedQueryMockRequest(state); + + await oauthProvider.frameHandler(mockRequest, mockResponse); + expect(mockResponse.redirect).toHaveBeenCalledTimes(1); }); it('persists scope through cookie if enabled', async () => { @@ -179,32 +201,15 @@ describe('OAuthAdapter', () => { }); // First we test the /start request, making sure state is set - const mockStartReq = { - query: { - scope: 'user', - env: 'development', - }, - } as unknown as express.Request; - const mockStartRes = { - cookie: jest.fn().mockReturnThis(), - end: jest.fn().mockReturnThis(), - setHeader: jest.fn().mockReturnThis(), - statusCode: jest.fn().mockReturnThis(), - } as unknown as express.Response; - - await oauthProvider.start(mockStartReq, mockStartRes); + await oauthProvider.start(mockStartRequest, mockResponse); expect(handlers.start).toHaveBeenCalledTimes(1); expect(handlers.start).toHaveBeenCalledWith({ - query: { - scope: 'user', - env: 'development', - }, + ...mockStartRequest, scope: 'user', state: { nonce: expect.any(String), env: 'development', - origin: undefined, scope: 'user', }, }); @@ -223,6 +228,7 @@ describe('OAuthAdapter', () => { cookie: jest.fn().mockReturnThis(), setHeader: jest.fn().mockReturnThis(), end: jest.fn().mockReturnThis(), + redirect: jest.fn().mockReturnThis(), } as unknown as express.Response; await oauthProvider.frameHandler(mockHandleReq, mockHandleRes); @@ -230,17 +236,11 @@ describe('OAuthAdapter', () => { expect(mockHandleRes.cookie).toHaveBeenCalledWith( 'test-provider-granted-scope', 'user', - expect.objectContaining({ - httpOnly: true, - path: '/auth/test-provider', - maxAge: THOUSAND_DAYS_MS, - domain: 'domain.org', - secure: false, - sameSite: 'lax', - }), + expect.objectContaining(refreshCookieData), ); + expect(mockResponse.redirect).not.toHaveBeenCalled(); - // Them make sure scopes are forwarded correctly during refresh + // Then make sure scopes are forwarded correctly during refresh const mockRefreshReq = { query: { scope: 'ignore-me' }, cookies: { @@ -252,6 +252,7 @@ describe('OAuthAdapter', () => { const mockRefreshRes = { status: jest.fn().mockReturnThis(), json: jest.fn().mockReturnThis(), + redirect: jest.fn().mockReturnThis(), } as unknown as express.Response; await oauthProvider.refresh(mockRefreshReq, mockRefreshRes); expect(handlers.refresh).toHaveBeenCalledTimes(1); @@ -261,8 +262,18 @@ describe('OAuthAdapter', () => { refreshToken: 'refresh-token', }), ); + expect(mockRefreshRes.redirect).not.toHaveBeenCalled(); }); + const mockRequestWithHeader = { + header: () => 'XMLHttpRequest', + cookies: { + 'test-provider-refresh-token': 'token', + }, + query: {}, + get: jest.fn(), + } as unknown as express.Request; + it('removes refresh cookie and calls logout handler when logging out', async () => { const logoutSpy = jest.spyOn(providerInstance, 'logout'); const oauthProvider = new OAuthAdapter(providerInstance, { @@ -270,22 +281,8 @@ describe('OAuthAdapter', () => { isOriginAllowed: () => false, }); - const mockRequest = { - cookies: { - 'test-provider-refresh-token': 'token', - }, - header: () => 'XMLHttpRequest', - get: jest.fn(), - } as unknown as express.Request; - - const mockResponse = { - cookie: jest.fn().mockReturnThis(), - end: jest.fn().mockReturnThis(), - status: jest.fn().mockReturnThis(), - } as unknown as express.Response; - - await oauthProvider.logout(mockRequest, mockResponse); - expect(mockRequest.get).toHaveBeenCalledTimes(1); + await oauthProvider.logout(mockRequestWithHeader, mockResponse); + expect(mockRequestWithHeader.get).toHaveBeenCalledTimes(1); expect(logoutSpy).toHaveBeenCalledTimes(1); expect(mockResponse.cookie).toHaveBeenCalledTimes(1); expect(mockResponse.cookie).toHaveBeenCalledWith( @@ -294,6 +291,7 @@ describe('OAuthAdapter', () => { expect.objectContaining({ path: '/auth/test-provider' }), ); expect(mockResponse.end).toHaveBeenCalledTimes(1); + expect(mockResponse.redirect).not.toHaveBeenCalled(); }); it('gets new access-token when refreshing', async () => { @@ -302,20 +300,7 @@ describe('OAuthAdapter', () => { isOriginAllowed: () => false, }); - const mockRequest = { - header: () => 'XMLHttpRequest', - cookies: { - 'test-provider-refresh-token': 'token', - }, - query: {}, - } as unknown as express.Request; - - const mockResponse = { - json: jest.fn().mockReturnThis(), - status: jest.fn().mockReturnThis(), - } as unknown as express.Response; - - await oauthProvider.refresh(mockRequest, mockResponse); + await oauthProvider.refresh(mockRequestWithHeader, mockResponse); expect(mockResponse.json).toHaveBeenCalledTimes(1); expect(mockResponse.json).toHaveBeenCalledWith({ ...mockResponseData, @@ -328,6 +313,7 @@ describe('OAuthAdapter', () => { }, }, }); + expect(mockResponse.redirect).not.toHaveBeenCalled(); }); it('sets new access-token when old cookie exists', async () => { @@ -337,20 +323,12 @@ describe('OAuthAdapter', () => { }); const mockRequest = { - header: () => 'XMLHttpRequest', + ...mockRequestWithHeader, cookies: { 'test-provider-refresh-token': 'old-token', }, - query: {}, - get: jest.fn(), } as unknown as express.Request; - const mockResponse = { - json: jest.fn().mockReturnThis(), - status: jest.fn().mockReturnThis(), - cookie: jest.fn().mockReturnThis(), - } as unknown as express.Response; - await oauthProvider.refresh(mockRequest, mockResponse); expect(mockRequest.get).toHaveBeenCalledTimes(1); expect(mockCookieConfigurer).toHaveBeenCalledTimes(1); @@ -358,15 +336,9 @@ describe('OAuthAdapter', () => { expect(mockResponse.cookie).toHaveBeenCalledWith( 'test-provider-refresh-token', 'token', - expect.objectContaining({ - httpOnly: true, - path: '/auth/test-provider', - maxAge: THOUSAND_DAYS_MS, - domain: 'domain.org', - secure: false, - sameSite: 'lax', - }), + expect.objectContaining(refreshCookieData), ); + expect(mockResponse.redirect).not.toHaveBeenCalled(); }); it('sets the correct nonce cookie configuration', async () => { @@ -380,162 +352,89 @@ describe('OAuthAdapter', () => { ...oAuthProviderOptions, }); - const mockRequest = { - query: { - scope: 'user', - env: 'development', - origin: 'http://domain.org', - }, - } as unknown as express.Request; - - const mockResponse = { - cookie: jest.fn().mockReturnThis(), - end: jest.fn().mockReturnThis(), - setHeader: jest.fn().mockReturnThis(), - statusCode: jest.fn().mockReturnThis(), - } as unknown as express.Response; - - await oauthProvider.start(mockRequest, mockResponse); + await oauthProvider.start(mockStartRequest, mockResponse); expect(mockCookieConfigurer).not.toHaveBeenCalled(); expect(mockResponse.cookie).toHaveBeenCalledTimes(1); expect(mockResponse.cookie).toHaveBeenCalledWith( `${oAuthProviderOptions.providerId}-nonce`, expect.any(String), - expect.objectContaining({ - httpOnly: true, - domain: 'domain.org', - maxAge: TEN_MINUTES_MS, - path: '/auth/test-provider/handler', - secure: false, - sameSite: 'lax', - }), + expect.objectContaining(expectedStartAuthCookieData), ); + expect(mockResponse.redirect).not.toHaveBeenCalled(); }); - it('sets the correct nonce cookie configuration using origin from request', async () => { - const config = { - baseUrl: 'http://domain.org/auth', - appUrl: 'http://domain.org', - isOriginAllowed: () => false, - }; + const config = { + baseUrl: 'http://domain.org/auth', + appUrl: 'http://domain.org', + isOriginAllowed: () => false, + }; + const mockStartRequestWithOrigin = { + query: { + scope: 'user', + env: 'development', + origin: 'http://other.domain', + }, + } as unknown as express.Request; + + it('sets the correct nonce cookie configuration using origin from request', async () => { const oauthProvider = OAuthAdapter.fromConfig(config, providerInstance, { ...oAuthProviderOptions, callbackUrl: 'https://domain.org/auth/test-provider/handler/frame', }); - const mockRequest = { - query: { - scope: 'user', - env: 'development', - origin: 'http://other.domain', - }, - } as unknown as express.Request; - - const mockResponse = { - cookie: jest.fn().mockReturnThis(), - end: jest.fn().mockReturnThis(), - setHeader: jest.fn().mockReturnThis(), - statusCode: jest.fn().mockReturnThis(), - } as unknown as express.Response; - - await oauthProvider.start(mockRequest, mockResponse); + await oauthProvider.start(mockStartRequestWithOrigin, mockResponse); expect(mockCookieConfigurer).not.toHaveBeenCalled(); expect(mockResponse.cookie).toHaveBeenCalledTimes(1); expect(mockResponse.cookie).toHaveBeenCalledWith( `${oAuthProviderOptions.providerId}-nonce`, expect.any(String), expect.objectContaining({ - httpOnly: true, - domain: 'domain.org', - maxAge: TEN_MINUTES_MS, - path: '/auth/test-provider/handler', + ...expectedStartAuthCookieData, secure: true, sameSite: 'none', }), ); + expect(mockResponse.redirect).not.toHaveBeenCalled(); }); - it('sets the correct cookie configuration using an secure callbackUrl', async () => { - const config = { - baseUrl: 'https://domain.org/auth', - appUrl: 'http://domain.org', - isOriginAllowed: () => false, - }; + const secureCookieData = { + ...refreshCookieData, + secure: true, + sameSite: 'lax', + maxAge: THOUSAND_DAYS_MS, + }; + it('sets the correct cookie configuration using an secure callbackUrl', async () => { const oauthProvider = OAuthAdapter.fromConfig(config, providerInstance, { ...oAuthProviderOptions, callbackUrl: 'https://domain.org/auth/test-provider/handler/frame', }); - const state = { - nonce: 'nonce', - env: 'development', - }; - - const mockRequest = { - cookies: { - 'test-provider-nonce': 'nonce', - }, - query: { - state: encodeState(state), - }, - } as unknown as express.Request; - - const mockResponse = { - cookie: jest.fn().mockReturnThis(), - setHeader: jest.fn().mockReturnThis(), - end: jest.fn().mockReturnThis(), - } as unknown as express.Response; - + const mockRequest = createEncodedQueryMockRequest(defaultState); await oauthProvider.frameHandler(mockRequest, mockResponse); expect(mockCookieConfigurer).not.toHaveBeenCalled(); expect(mockResponse.cookie).toHaveBeenCalledTimes(1); expect(mockResponse.cookie).toHaveBeenCalledWith( expect.stringContaining('test-provider-refresh-token'), expect.stringContaining('token'), - expect.objectContaining({ - httpOnly: true, - domain: 'domain.org', - path: '/auth/test-provider', - secure: true, - sameSite: 'lax', - }), + expect.objectContaining(secureCookieData), ); + expect(mockResponse.redirect).not.toHaveBeenCalled(); }); - it('sets the correct cookie configuration when on different domains and secure', async () => { - const config = { - baseUrl: 'https://domain.org/auth', - appUrl: 'http://domain.org', - isOriginAllowed: () => false, - }; + const secureSameSiteNoneCookieData = { + ...secureCookieData, + sameSite: 'none', + }; + it('sets the correct cookie configuration when on different domains and secure', async () => { const oauthProvider = OAuthAdapter.fromConfig(config, providerInstance, { ...oAuthProviderOptions, callbackUrl: 'https://authdomain.org/auth/test-provider/handler/frame', }); - const state = { - nonce: 'nonce', - env: 'development', - }; - - const mockRequest = { - cookies: { - 'test-provider-nonce': 'nonce', - }, - query: { - state: encodeState(state), - }, - } as unknown as express.Request; - - const mockResponse = { - cookie: jest.fn().mockReturnThis(), - setHeader: jest.fn().mockReturnThis(), - end: jest.fn().mockReturnThis(), - } as unknown as express.Response; - + const mockRequest = createEncodedQueryMockRequest(defaultState); await oauthProvider.frameHandler(mockRequest, mockResponse); expect(mockCookieConfigurer).not.toHaveBeenCalled(); expect(mockResponse.cookie).toHaveBeenCalledTimes(1); @@ -543,106 +442,108 @@ describe('OAuthAdapter', () => { expect.stringContaining('test-provider-refresh-token'), expect.stringContaining('token'), expect.objectContaining({ - httpOnly: true, + ...secureSameSiteNoneCookieData, domain: 'authdomain.org', - path: '/auth/test-provider', - secure: true, - sameSite: 'none', }), ); + expect(mockResponse.redirect).not.toHaveBeenCalled(); }); + const configOriginAllowed = { + ...config, + isOriginAllowed: () => true, + }; + it('sets the correct cookie configuration using origin from state', async () => { - const config = { - baseUrl: 'https://domain.org/auth', - appUrl: 'http://domain.org', - isOriginAllowed: () => true, - }; + const oauthProvider = OAuthAdapter.fromConfig( + configOriginAllowed, + providerInstance, + { + ...oAuthProviderOptions, + callbackUrl: 'https://domain.org/auth/test-provider/handler/frame', + }, + ); - const oauthProvider = OAuthAdapter.fromConfig(config, providerInstance, { - ...oAuthProviderOptions, - callbackUrl: 'https://domain.org/auth/test-provider/handler/frame', - }); - - const state = { - nonce: 'nonce', - env: 'development', + const mockRequest = createEncodedQueryMockRequest({ + ...defaultState, origin: 'http://other.domain', - }; - - const mockRequest = { - cookies: { - 'test-provider-nonce': 'nonce', - }, - query: { - state: encodeState(state), - }, - } as unknown as express.Request; - - const mockResponse = { - cookie: jest.fn().mockReturnThis(), - setHeader: jest.fn().mockReturnThis(), - end: jest.fn().mockReturnThis(), - } as unknown as express.Response; - + }); await oauthProvider.frameHandler(mockRequest, mockResponse); expect(mockCookieConfigurer).not.toHaveBeenCalled(); expect(mockResponse.cookie).toHaveBeenCalledTimes(1); expect(mockResponse.cookie).toHaveBeenCalledWith( expect.stringContaining('test-provider-refresh-token'), expect.stringContaining('token'), - expect.objectContaining({ - httpOnly: true, - domain: 'domain.org', - path: '/auth/test-provider', - secure: true, - sameSite: 'none', - }), + expect.objectContaining(secureSameSiteNoneCookieData), ); + expect(mockResponse.redirect).not.toHaveBeenCalled(); }); - it('sets the correct cookie configuration using origin from header', async () => { - const config = { - baseUrl: 'https://domain.org/auth', - appUrl: 'http://domain.org', - isOriginAllowed: () => false, - }; + const mockRequestWithGetMockReturn = { + header: () => 'XMLHttpRequest', + cookies: { + 'test-provider-refresh-token': 'old-token', + }, + query: {}, + get: jest.fn().mockReturnValue('http://other.domain'), + } as unknown as express.Request; + it('sets the correct cookie configuration using origin from header', async () => { const oauthProvider = OAuthAdapter.fromConfig(config, providerInstance, { ...oAuthProviderOptions, callbackUrl: 'https://domain.org/auth/test-provider/handler/frame', }); - const mockRequest = { - header: () => 'XMLHttpRequest', - cookies: { - 'test-provider-refresh-token': 'old-token', - }, - query: {}, - get: jest.fn().mockReturnValue('http://other.domain'), - } as unknown as express.Request; - - const mockResponse = { - json: jest.fn().mockReturnThis(), - status: jest.fn().mockReturnThis(), - cookie: jest.fn().mockReturnThis(), - } as unknown as express.Response; - - await oauthProvider.refresh(mockRequest, mockResponse); - expect(mockRequest.get).toHaveBeenCalledTimes(1); + await oauthProvider.refresh(mockRequestWithGetMockReturn, mockResponse); + expect(mockRequestWithGetMockReturn.get).toHaveBeenCalledTimes(1); expect(mockCookieConfigurer).not.toHaveBeenCalled(); expect(mockResponse.cookie).toHaveBeenCalledTimes(1); expect(mockResponse.cookie).toHaveBeenCalledWith( 'test-provider-refresh-token', 'token', - expect.objectContaining({ - httpOnly: true, - path: '/auth/test-provider', - maxAge: THOUSAND_DAYS_MS, - domain: 'domain.org', - secure: true, - sameSite: 'none', - }), + expect.objectContaining(secureSameSiteNoneCookieData), ); + expect(mockResponse.redirect).not.toHaveBeenCalled(); + }); + + it('executed a response redirect when flow query string is set to "redirect"', async () => { + const handlers = { + start: jest.fn(async (_req: { state: OAuthState }) => ({ + url: '/url', + status: 301, + })), + handler: jest.fn(async () => ({ response: mockResponseData })), + refresh: jest.fn(async () => ({ response: mockResponseData })), + }; + const configWithNoPopupEnabled = { + ...configOriginAllowed, + }; + const oauthProvider = OAuthAdapter.fromConfig( + configWithNoPopupEnabled, + handlers, + { + ...oAuthProviderOptions, + callbackUrl: 'https://domain.org/auth/test-provider/handler/frame', + }, + ); + + const state = { + ...defaultState, + origin: 'http://other.domain', + redirectUrl: 'http://domain.org', + flow: 'redirect', + }; + + const mockRequest = { + ...createEncodedQueryMockRequest(state), + get: jest.fn().mockReturnValue('http://other.domain'), + } as unknown as express.Request; + + await oauthProvider.frameHandler(mockRequest, mockResponse); + expect(mockRequest.get).not.toHaveBeenCalled(); + expect(mockCookieConfigurer).not.toHaveBeenCalled(); + expect(mockResponse.cookie).not.toHaveBeenCalled(); + expect(mockResponse.redirect).toHaveBeenCalledTimes(1); + expect(mockResponse.redirect).toHaveBeenCalledWith('http://domain.org'); }); }); diff --git a/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts b/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts index 85104e9608..5f51b2d301 100644 --- a/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts +++ b/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts @@ -33,7 +33,11 @@ import { NotAllowedError, } from '@backstage/errors'; import { defaultCookieConfigurer, readState, verifyNonce } from './helpers'; -import { postMessageResponse, ensuresXRequestedWith } from '../flow'; +import { + postMessageResponse, + ensuresXRequestedWith, + WebMessageResponse, +} from '../flow'; import { OAuthHandlers, OAuthStartRequest, @@ -98,6 +102,8 @@ export class OAuthAdapter implements AuthProviderRouteHandlers { const scope = req.query.scope?.toString() ?? ''; const env = req.query.env?.toString(); const origin = req.query.origin?.toString(); + const redirectUrl = req.query.redirectUrl?.toString(); + const flow = req.query.flow?.toString(); if (!env) { throw new InputError('No env provided in request query parameters'); @@ -109,7 +115,7 @@ export class OAuthAdapter implements AuthProviderRouteHandlers { // set a nonce cookie before redirecting to oauth provider this.setNonceCookie(res, nonce, cookieConfig); - const state: OAuthState = { nonce, env, origin }; + const state: OAuthState = { nonce, env, origin, redirectUrl, flow }; // If scopes are persisted then we pass them through the state so that we // can set the cookie on successful auth @@ -169,11 +175,21 @@ export class OAuthAdapter implements AuthProviderRouteHandlers { const identity = await this.populateIdentity(response.backstageIdentity); - // post message back to popup if successful - return postMessageResponse(res, appOrigin, { + const responseObj: WebMessageResponse = { type: 'authorization_response', response: { ...response, backstageIdentity: identity }, - }); + }; + + if (state.flow === 'redirect') { + if (!state.redirectUrl) { + throw new InputError( + 'No redirectUrl provided in request query parameters', + ); + } + res.redirect(state.redirectUrl); + } + // post message back to popup if successful + return postMessageResponse(res, appOrigin, responseObj); } catch (error) { const { name, message } = isError(error) ? error diff --git a/plugins/auth-backend/src/lib/oauth/types.ts b/plugins/auth-backend/src/lib/oauth/types.ts index 3902c3f026..e960af2988 100644 --- a/plugins/auth-backend/src/lib/oauth/types.ts +++ b/plugins/auth-backend/src/lib/oauth/types.ts @@ -90,6 +90,8 @@ export type OAuthState = { env: string; origin?: string; scope?: string; + redirectUrl?: string; + flow?: string; }; /** @public */ diff --git a/plugins/auth-node/CHANGELOG.md b/plugins/auth-node/CHANGELOG.md index 6c629ad208..210658c09d 100644 --- a/plugins/auth-node/CHANGELOG.md +++ b/plugins/auth-node/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-node +## 0.2.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/errors@1.1.5 + ## 0.2.12 ### Patch Changes diff --git a/plugins/auth-node/package.json b/plugins/auth-node/package.json index 690f67b868..6e3a74c66d 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.12", + "version": "0.2.13-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/azure-devops-backend/CHANGELOG.md b/plugins/azure-devops-backend/CHANGELOG.md index a59697c5b0..6aae0be627 100644 --- a/plugins/azure-devops-backend/CHANGELOG.md +++ b/plugins/azure-devops-backend/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-azure-devops-backend +## 0.3.23-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/plugin-azure-devops-common@0.3.0 + ## 0.3.22 ### Patch Changes diff --git a/plugins/azure-devops-backend/package.json b/plugins/azure-devops-backend/package.json index 8b2e3caf57..dcafd05680 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.22", + "version": "0.3.23-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/azure-devops/CHANGELOG.md b/plugins/azure-devops/CHANGELOG.md index 9682fe8de8..de9bb877d4 100644 --- a/plugins/azure-devops/CHANGELOG.md +++ b/plugins/azure-devops/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-azure-devops +## 0.2.8-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + - @backstage/plugin-azure-devops-common@0.3.0 + ## 0.2.7 ### Patch Changes diff --git a/plugins/azure-devops/package.json b/plugins/azure-devops/package.json index 01e898978f..40104c5036 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.7", + "version": "0.2.8-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -37,7 +37,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "humanize-duration": "^3.27.0", "luxon": "^3.0.0", "react-use": "^17.2.4" diff --git a/plugins/azure-sites-backend/CHANGELOG.md b/plugins/azure-sites-backend/CHANGELOG.md index d09e308269..5fda3502c5 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.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/plugin-azure-sites-common@0.1.0 + ## 0.1.5 ### Patch Changes diff --git a/plugins/azure-sites-backend/package.json b/plugins/azure-sites-backend/package.json index 0289ed01bd..77b6b3091c 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.5", + "version": "0.1.6-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/azure-sites/CHANGELOG.md b/plugins/azure-sites/CHANGELOG.md index 99f3c57cda..9c4b55e67f 100644 --- a/plugins/azure-sites/CHANGELOG.md +++ b/plugins/azure-sites/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-azure-sites +## 0.1.6-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + - @backstage/plugin-azure-sites-common@0.1.0 + ## 0.1.5 ### Patch Changes diff --git a/plugins/azure-sites/package.json b/plugins/azure-sites/package.json index 418d4ff578..6c8acb0fda 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.5", + "version": "0.1.6-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -40,7 +40,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "luxon": "^3.0.0", "react-use": "^17.2.4" }, diff --git a/plugins/badges-backend/CHANGELOG.md b/plugins/badges-backend/CHANGELOG.md index 4d3242f09d..88fb467687 100644 --- a/plugins/badges-backend/CHANGELOG.md +++ b/plugins/badges-backend/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-badges-backend +## 0.1.38-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + ## 0.1.37 ### Patch Changes diff --git a/plugins/badges-backend/package.json b/plugins/badges-backend/package.json index 88dac005e0..15caf0ec10 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.37", + "version": "0.1.38-next.0", "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 6f3aaa3897..da109890b7 100644 --- a/plugins/badges/CHANGELOG.md +++ b/plugins/badges/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-badges +## 0.2.41-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + ## 0.2.40 ### Patch Changes diff --git a/plugins/badges/package.json b/plugins/badges/package.json index 337d36c6cf..51ed87a34a 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.40", + "version": "0.2.41-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -37,7 +37,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "react-use": "^17.2.4" }, "peerDependencies": { diff --git a/plugins/bazaar-backend/CHANGELOG.md b/plugins/bazaar-backend/CHANGELOG.md index 29aaf96358..da7151291a 100644 --- a/plugins/bazaar-backend/CHANGELOG.md +++ b/plugins/bazaar-backend/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-bazaar-backend +## 0.2.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/errors@1.1.5 + - @backstage/plugin-auth-node@0.2.13-next.0 + ## 0.2.6 ### Patch Changes diff --git a/plugins/bazaar-backend/package.json b/plugins/bazaar-backend/package.json index 97c61156d4..78ddc51153 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.6", + "version": "0.2.7-next.0", "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 ff9fe6e97e..139a8af90c 100644 --- a/plugins/bazaar/CHANGELOG.md +++ b/plugins/bazaar/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-bazaar +## 0.2.7-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/plugin-catalog@1.10.0-next.0 + - @backstage/core-components@0.12.6-next.0 + - @backstage/cli@0.22.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + ## 0.2.6 ### Patch Changes diff --git a/plugins/bazaar/package.json b/plugins/bazaar/package.json index e1cf6a81b7..ef455587da 100644 --- a/plugins/bazaar/package.json +++ b/plugins/bazaar/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-bazaar", - "version": "0.2.6", + "version": "0.2.7-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,7 +34,7 @@ "@date-io/luxon": "1.x", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "@material-ui/pickers": "^3.3.10", "@testing-library/jest-dom": "^5.10.1", "luxon": "^3.0.0", diff --git a/plugins/bitrise/CHANGELOG.md b/plugins/bitrise/CHANGELOG.md index cd4b948675..4a92237aaa 100644 --- a/plugins/bitrise/CHANGELOG.md +++ b/plugins/bitrise/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-bitrise +## 0.1.44-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + ## 0.1.43 ### Patch Changes diff --git a/plugins/bitrise/package.json b/plugins/bitrise/package.json index 17f7faf835..9cdbeda3cd 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.43", + "version": "0.1.44-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,7 +30,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "cross-fetch": "^3.1.5", "lodash": "^4.17.21", "luxon": "^3.0.0", diff --git a/plugins/catalog-backend-module-aws/CHANGELOG.md b/plugins/catalog-backend-module-aws/CHANGELOG.md index 7b556b2d53..1aab4dac82 100644 --- a/plugins/catalog-backend-module-aws/CHANGELOG.md +++ b/plugins/catalog-backend-module-aws/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-catalog-backend-module-aws +## 0.1.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/plugin-kubernetes-common@0.6.2-next.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/types@1.0.2 + - @backstage/plugin-catalog-common@1.0.12 + - @backstage/plugin-catalog-node@1.3.5-next.0 + ## 0.1.17 ### Patch Changes diff --git a/plugins/catalog-backend-module-aws/package.json b/plugins/catalog-backend-module-aws/package.json index c0e2463cfd..0380c59585 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.17", + "version": "0.1.18-next.0", "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 30ccea2776..3a7d09070f 100644 --- a/plugins/catalog-backend-module-azure/CHANGELOG.md +++ b/plugins/catalog-backend-module-azure/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-catalog-backend-module-azure +## 0.1.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/types@1.0.2 + - @backstage/plugin-catalog-node@1.3.5-next.0 + ## 0.1.14 ### Patch Changes diff --git a/plugins/catalog-backend-module-azure/package.json b/plugins/catalog-backend-module-azure/package.json index 4015eb07f2..4ed831fcfd 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.14", + "version": "0.1.15-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md index 90d939638c..4a289a393f 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md +++ b/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-catalog-backend-module-bitbucket-cloud +## 0.1.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/plugin-bitbucket-cloud-common@0.2.4 + - @backstage/plugin-catalog-common@1.0.12 + - @backstage/plugin-catalog-node@1.3.5-next.0 + - @backstage/plugin-events-node@0.2.5-next.0 + ## 0.1.10 ### Patch Changes diff --git a/plugins/catalog-backend-module-bitbucket-cloud/package.json b/plugins/catalog-backend-module-bitbucket-cloud/package.json index af3b21d2d0..6e9aed31be 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.10", + "version": "0.1.11-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md index 216b7f6a9a..12e3d2e7d8 100644 --- a/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md +++ b/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-catalog-backend-module-bitbucket-server +## 0.1.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/plugin-catalog-node@1.3.5-next.0 + ## 0.1.8 ### Patch Changes diff --git a/plugins/catalog-backend-module-bitbucket-server/package.json b/plugins/catalog-backend-module-bitbucket-server/package.json index 6cf06b432e..9b680a80ca 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.8", + "version": "0.1.9-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-bitbucket/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket/CHANGELOG.md index 936303e285..c10530f41a 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.11-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/types@1.0.2 + - @backstage/plugin-bitbucket-cloud-common@0.2.4 + - @backstage/plugin-catalog-node@1.3.5-next.0 + ## 0.2.10 ### Patch Changes diff --git a/plugins/catalog-backend-module-bitbucket/package.json b/plugins/catalog-backend-module-bitbucket/package.json index 48fad40034..92c0adda4a 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.10", + "version": "0.2.11-next.0", "deprecated": true, "main": "src/index.ts", "types": "src/index.ts", diff --git a/plugins/catalog-backend-module-gerrit/CHANGELOG.md b/plugins/catalog-backend-module-gerrit/CHANGELOG.md index 35913b542f..98f0959dfd 100644 --- a/plugins/catalog-backend-module-gerrit/CHANGELOG.md +++ b/plugins/catalog-backend-module-gerrit/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-catalog-backend-module-gerrit +## 0.1.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/plugin-catalog-node@1.3.5-next.0 + ## 0.1.11 ### Patch Changes diff --git a/plugins/catalog-backend-module-gerrit/package.json b/plugins/catalog-backend-module-gerrit/package.json index 244bcdf1ed..3d66f715cc 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.11", + "version": "0.1.12-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-github/CHANGELOG.md b/plugins/catalog-backend-module-github/CHANGELOG.md index 22d4e10583..44760980cb 100644 --- a/plugins/catalog-backend-module-github/CHANGELOG.md +++ b/plugins/catalog-backend-module-github/CHANGELOG.md @@ -1,5 +1,24 @@ # @backstage/plugin-catalog-backend-module-github +## 0.2.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.8.1-next.0 + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/types@1.0.2 + - @backstage/plugin-catalog-common@1.0.12 + - @backstage/plugin-catalog-node@1.3.5-next.0 + - @backstage/plugin-events-node@0.2.5-next.0 + ## 0.2.6 ### Patch Changes diff --git a/plugins/catalog-backend-module-github/package.json b/plugins/catalog-backend-module-github/package.json index 5c9f7f67e1..ba7233e70f 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.6", + "version": "0.2.7-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", 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 624ea5c3c9..0345d4ba3e 100644 --- a/plugins/catalog-backend-module-github/src/lib/github.test.ts +++ b/plugins/catalog-backend-module-github/src/lib/github.test.ts @@ -16,11 +16,10 @@ import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; import { GroupEntity, UserEntity } from '@backstage/catalog-model'; -import { graphql } from '@octokit/graphql'; +import { graphql as graphqlOctokit } from '@octokit/graphql'; import { graphql as graphqlMsw } from 'msw'; import { setupServer } from 'msw/node'; import { TeamTransformer, UserTransformer } from './defaultTransformers'; - import { getOrganizationTeams, getOrganizationUsers, @@ -35,11 +34,9 @@ import { } 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 graphql = graphqlOctokit.defaults({ request: { fetch } }); + const server = setupServer(); setupRequestMockHandlers(server); diff --git a/plugins/catalog-backend-module-gitlab/CHANGELOG.md b/plugins/catalog-backend-module-gitlab/CHANGELOG.md index 2bde8b2635..02a274469d 100644 --- a/plugins/catalog-backend-module-gitlab/CHANGELOG.md +++ b/plugins/catalog-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,34 @@ # @backstage/plugin-catalog-backend-module-gitlab +## 0.2.0-next.0 + +### Minor Changes + +- f64345108a0: **BREAKING**: The configuration of the `GitlabDiscoveryEntityProvider` has changed as follows: + + - The configuration key `branch` is now used to define the branch from which the catalog-info should be discovered. + - The old configuration key `branch` is now called `fallbackBranch`. This value specifies which branch should be used + if no default branch is defined on the project itself. + + To migrate to the new configuration value, rename `branch` to `fallbackBranch` + +### Patch Changes + +- 7b1b7bfdb7b: The gitlab org data integration now makes use of the GraphQL API to determine + the relationships between imported User and Group entities, effectively making + this integration usable without an administrator account's Personal Access + Token. +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/types@1.0.2 + - @backstage/plugin-catalog-node@1.3.5-next.0 + ## 0.1.14 ### Patch Changes diff --git a/plugins/catalog-backend-module-gitlab/package.json b/plugins/catalog-backend-module-gitlab/package.json index b6437cd46b..3bdef6958d 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.14", + "version": "0.2.0-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-gitlab/src/lib/client.test.ts b/plugins/catalog-backend-module-gitlab/src/lib/client.test.ts index 513a5b937f..122aae7f54 100644 --- a/plugins/catalog-backend-module-gitlab/src/lib/client.test.ts +++ b/plugins/catalog-backend-module-gitlab/src/lib/client.test.ts @@ -18,9 +18,10 @@ import { ConfigReader } from '@backstage/config'; import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; import { readGitLabIntegrationConfig } from '@backstage/integration'; import { getVoidLogger } from '@backstage/backend-common'; -import { rest } from 'msw'; -import { setupServer, SetupServerApi } from 'msw/node'; +import { graphql, rest } from 'msw'; +import { setupServer, SetupServer } from 'msw/node'; import { GitLabClient, paginated } from './client'; +import { GitLabGroup, GitLabUser } from './types'; const server = setupServer(); setupRequestMockHandlers(server); @@ -30,12 +31,13 @@ const MOCK_CONFIG = readGitLabIntegrationConfig( host: 'example.com', token: 'test-token', apiBaseUrl: 'https://example.com/api/v4', + baseUrl: 'https://example.com', }), ); const FAKE_PAGED_ENDPOINT = `/some-endpoint`; const FAKE_PAGED_URL = `${MOCK_CONFIG.apiBaseUrl}${FAKE_PAGED_ENDPOINT}`; -function setupFakeFourPageURL(srv: SetupServerApi, url: string) { +function setupFakeFourPageURL(srv: SetupServer, url: string) { srv.use( rest.get(url, (req, res, ctx) => { const page = req.url.searchParams.get('page'); @@ -55,7 +57,7 @@ function setupFakeFourPageURL(srv: SetupServerApi, url: string) { } function setupFakeGroupProjectsEndpoint( - srv: SetupServerApi, + srv: SetupServer, apiBaseUrl: string, groupID: string, ) { @@ -77,7 +79,7 @@ function setupFakeGroupProjectsEndpoint( } function setupFakeInstanceProjectsEndpoint( - srv: SetupServerApi, + srv: SetupServer, apiBaseUrl: string, ) { srv.use( @@ -103,7 +105,7 @@ function setupFakeInstanceProjectsEndpoint( ); } -function setupFakeHasFileEndpoint(srv: SetupServerApi, apiBaseUrl: string) { +function setupFakeHasFileEndpoint(srv: SetupServer, apiBaseUrl: string) { srv.use( rest.head( `${apiBaseUrl}/projects/group%2Frepo/repository/files/catalog-info.yaml`, @@ -259,6 +261,228 @@ describe('GitLabClient', () => { expect(allProjects).toHaveLength(2); }); }); + + it('listUsers gets all users in the instance', async () => { + server.use( + rest.get(`${MOCK_CONFIG.apiBaseUrl}/users`, (_, res, ctx) => + res( + ctx.set('x-next-page', ''), + ctx.json([ + { + id: 1, + username: 'test1', + name: 'Test Testit', + state: 'active', + avatar_url: 'https://secure.gravatar.com/', + web_url: 'https://gitlab.example/test1', + created_at: '2023-01-19T07:27:03.333Z', + bio: '', + location: null, + public_email: null, + skype: '', + linkedin: '', + twitter: '', + website_url: '', + organization: null, + job_title: '', + pronouns: null, + bot: false, + work_information: null, + followers: 0, + following: 0, + is_followed: false, + local_time: null, + last_sign_in_at: '2023-01-19T07:27:49.601Z', + confirmed_at: '2023-01-19T07:27:02.905Z', + last_activity_on: '2023-01-19', + email: 'test@example.com', + theme_id: 1, + color_scheme_id: 1, + projects_limit: 100000, + current_sign_in_at: '2023-01-19T09:09:10.676Z', + identities: [], + can_create_group: true, + can_create_project: true, + two_factor_enabled: false, + external: false, + private_profile: false, + commit_email: 'test@example.com', + is_admin: false, + note: '', + }, + ]), + ), + ), + ); + const client = new GitLabClient({ + config: MOCK_CONFIG, + logger: getVoidLogger(), + }); + + const allUsers: GitLabUser[] = []; + for await (const user of paginated( + options => client.listUsers(options), + {}, + )) { + allUsers.push(user); + } + + expect(allUsers).toMatchObject([ + { + id: 1, + username: 'test1', + email: 'test@example.com', + name: 'Test Testit', + state: 'active', + web_url: 'https://gitlab.example/test1', + avatar_url: 'https://secure.gravatar.com/', + }, + ]); + }); + + it('listGroups gets all groups in the instance', async () => { + server.use( + rest.get(`${MOCK_CONFIG.apiBaseUrl}/groups`, (_, res, ctx) => + res( + ctx.set('x-next-page', ''), + ctx.json([ + { + id: 1, + web_url: 'https://gitlab.example/groups/group1', + name: 'group1', + path: 'group1', + description: '', + visibility: 'internal', + share_with_group_lock: false, + require_two_factor_authentication: false, + two_factor_grace_period: 48, + project_creation_level: 'developer', + auto_devops_enabled: null, + subgroup_creation_level: 'owner', + emails_disabled: null, + mentions_disabled: null, + lfs_enabled: true, + default_branch_protection: 2, + avatar_url: null, + request_access_enabled: false, + full_name: '8020', + full_path: '8020', + created_at: '2017-06-19T06:42:34.160Z', + parent_id: null, + }, + ]), + ), + ), + ); + const client = new GitLabClient({ + config: MOCK_CONFIG, + logger: getVoidLogger(), + }); + + const allGroups: GitLabGroup[] = []; + for await (const group of paginated( + options => client.listGroups(options), + {}, + )) { + allGroups.push(group); + } + + expect(allGroups).toMatchObject([ + { + id: 1, + name: 'group1', + full_path: '8020', + description: '', + parent_id: null, + }, + ]); + }); + + describe('getGroupMembers', () => { + it('gets member IDs', async () => { + server.use( + graphql + .link(`${MOCK_CONFIG.baseUrl}/api/graphql`) + .operation((_, res, ctx) => + res( + ctx.data({ + group: { + groupMembers: { + nodes: [{ user: { id: 'gid://gitlab/User/1' } }], + pageInfo: { + endCursor: 'end', + hasNextPage: false, + }, + }, + }, + }), + ), + ), + ); + const client = new GitLabClient({ + config: MOCK_CONFIG, + logger: getVoidLogger(), + }); + + const members = await client.getGroupMembers('group1'); + + expect(members).toEqual([1]); + }); + + it('rejects when GraphQL returns errors', async () => { + server.use( + graphql + .link(`${MOCK_CONFIG.baseUrl}/api/graphql`) + .operation((_, res, ctx) => + res( + ctx.errors([ + { message: 'Unexpected end of document', locations: [] }, + ]), + ), + ), + ); + const client = new GitLabClient({ + config: MOCK_CONFIG, + logger: getVoidLogger(), + }); + + await expect(() => client.getGroupMembers('group1')).rejects.toThrow( + 'GraphQL errors: [{"message":"Unexpected end of document","locations":[]}]', + ); + }); + + it('traverses multi-page results', async () => { + server.use( + graphql + .link(`${MOCK_CONFIG.baseUrl}/api/graphql`) + .operation((req, res, ctx) => + res( + ctx.data({ + group: { + groupMembers: { + nodes: req.variables.endCursor + ? [{ user: { id: 'gid://gitlab/User/2' } }] + : [{ user: { id: 'gid://gitlab/User/1' } }], + pageInfo: { + endCursor: req.variables.endCursor ? 'end' : 'next', + hasNextPage: !req.variables.endCursor, + }, + }, + }, + }), + ), + ), + ); + const client = new GitLabClient({ + config: MOCK_CONFIG, + logger: getVoidLogger(), + }); + + const members = await client.getGroupMembers('group1'); + + expect(members).toEqual([1, 2]); + }); + }); }); describe('paginated', () => { diff --git a/plugins/catalog-backend-module-gitlab/src/lib/client.ts b/plugins/catalog-backend-module-gitlab/src/lib/client.ts index bad0eb2a86..8f8c67895c 100644 --- a/plugins/catalog-backend-module-gitlab/src/lib/client.ts +++ b/plugins/catalog-backend-module-gitlab/src/lib/client.ts @@ -20,7 +20,7 @@ import { GitLabIntegrationConfig, } from '@backstage/integration'; import { Logger } from 'winston'; -import { GitLabGroup, GitLabMembership, GitLabUser } from './types'; +import { GitLabGroup, GitLabGroupMembersResponse, GitLabUser } from './types'; export type CommonListOptions = { [key: string]: string | number | boolean | undefined; @@ -78,16 +78,11 @@ export class GitLabClient { async listUsers( options?: UserListOptions, ): Promise> { - let requestOptions = options; - - if (!requestOptions) { - requestOptions = {}; - } - - requestOptions.without_project_bots = true; - requestOptions.exclude_internal = true; - - return this.pagedRequest(`/users?`, requestOptions); + return this.pagedRequest(`/users?`, { + ...options, + without_project_bots: true, + exclude_internal: true, + }); } async listGroups( @@ -96,30 +91,51 @@ export class GitLabClient { return this.pagedRequest(`/groups`, options); } - async getUserMemberships(userId: number): Promise { - const endpoint: string = `/users/${encodeURIComponent(userId)}/memberships`; - const request = new URL(`${this.config.apiBaseUrl}${endpoint}`); - request.searchParams.append('per_page', '100'); - - const response = await fetch(request.toString(), { - headers: getGitLabRequestOptions(this.config).headers, - method: 'GET', - }); - - if (!response.ok) { - if (response.status >= 500) { - this.logger.debug( - `Unexpected response when fetching ${request.toString()}. Expected 200 but got ${ - response.status - } - ${response.statusText}`, - ); + async getGroupMembers(groupPath: string): Promise { + const memberIds = []; + let hasNextPage: boolean = false; + let endCursor: string | null = null; + do { + const response: GitLabGroupMembersResponse = await fetch( + `${this.config.baseUrl}/api/graphql`, + { + method: 'POST', + headers: { + ...getGitLabRequestOptions(this.config).headers, + ['Content-Type']: 'application/json', + }, + body: JSON.stringify({ + variables: { group: groupPath, endCursor }, + query: `query($group: ID!, $endCursor: String) { + group(fullPath: $group) { + groupMembers(first: 100, relations: [DIRECT], after: $endCursor) { + nodes { + user { + id + } + } + pageInfo { + endCursor + hasNextPage + } + } + } + }`, + }), + }, + ).then(r => r.json()); + if (response.errors) { + throw new Error(`GraphQL errors: ${JSON.stringify(response.errors)}`); } - return []; - } - - return response.json().then(items => { - return items as GitLabMembership[]; - }); + memberIds.push( + ...response.data.group.groupMembers.nodes.map( + (node: { user: { id: string } }) => + Number(node.user.id.replace(/^gid:\/\/gitlab\/User\//, '')), + ), + ); + ({ hasNextPage, endCursor } = response.data.group.groupMembers.pageInfo); + } while (hasNextPage); + return memberIds; } /** diff --git a/plugins/catalog-backend-module-gitlab/src/lib/types.ts b/plugins/catalog-backend-module-gitlab/src/lib/types.ts index c3fc8a4ede..c27007861b 100644 --- a/plugins/catalog-backend-module-gitlab/src/lib/types.ts +++ b/plugins/catalog-backend-module-gitlab/src/lib/types.ts @@ -50,11 +50,19 @@ export type GitLabGroup = { parent_id?: number; }; -export type GitLabMembership = { - source_id: number; - source_name: string; - source_type: string; - access_level: number; +export type GitLabGroupMembersResponse = { + errors: { message: string }[]; + data: { + group: { + groupMembers: { + nodes: { user: { id: string } }[]; + pageInfo: { + endCursor: string; + hasNextPage: boolean; + }; + }; + }; + }; }; export type GitlabProviderConfig = { @@ -62,11 +70,12 @@ export type GitlabProviderConfig = { group: string; id: string; /** - * @deprecated use `fallbackBranch` instead + * The name of the branch to be used, to discover catalog files. */ branch?: string; /** - * If there is no default branch defined at the project, this fallback is used to discover catalog files. + * If no `branch` is configured and there is no default branch defined at the project as well, this fallback is used + * to discover catalog files. * Defaults to: `master` */ fallbackBranch: string; diff --git a/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.test.ts b/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.test.ts index 42fa1b471c..75a4c6414c 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.test.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.test.ts @@ -449,4 +449,111 @@ describe('GitlabDiscoveryEntityProvider', () => { 'GitlabDiscoveryEntityProvider:test-id', ); }); + + it('should filter found projects based on the branch', async () => { + const config = new ConfigReader({ + integrations: { + gitlab: [ + { + host: 'test-gitlab', + apiBaseUrl: 'https://api.gitlab.example/api/v4', + token: '1234', + }, + ], + }, + catalog: { + providers: { + gitlab: { + 'test-id': { + host: 'test-gitlab', + branch: 'test', + }, + }, + }, + }, + }); + const schedule = new PersistingTaskRunner(); + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + const provider = GitlabDiscoveryEntityProvider.fromConfig(config, { + logger, + schedule, + })[0]; + + server.use( + rest.get( + `https://api.gitlab.example/api/v4/projects`, + (_req, res, ctx) => { + const response = [ + { + id: 123, + default_branch: 'master', + archived: false, + last_activity_at: new Date().toString(), + web_url: 'https://api.gitlab.example/test-group/test-repo', + path_with_namespace: 'test-group/test-repo', + }, + { + id: 124, + default_branch: 'master', + archived: false, + last_activity_at: new Date().toString(), + web_url: 'https://api.gitlab.example/john/example', + path_with_namespace: 'john/example', + }, + ]; + return res(ctx.json(response)); + }, + ), + rest.head( + 'https://api.gitlab.example/api/v4/projects/test-group%2Ftest-repo/repository/files/catalog-info.yaml', + (_, res, ctx) => { + return res(ctx.status(404, 'Not Found')); + }, + ), + rest.head( + 'https://api.gitlab.example/api/v4/projects/john%2Fexample/repository/files/catalog-info.yaml', + (req, res, ctx) => { + if (req.url.searchParams.get('ref') === 'test') { + return res(ctx.status(200)); + } + return res(ctx.status(404, 'Not Found')); + }, + ), + ); + + await provider.connect(entityProviderConnection); + + await provider.refresh(logger); + + expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ + type: 'full', + entities: [ + { + entity: { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Location', + metadata: { + annotations: { + 'backstage.io/managed-by-location': + 'url:https://api.gitlab.example/john/example/-/blob/test/catalog-info.yaml', + 'backstage.io/managed-by-origin-location': + 'url:https://api.gitlab.example/john/example/-/blob/test/catalog-info.yaml', + }, + name: 'generated-232185d858fee049986d202c10316d634e76a3d1', + }, + spec: { + presence: 'optional', + target: + 'https://api.gitlab.example/john/example/-/blob/test/catalog-info.yaml', + type: 'url', + }, + }, + locationKey: 'GitlabDiscoveryEntityProvider:test-id', + }, + ], + }); + }); }); diff --git a/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.ts b/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.ts index ece10ee8c6..6001a32a4a 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.ts @@ -61,10 +61,7 @@ export class GitlabDiscoveryEntityProvider implements EntityProvider { throw new Error('Either schedule or scheduler must be provided.'); } - const providerConfigs = readGitlabConfigs( - config, - options.logger.child({ target: 'GitlabDiscoveryEntityProvider' }), - ); + const providerConfigs = readGitlabConfigs(config); const integrations = ScmIntegrations.fromConfig(config).gitlab; const providers: GitlabDiscoveryEntityProvider[] = []; @@ -181,6 +178,7 @@ export class GitlabDiscoveryEntityProvider implements EntityProvider { } if ( + !this.config.branch && this.config.fallbackBranch === '*' && project.default_branch === undefined ) { @@ -188,7 +186,9 @@ export class GitlabDiscoveryEntityProvider implements EntityProvider { } const project_branch = - project.default_branch ?? this.config.fallbackBranch; + this.config.branch ?? + project.default_branch ?? + this.config.fallbackBranch; const projectHasFile: boolean = await client.hasFile( project.path_with_namespace ?? '', @@ -211,7 +211,10 @@ export class GitlabDiscoveryEntityProvider implements EntityProvider { } private createLocationSpec(project: GitLabProject): LocationSpec { - const project_branch = project.default_branch ?? this.config.fallbackBranch; + const project_branch = + this.config.branch ?? + project.default_branch ?? + this.config.fallbackBranch; return { type: 'url', target: `${project.web_url}/-/blob/${project_branch}/${this.config.catalogFile}`, diff --git a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.test.ts b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.test.ts index 5a323a8dec..3d6ff0a91a 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.test.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.test.ts @@ -23,7 +23,7 @@ import { import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; import { ConfigReader } from '@backstage/config'; import { EntityProviderConnection } from '@backstage/plugin-catalog-node'; -import { rest } from 'msw'; +import { graphql, rest } from 'msw'; import { setupServer } from 'msw/node'; import { GitlabOrgDiscoveryEntityProvider } from './GitlabOrgDiscoveryEntityProvider'; @@ -318,20 +318,26 @@ describe('GitlabOrgDiscoveryEntityProvider', () => { ]; return res(ctx.json(response)); }), - rest.get( - `https://api.gitlab.example/api/v4/users/1/memberships`, - (_req, res, ctx) => { - const response = [ - { - source_id: 2, - source_name: 'Group 2', - source_type: 'Namespace', - access_level: 50, - }, - ]; - return res(ctx.json(response)); - }, - ), + graphql + .link('https://test-gitlab/api/graphql') + .operation(async (req, res, ctx) => + res( + ctx.data({ + group: { + groupMembers: { + nodes: + req.variables.group === 'group1/group2' + ? [{ user: { id: 'gid://gitlab/User/1' } }] + : [], + pageInfo: { + endCursor: 'end', + hasNextPage: false, + }, + }, + }, + }), + ), + ), ); await provider.connect(entityProviderConnection); diff --git a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts index acfa784c2e..1fe607afbb 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts @@ -72,10 +72,7 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { throw new Error('Either schedule or scheduler must be provided.'); } - const providerConfigs = readGitlabConfigs( - config, - options.logger.child({ target: 'GitlabOrgDiscoveryEntityProvider' }), - ); + const providerConfigs = readGitlabConfigs(config); const integrations = ScmIntegrations.fromConfig(config).gitlab; const providers: GitlabOrgDiscoveryEntityProvider[] = []; @@ -185,7 +182,7 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { }, ); - const idMappedGroup: { [groupId: number]: GitLabGroup } = {}; + const idMappedUser: { [userId: number]: GitLabUser } = {}; const res: Result = { scanned: 0, @@ -197,6 +194,21 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { matches: [], }; + for await (const user of users) { + if (!this.config.userPattern.test(user.email ?? user.username ?? '')) { + continue; + } + + res.scanned++; + + if (user.state !== 'active') { + continue; + } + + idMappedUser[user.id] = user; + res.matches.push(user); + } + for await (const group of groups) { if (!this.config.groupPattern.test(group.full_path ?? '')) { continue; @@ -212,35 +224,12 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { groupRes.scanned++; groupRes.matches.push(group); - idMappedGroup[group.id] = group; - } - - for await (const user of users) { - if (!this.config.userPattern.test(user.email ?? user.username ?? '')) { - continue; - } - - res.scanned++; - - if (user.state !== 'active') { - continue; - } - - const memberships = await client.getUserMemberships(user.id); - const userGroups: GitLabGroup[] = []; - - for (const i of memberships) { - if ( - i.source_type === 'Namespace' && - idMappedGroup.hasOwnProperty(i.source_id) - ) { - userGroups.push(idMappedGroup[i.source_id]); + for (const id of await client.getGroupMembers(group.full_path)) { + const user = idMappedUser[id]; + if (user) { + user.groups = (user.groups ?? []).concat(group); } } - - user.groups = userGroups; - - res.matches.push(user); } const groupsWithUsers = groupRes.matches.filter(group => { diff --git a/plugins/catalog-backend-module-gitlab/src/providers/config.test.ts b/plugins/catalog-backend-module-gitlab/src/providers/config.test.ts index c9b35e78c2..1035538939 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/config.test.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/config.test.ts @@ -17,9 +17,6 @@ import { ConfigReader } from '@backstage/config'; import { Duration } from 'luxon'; import { readGitlabConfigs } from './config'; -import { getVoidLogger } from '@backstage/backend-common'; - -const logger = getVoidLogger(); describe('config', () => { it('empty gitlab config', () => { @@ -29,7 +26,7 @@ describe('config', () => { }, }); - const result = readGitlabConfigs(config, logger); + const result = readGitlabConfigs(config); expect(result).toHaveLength(0); }); @@ -47,12 +44,13 @@ describe('config', () => { }, }); - const result = readGitlabConfigs(config, logger); + const result = readGitlabConfigs(config); expect(result).toHaveLength(1); result.forEach(r => expect(r).toStrictEqual({ id: 'test', group: 'group', + branch: undefined, fallbackBranch: 'master', host: 'host', catalogFile: 'catalog-info.yaml', @@ -74,6 +72,7 @@ describe('config', () => { group: 'group', host: 'host', branch: 'not-master', + fallbackBranch: 'main', entityFilename: 'custom-file.yaml', }, }, @@ -81,13 +80,14 @@ describe('config', () => { }, }); - const result = readGitlabConfigs(config, logger); + const result = readGitlabConfigs(config); expect(result).toHaveLength(1); result.forEach(r => expect(r).toStrictEqual({ id: 'test', group: 'group', - fallbackBranch: 'not-master', + branch: 'not-master', + fallbackBranch: 'main', host: 'host', catalogFile: 'custom-file.yaml', projectPattern: /[\s\S]*/, @@ -119,12 +119,13 @@ describe('config', () => { }, }); - const result = readGitlabConfigs(config, logger); + const result = readGitlabConfigs(config); expect(result).toHaveLength(1); result.forEach(r => expect(r).toStrictEqual({ id: 'test', group: 'group', + branch: undefined, fallbackBranch: 'master', host: 'host', catalogFile: 'catalog-info.yaml', @@ -158,7 +159,7 @@ describe('config', () => { }, }); - expect(() => readGitlabConfigs(config, logger)).toThrow( + expect(() => readGitlabConfigs(config)).toThrow( "Missing required config value at 'catalog.providers.gitlab.test.host'", ); }); @@ -177,7 +178,7 @@ describe('config', () => { }, }); - const result = readGitlabConfigs(config, logger); + const result = readGitlabConfigs(config); expect(result).toHaveLength(1); expect(result[0].group).toEqual(''); }); diff --git a/plugins/catalog-backend-module-gitlab/src/providers/config.ts b/plugins/catalog-backend-module-gitlab/src/providers/config.ts index e5cf5a6298..cd15c4825c 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/config.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/config.ts @@ -17,7 +17,6 @@ import { readTaskScheduleDefinitionFromConfig } from '@backstage/backend-tasks'; import { Config } from '@backstage/config'; import { GitlabProviderConfig } from '../lib'; -import { Logger } from 'winston'; /** * Extracts the gitlab config from a config object @@ -26,25 +25,12 @@ import { Logger } from 'winston'; * * @param id - The provider key * @param config - The config object to extract from - * @param logger - The logger */ -function readGitlabConfig( - id: string, - config: Config, - logger: Logger, -): GitlabProviderConfig { +function readGitlabConfig(id: string, config: Config): GitlabProviderConfig { const group = config.getOptionalString('group') ?? ''; const host = config.getString('host'); const branch = config.getOptionalString('branch'); - - if (branch) { - logger.warn( - 'The configuration key `branch` has been deprecated in favor of the configuration key `fallbackBranch`.', - ); - } - - const fallbackBranch = - config.getOptionalString('fallbackBranch') ?? branch ?? 'master'; + const fallbackBranch = config.getOptionalString('fallbackBranch') ?? 'master'; const catalogFile = config.getOptionalString('entityFilename') ?? 'catalog-info.yaml'; const projectPattern = new RegExp( @@ -65,6 +51,7 @@ function readGitlabConfig( return { id, group, + branch, fallbackBranch, host, catalogFile, @@ -82,12 +69,8 @@ function readGitlabConfig( * @public * * @param config - The config object to extract from - * @param logger - The logger */ -export function readGitlabConfigs( - config: Config, - logger: Logger, -): GitlabProviderConfig[] { +export function readGitlabConfigs(config: Config): GitlabProviderConfig[] { const configs: GitlabProviderConfig[] = []; const providerConfigs = config.getOptionalConfig('catalog.providers.gitlab'); @@ -97,13 +80,7 @@ export function readGitlabConfigs( } for (const id of providerConfigs.keys()) { - configs.push( - readGitlabConfig( - id, - providerConfigs.getConfig(id), - logger.child({ target: id }), - ), - ); + configs.push(readGitlabConfig(id, providerConfigs.getConfig(id))); } return configs; diff --git a/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md b/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md index d411c63ed2..5bf522c41b 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md +++ b/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-catalog-backend-module-incremental-ingestion +## 0.3.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.8.1-next.0 + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/plugin-catalog-node@1.3.5-next.0 + - @backstage/plugin-events-node@0.2.5-next.0 + - @backstage/plugin-permission-common@0.7.4 + ## 0.3.0 ### Minor Changes diff --git a/plugins/catalog-backend-module-incremental-ingestion/package.json b/plugins/catalog-backend-module-incremental-ingestion/package.json index df86610dce..66e939dbe3 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/package.json +++ b/plugins/catalog-backend-module-incremental-ingestion/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-incremental-ingestion", "description": "An entity provider for streaming large asset sources into the catalog", - "version": "0.3.0", + "version": "0.3.1-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-ldap/CHANGELOG.md b/plugins/catalog-backend-module-ldap/CHANGELOG.md index 99503f83bf..a89c835ef2 100644 --- a/plugins/catalog-backend-module-ldap/CHANGELOG.md +++ b/plugins/catalog-backend-module-ldap/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-catalog-backend-module-ldap +## 0.5.11-next.0 + +### Patch Changes + +- c9a0fdcd2c8: Fix deprecated types. +- Updated dependencies + - @backstage/config@1.0.7 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/types@1.0.2 + - @backstage/plugin-catalog-common@1.0.12 + - @backstage/plugin-catalog-node@1.3.5-next.0 + ## 0.5.10 ### Patch Changes diff --git a/plugins/catalog-backend-module-ldap/api-report.md b/plugins/catalog-backend-module-ldap/api-report.md index 088e34fc34..997ad55560 100644 --- a/plugins/catalog-backend-module-ldap/api-report.md +++ b/plugins/catalog-backend-module-ldap/api-report.md @@ -11,7 +11,7 @@ import { EntityProvider } from '@backstage/plugin-catalog-node'; import { EntityProviderConnection } from '@backstage/plugin-catalog-node'; import { GroupEntity } from '@backstage/catalog-model'; import { JsonValue } from '@backstage/types'; -import { LocationSpec } from '@backstage/plugin-catalog-node'; +import { LocationSpec } from '@backstage/plugin-catalog-common'; import { Logger } from 'winston'; import { SearchEntry } from 'ldapjs'; import { SearchOptions } from 'ldapjs'; diff --git a/plugins/catalog-backend-module-ldap/package.json b/plugins/catalog-backend-module-ldap/package.json index d483baa914..6986f7a84a 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.10", + "version": "0.5.11-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -36,6 +36,7 @@ "@backstage/catalog-model": "workspace:^", "@backstage/config": "workspace:^", "@backstage/errors": "workspace:^", + "@backstage/plugin-catalog-common": "workspace:^", "@backstage/plugin-catalog-node": "workspace:^", "@backstage/types": "workspace:^", "@types/ldapjs": "^2.2.0", diff --git a/plugins/catalog-backend-module-ldap/src/processors/LdapOrgReaderProcessor.ts b/plugins/catalog-backend-module-ldap/src/processors/LdapOrgReaderProcessor.ts index 9c5442ca0c..00578ac3a4 100644 --- a/plugins/catalog-backend-module-ldap/src/processors/LdapOrgReaderProcessor.ts +++ b/plugins/catalog-backend-module-ldap/src/processors/LdapOrgReaderProcessor.ts @@ -27,9 +27,9 @@ import { import { CatalogProcessor, CatalogProcessorEmit, - LocationSpec, processingResult, } from '@backstage/plugin-catalog-node'; +import { LocationSpec } from '@backstage/plugin-catalog-common'; /** * Extracts teams and users out of an LDAP server. diff --git a/plugins/catalog-backend-module-msgraph/CHANGELOG.md b/plugins/catalog-backend-module-msgraph/CHANGELOG.md index 37393dfd7b..9eed88aa13 100644 --- a/plugins/catalog-backend-module-msgraph/CHANGELOG.md +++ b/plugins/catalog-backend-module-msgraph/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-catalog-backend-module-msgraph +## 0.5.3-next.0 + +### Patch Changes + +- c9a0fdcd2c8: Fix deprecated types. +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/catalog-model@1.2.1 + - @backstage/plugin-catalog-common@1.0.12 + - @backstage/plugin-catalog-node@1.3.5-next.0 + ## 0.5.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-msgraph/api-report.md b/plugins/catalog-backend-module-msgraph/api-report.md index bde8c06fbb..3e4d8d99bc 100644 --- a/plugins/catalog-backend-module-msgraph/api-report.md +++ b/plugins/catalog-backend-module-msgraph/api-report.md @@ -9,7 +9,7 @@ import { Config } from '@backstage/config'; import { EntityProvider } from '@backstage/plugin-catalog-node'; import { EntityProviderConnection } from '@backstage/plugin-catalog-node'; import { GroupEntity } from '@backstage/catalog-model'; -import { LocationSpec } from '@backstage/plugin-catalog-node'; +import { LocationSpec } from '@backstage/plugin-catalog-common'; import { Logger } from 'winston'; import * as MicrosoftGraph from '@microsoft/microsoft-graph-types'; import { PluginTaskScheduler } from '@backstage/backend-tasks'; diff --git a/plugins/catalog-backend-module-msgraph/package.json b/plugins/catalog-backend-module-msgraph/package.json index 3201e0b8d4..15f272d48f 100644 --- a/plugins/catalog-backend-module-msgraph/package.json +++ b/plugins/catalog-backend-module-msgraph/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-msgraph", "description": "A Backstage catalog backend module that helps integrate towards Microsoft Graph", - "version": "0.5.2", + "version": "0.5.3-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -51,6 +51,7 @@ "@backstage/backend-tasks": "workspace:^", "@backstage/catalog-model": "workspace:^", "@backstage/config": "workspace:^", + "@backstage/plugin-catalog-common": "workspace:^", "@backstage/plugin-catalog-node": "workspace:^", "@microsoft/microsoft-graph-types": "^2.6.0", "@types/node-fetch": "^2.5.12", diff --git a/plugins/catalog-backend-module-msgraph/src/processors/MicrosoftGraphOrgReaderProcessor.ts b/plugins/catalog-backend-module-msgraph/src/processors/MicrosoftGraphOrgReaderProcessor.ts index 2beef51c31..d9119a3c4d 100644 --- a/plugins/catalog-backend-module-msgraph/src/processors/MicrosoftGraphOrgReaderProcessor.ts +++ b/plugins/catalog-backend-module-msgraph/src/processors/MicrosoftGraphOrgReaderProcessor.ts @@ -18,9 +18,9 @@ import { Config } from '@backstage/config'; import { CatalogProcessor, CatalogProcessorEmit, - LocationSpec, processingResult, } from '@backstage/plugin-catalog-node'; +import { LocationSpec } from '@backstage/plugin-catalog-common'; import { Logger } from 'winston'; import { GroupTransformer, diff --git a/plugins/catalog-backend-module-openapi/CHANGELOG.md b/plugins/catalog-backend-module-openapi/CHANGELOG.md index 414f7960cd..680e86263f 100644 --- a/plugins/catalog-backend-module-openapi/CHANGELOG.md +++ b/plugins/catalog-backend-module-openapi/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-catalog-backend-module-openapi +## 0.1.10-next.0 + +### Patch Changes + +- c9a0fdcd2c8: Fix deprecated types. +- Updated dependencies + - @backstage/plugin-catalog-backend@1.8.1-next.0 + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/catalog-model@1.2.1 + - @backstage/types@1.0.2 + - @backstage/plugin-catalog-common@1.0.12 + - @backstage/plugin-catalog-node@1.3.5-next.0 + ## 0.1.9 ### Patch Changes diff --git a/plugins/catalog-backend-module-openapi/api-report.md b/plugins/catalog-backend-module-openapi/api-report.md index c2af9cbe01..455816645a 100644 --- a/plugins/catalog-backend-module-openapi/api-report.md +++ b/plugins/catalog-backend-module-openapi/api-report.md @@ -3,11 +3,11 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts -import { CatalogProcessor } from '@backstage/plugin-catalog-backend'; +import { CatalogProcessor } from '@backstage/plugin-catalog-node'; import { Config } from '@backstage/config'; import { Entity } from '@backstage/catalog-model'; import { JsonValue } from '@backstage/types'; -import { LocationSpec } from '@backstage/plugin-catalog-backend'; +import { LocationSpec } from '@backstage/plugin-catalog-common'; import { Logger } from 'winston'; import { PlaceholderResolverParams } from '@backstage/plugin-catalog-backend'; import { ScmIntegrations } from '@backstage/integration'; diff --git a/plugins/catalog-backend-module-openapi/package.json b/plugins/catalog-backend-module-openapi/package.json index 6bb9d66ec5..fd4a8fef4d 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.9", + "version": "0.1.10-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -38,6 +38,7 @@ "@backstage/config": "workspace:^", "@backstage/integration": "workspace:^", "@backstage/plugin-catalog-backend": "workspace:^", + "@backstage/plugin-catalog-common": "workspace:^", "@backstage/plugin-catalog-node": "workspace:^", "@backstage/types": "workspace:^", "winston": "^3.2.1", diff --git a/plugins/catalog-backend-module-openapi/src/OpenApiRefProcessor.ts b/plugins/catalog-backend-module-openapi/src/OpenApiRefProcessor.ts index 9dcadad61d..6b00519b2f 100644 --- a/plugins/catalog-backend-module-openapi/src/OpenApiRefProcessor.ts +++ b/plugins/catalog-backend-module-openapi/src/OpenApiRefProcessor.ts @@ -17,10 +17,8 @@ import { UrlReader } from '@backstage/backend-common'; import { Entity } from '@backstage/catalog-model'; import { Config } from '@backstage/config'; import { ScmIntegrations } from '@backstage/integration'; -import { - CatalogProcessor, - LocationSpec, -} from '@backstage/plugin-catalog-backend'; +import { CatalogProcessor } from '@backstage/plugin-catalog-node'; +import { LocationSpec } from '@backstage/plugin-catalog-common'; import { bundleFileWithRefs } from './lib'; import { Logger } from 'winston'; diff --git a/plugins/catalog-backend-module-puppetdb/CHANGELOG.md b/plugins/catalog-backend-module-puppetdb/CHANGELOG.md index d3ccdb6782..50c805985e 100644 --- a/plugins/catalog-backend-module-puppetdb/CHANGELOG.md +++ b/plugins/catalog-backend-module-puppetdb/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-catalog-backend-module-puppetdb +## 0.1.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/types@1.0.2 + - @backstage/plugin-catalog-node@1.3.5-next.0 + ## 0.1.0 ### Minor Changes diff --git a/plugins/catalog-backend-module-puppetdb/package.json b/plugins/catalog-backend-module-puppetdb/package.json index 3334e3d204..f3df2dfdc8 100644 --- a/plugins/catalog-backend-module-puppetdb/package.json +++ b/plugins/catalog-backend-module-puppetdb/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-puppetdb", "description": "A Backstage catalog backend module that helps integrate towards PuppetDB", - "version": "0.1.0", + "version": "0.1.1-next.0", "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 0a3c5853e0..e450baf77b 100644 --- a/plugins/catalog-backend/CHANGELOG.md +++ b/plugins/catalog-backend/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-catalog-backend +## 1.8.1-next.0 + +### Patch Changes + +- c9a0fdcd2c8: Fix deprecated types. +- 899ebfd8e02: Add full text search support to the `by-query` endpoint. +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.2.7-next.0 + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/types@1.0.2 + - @backstage/plugin-catalog-common@1.0.12 + - @backstage/plugin-catalog-node@1.3.5-next.0 + - @backstage/plugin-permission-common@0.7.4 + - @backstage/plugin-permission-node@0.7.7-next.0 + - @backstage/plugin-search-common@1.2.2 + ## 1.8.0 ### Minor Changes diff --git a/plugins/catalog-backend/api-report.md b/plugins/catalog-backend/api-report.md index 5e7b2dee02..d491f391d5 100644 --- a/plugins/catalog-backend/api-report.md +++ b/plugins/catalog-backend/api-report.md @@ -11,6 +11,7 @@ import { AnalyzeLocationGenerateEntity as AnalyzeLocationGenerateEntity_2 } from import { AnalyzeLocationRequest as AnalyzeLocationRequest_2 } from '@backstage/plugin-catalog-common'; import { AnalyzeLocationResponse as AnalyzeLocationResponse_2 } from '@backstage/plugin-catalog-common'; import { CatalogApi } from '@backstage/catalog-client'; +import type { CatalogCollatorEntityTransformer as CatalogCollatorEntityTransformer_2 } from '@backstage/plugin-search-backend-module-catalog'; import { CatalogEntityDocument } from '@backstage/plugin-catalog-common'; import { CatalogProcessor as CatalogProcessor_2 } from '@backstage/plugin-catalog-node'; import { CatalogProcessorCache as CatalogProcessorCache_2 } from '@backstage/plugin-catalog-node'; @@ -23,8 +24,9 @@ import { CatalogProcessorRefreshKeysResult as CatalogProcessorRefreshKeysResult_ import { CatalogProcessorRelationResult as CatalogProcessorRelationResult_2 } from '@backstage/plugin-catalog-node'; import { CatalogProcessorResult as CatalogProcessorResult_2 } from '@backstage/plugin-catalog-node'; import { Config } from '@backstage/config'; +import { DefaultCatalogCollatorFactory as DefaultCatalogCollatorFactory_2 } from '@backstage/plugin-search-backend-module-catalog'; +import type { DefaultCatalogCollatorFactoryOptions as DefaultCatalogCollatorFactoryOptions_2 } from '@backstage/plugin-search-backend-module-catalog'; import { DeferredEntity as DeferredEntity_2 } from '@backstage/plugin-catalog-node'; -import { DocumentCollatorFactory } from '@backstage/plugin-search-common'; import { Entity } from '@backstage/catalog-model'; import { EntityPolicy } from '@backstage/catalog-model'; import { EntityProvider as EntityProvider_2 } from '@backstage/plugin-catalog-node'; @@ -44,7 +46,6 @@ import { PermissionRule } from '@backstage/plugin-permission-node'; import { PermissionRuleParams } from '@backstage/plugin-permission-common'; import { PluginDatabaseManager } from '@backstage/backend-common'; import { PluginEndpointDiscovery } from '@backstage/backend-common'; -import { Readable } from 'stream'; import { Router } from 'express'; import { ScmIntegrationRegistry } from '@backstage/integration'; import { TokenManager } from '@backstage/backend-common'; @@ -160,10 +161,9 @@ export class CatalogBuilder { useLegacySingleProcessorValidation(): this; } -// @public (undocumented) -export type CatalogCollatorEntityTransformer = ( - entity: Entity, -) => Omit; +// @public @deprecated (undocumented) +export type CatalogCollatorEntityTransformer = + CatalogCollatorEntityTransformer_2; // @public (undocumented) export type CatalogEnvironment = { @@ -286,34 +286,15 @@ export class DefaultCatalogCollator { readonly visibilityPermission: Permission; } -// @public (undocumented) -export const defaultCatalogCollatorEntityTransformer: CatalogCollatorEntityTransformer; +// @public @deprecated (undocumented) +export const defaultCatalogCollatorEntityTransformer: CatalogCollatorEntityTransformer_2; -// @public (undocumented) -export class DefaultCatalogCollatorFactory implements DocumentCollatorFactory { - // (undocumented) - static fromConfig( - _config: Config, - options: DefaultCatalogCollatorFactoryOptions, - ): DefaultCatalogCollatorFactory; - // (undocumented) - getCollator(): Promise; - // (undocumented) - readonly type = 'software-catalog'; - // (undocumented) - readonly visibilityPermission: Permission; -} +// @public @deprecated (undocumented) +export const DefaultCatalogCollatorFactory: typeof DefaultCatalogCollatorFactory_2; -// @public (undocumented) -export type DefaultCatalogCollatorFactoryOptions = { - discovery: PluginEndpointDiscovery; - tokenManager: TokenManager; - locationTemplate?: string; - filter?: GetEntitiesRequest['filter']; - batchSize?: number; - catalogClient?: CatalogApi; - entityTransformer?: CatalogCollatorEntityTransformer; -}; +// @public @deprecated (undocumented) +export type DefaultCatalogCollatorFactoryOptions = + DefaultCatalogCollatorFactoryOptions_2; // @public @deprecated (undocumented) export type DeferredEntity = DeferredEntity_2; diff --git a/plugins/catalog-backend/package.json b/plugins/catalog-backend/package.json index 1e837fd9ba..023d709d81 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.8.0", + "version": "1.8.1-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -57,6 +57,7 @@ "@backstage/plugin-permission-common": "workspace:^", "@backstage/plugin-permission-node": "workspace:^", "@backstage/plugin-scaffolder-common": "workspace:^", + "@backstage/plugin-search-backend-module-catalog": "workspace:^", "@backstage/plugin-search-common": "workspace:^", "@backstage/types": "workspace:^", "@opentelemetry/api": "^1.3.0", diff --git a/plugins/catalog-backend/src/index.ts b/plugins/catalog-backend/src/index.ts index b3d2bc95c7..eca155ce46 100644 --- a/plugins/catalog-backend/src/index.ts +++ b/plugins/catalog-backend/src/index.ts @@ -27,3 +27,40 @@ export * from './processing'; export * from './search'; export * from './service'; export * from './deprecated'; + +import { + DefaultCatalogCollatorFactory as _DefaultCatalogCollatorFactory, + defaultCatalogCollatorEntityTransformer as _defaultCatalogCollatorEntityTransformer, +} from '@backstage/plugin-search-backend-module-catalog'; + +/** + * @public + * @deprecated import from `@backstage/search-backend-module-catalog` instead + */ +export const DefaultCatalogCollatorFactory = _DefaultCatalogCollatorFactory; + +/** + * @public + * @deprecated import from `@backstage/search-backend-module-catalog` instead + */ +export const defaultCatalogCollatorEntityTransformer = + _defaultCatalogCollatorEntityTransformer; + +import type { + DefaultCatalogCollatorFactoryOptions as _DefaultCatalogCollatorFactoryOptions, + CatalogCollatorEntityTransformer as _CatalogCollatorEntityTransformer, +} from '@backstage/plugin-search-backend-module-catalog'; + +/** + * @public + * @deprecated import from `@backstage/search-backend-module-catalog` instead + */ +export type DefaultCatalogCollatorFactoryOptions = + _DefaultCatalogCollatorFactoryOptions; + +/** + * @public + * @deprecated import from `@backstage/search-backend-module-catalog` instead + */ +export type CatalogCollatorEntityTransformer = + _CatalogCollatorEntityTransformer; diff --git a/plugins/catalog-backend/src/migrations.test.ts b/plugins/catalog-backend/src/migrations.test.ts index f1ed40dbbe..33f88e9aa7 100644 --- a/plugins/catalog-backend/src/migrations.test.ts +++ b/plugins/catalog-backend/src/migrations.test.ts @@ -44,6 +44,67 @@ describe('migrations', () => { ids: ['MYSQL_8', 'POSTGRES_13', 'POSTGRES_9', 'SQLITE_3'], }); + it.each(databases.eachSupportedId())( + 'latest version correctly cascades deletions, %p', + async databaseId => { + const knex = await databases.init(databaseId); + await knex.migrate.latest({ directory: migrationsDir }); + + await knex + .insert({ + entity_id: 'i1', + entity_ref: 'k:ns/n1', + unprocessed_entity: '{}', + errors: '[]', + next_update_at: new Date(), + last_discovery_at: new Date(), + }) + .into('refresh_state'); + await knex + .insert({ + entity_id: 'i2', + entity_ref: 'k:ns/n2', + unprocessed_entity: '{}', + errors: '[]', + next_update_at: new Date(), + last_discovery_at: new Date(), + }) + .into('refresh_state'); + await knex + .insert({ entity_id: 'i1', key: 'k1', value: 'v1' }) + .into('search'); + await knex + .insert({ + source_entity_ref: 'k:ns/n1', + target_entity_ref: 'k:ns/n2', + }) + .into('refresh_state_references'); + await knex + .insert({ + originating_entity_id: 'i1', + source_entity_ref: 'k:ns/n1', + target_entity_ref: 'k:ns/n2', + type: 't', + }) + .into('relations'); + await knex + .insert({ + entity_id: 'i1', + hash: 'h', + stitch_ticket: '', + final_entity: '{}', + }) + .into('final_entities'); + + await knex.delete().from('refresh_state').where({ entity_id: 'i1' }); + + await expect(knex('search')).resolves.toEqual([]); + await expect(knex('refresh_state_references')).resolves.toEqual([]); + await expect(knex('relations')).resolves.toEqual([]); + await expect(knex('final_entities')).resolves.toEqual([]); + }, + ); + it.each(databases.eachSupportedId())( '20221109192547_search_add_original_value_column.js, %p', async databaseId => { diff --git a/plugins/catalog-backend/src/modules/core/LocationEntityProcessor.test.ts b/plugins/catalog-backend/src/modules/core/LocationEntityProcessor.test.ts index 68c073eb0a..5e000f87d6 100644 --- a/plugins/catalog-backend/src/modules/core/LocationEntityProcessor.test.ts +++ b/plugins/catalog-backend/src/modules/core/LocationEntityProcessor.test.ts @@ -21,7 +21,7 @@ import { } from '@backstage/integration'; import path from 'path'; import { toAbsoluteUrl } from './LocationEntityProcessor'; -import { LocationSpec } from '@backstage/plugin-catalog-node'; +import { LocationSpec } from '@backstage/plugin-catalog-common'; describe('LocationEntityProcessor', () => { describe('toAbsoluteUrl', () => { diff --git a/plugins/catalog-backend/src/search/index.ts b/plugins/catalog-backend/src/search/index.ts index 3603ab2e60..50966e4c5b 100644 --- a/plugins/catalog-backend/src/search/index.ts +++ b/plugins/catalog-backend/src/search/index.ts @@ -14,11 +14,6 @@ * limitations under the License. */ -export { DefaultCatalogCollatorFactory } from './DefaultCatalogCollatorFactory'; -export type { DefaultCatalogCollatorFactoryOptions } from './DefaultCatalogCollatorFactory'; -export type { CatalogCollatorEntityTransformer } from './CatalogCollatorEntityTransformer'; -export { defaultCatalogCollatorEntityTransformer } from './defaultCatalogCollatorEntityTransformer'; - /** * todo(backstage/techdocs-core): stop exporting this in a future release. */ diff --git a/plugins/catalog-backend/src/service/CatalogBuilder.ts b/plugins/catalog-backend/src/service/CatalogBuilder.ts index 7da5d69767..782ad1bf3c 100644 --- a/plugins/catalog-backend/src/service/CatalogBuilder.ts +++ b/plugins/catalog-backend/src/service/CatalogBuilder.ts @@ -599,16 +599,28 @@ export class CatalogBuilder { ...this.placeholderResolvers, }; - // These are always there no matter what + // The placeholder is always there no matter what const processors: CatalogProcessor[] = [ new PlaceholderProcessor({ resolvers: placeholderResolvers, reader, integrations, }), - new BuiltinKindsEntityProcessor(), ]; + const builtinKindsEntityProcessor = new BuiltinKindsEntityProcessor(); + // If the user adds a processor named 'BuiltinKindsEntityProcessor', + // skip inclusion of the catalog-backend version. + if ( + !this.processors.some( + processor => + processor.getProcessorName() === + builtinKindsEntityProcessor.getProcessorName(), + ) + ) { + processors.push(builtinKindsEntityProcessor); + } + // These are only added unless the user replaced them all if (!this.processorsReplace) { processors.push(...this.getDefaultProcessors()); diff --git a/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.test.ts b/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.test.ts index 275bd1c42c..25cdc8d826 100644 --- a/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.test.ts +++ b/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.test.ts @@ -1119,6 +1119,193 @@ describe('DefaultEntitiesCatalog', () => { }, ); + it.each(databases.eachSupportedId())( + 'should filter the text results when sortOrder is not provided, %p', + async databaseId => { + await createDatabase(databaseId); + + const names = ['lion', 'cat', 'atcatss', 'dog', 'dogcat', 'aa', 's']; + const entities: Entity[] = names.map((name, index) => + // Need a stable search since default filtering is by uid, and those get generated on the fly + // during the test case. + entityFrom(`${index}`, { uid: `id${index}`, title: name }), + ); + + const notFoundEntities: Entity[] = [ + { + apiVersion: 'a', + kind: 'k', + metadata: { name: 'something' }, + spec: {}, + }, + { + apiVersion: 'a', + kind: 'k', + metadata: { name: 'something else' }, + spec: {}, + }, + ]; + + await Promise.all( + entities.concat(notFoundEntities).map(e => addEntityToSearch(e)), + ); + + const catalog = new DefaultEntitiesCatalog({ + database: knex, + logger: getVoidLogger(), + stitcher, + }); + + const filter = { + key: 'spec.should_include_this', + }; + + const request: QueryEntitiesInitialRequest = { + filter, + limit: 100, + fullTextFilter: { term: 'cAt ', fields: ['metadata.title'] }, + }; + const response = await catalog.queryEntities(request); + expect(response.items).toEqual([ + entityFrom('1', { uid: 'id1', title: 'cat' }), + entityFrom('2', { uid: 'id2', title: 'atcatss' }), + entityFrom('4', { uid: 'id4', title: 'dogcat' }), + ]); + expect(response.pageInfo.nextCursor).toBeUndefined(); + expect(response.pageInfo.prevCursor).toBeUndefined(); + expect(response.totalItems).toBe(3); + + const paginatedResponse = await catalog.queryEntities({ + ...request, + limit: 2, + }); + expect(paginatedResponse.items).toEqual([ + entityFrom('1', { uid: 'id1', title: 'cat' }), + entityFrom('2', { uid: 'id2', title: 'atcatss' }), + ]); + expect(paginatedResponse.pageInfo.nextCursor).not.toBeUndefined(); + expect(paginatedResponse.pageInfo.prevCursor).toBeUndefined(); + expect(paginatedResponse.totalItems).toBe(3); + + const paginatedResponseNext = await catalog.queryEntities({ + cursor: paginatedResponse.pageInfo.nextCursor!, + }); + expect(paginatedResponseNext.items).toEqual([ + entityFrom('4', { uid: 'id4', title: 'dogcat' }), + ]); + expect(paginatedResponseNext.pageInfo.nextCursor).toBeUndefined(); + expect(paginatedResponseNext.pageInfo.prevCursor).not.toBeUndefined(); + expect(paginatedResponseNext.totalItems).toBe(3); + + const paginatedResponsePrev = await catalog.queryEntities({ + cursor: paginatedResponseNext.pageInfo.prevCursor!, + }); + expect(paginatedResponsePrev).toMatchObject(paginatedResponse); + }, + ); + + it.each(databases.eachSupportedId())( + 'should filter the text results by multiple search fields if provided, %p', + async databaseId => { + await createDatabase(databaseId); + + const defs = [ + { + title: 'lion', + name: 'KingOfTheJungle', + }, + { title: 'cat', name: 'NotKingOfTheJungle' }, + { title: 'atcatss', name: 'NotACatKing' }, + { title: 'king', name: '123' }, + { title: 'dogcat', name: 'dogcat' }, + { title: 'aa', name: 'test123' }, + { title: 's', name: 'idk' }, + ]; + const entities: Entity[] = defs.map(({ title, name }, index) => + // Need a stable search since default filtering is by uid, and those get generated on the fly + // during the test case. + entityFrom(name, { uid: `id${index}`, title }), + ); + + const notFoundEntities: Entity[] = [ + { + apiVersion: 'a', + kind: 'k', + metadata: { name: 'something' }, + spec: {}, + }, + { + apiVersion: 'a', + kind: 'k', + metadata: { name: 'something else' }, + spec: {}, + }, + ]; + + await Promise.all( + entities.concat(notFoundEntities).map(e => addEntityToSearch(e)), + ); + + const catalog = new DefaultEntitiesCatalog({ + database: knex, + logger: getVoidLogger(), + stitcher, + }); + + const filter = { + key: 'spec.should_include_this', + }; + + const request: QueryEntitiesInitialRequest = { + filter, + limit: 100, + fullTextFilter: { + term: 'KiNg ', + fields: ['metadata.title', 'metadata.name'], + }, + }; + const response = await catalog.queryEntities(request); + + expect(response.items).toEqual([ + entityFrom('KingOfTheJungle', { uid: 'id0', title: 'lion' }), + entityFrom('NotKingOfTheJungle', { uid: 'id1', title: 'cat' }), + entityFrom('NotACatKing', { uid: 'id2', title: 'atcatss' }), + entityFrom('123', { uid: 'id3', title: 'king' }), + ]); + expect(response.pageInfo.nextCursor).toBeUndefined(); + expect(response.pageInfo.prevCursor).toBeUndefined(); + expect(response.totalItems).toBe(4); + + const paginatedResponse = await catalog.queryEntities({ + ...request, + limit: 2, + }); + expect(paginatedResponse.items).toEqual([ + entityFrom('KingOfTheJungle', { uid: 'id0', title: 'lion' }), + entityFrom('NotKingOfTheJungle', { uid: 'id1', title: 'cat' }), + ]); + expect(paginatedResponse.pageInfo.nextCursor).not.toBeUndefined(); + expect(paginatedResponse.pageInfo.prevCursor).toBeUndefined(); + expect(paginatedResponse.totalItems).toBe(4); + + const paginatedResponseNext = await catalog.queryEntities({ + cursor: paginatedResponse.pageInfo.nextCursor!, + }); + expect(paginatedResponseNext.items).toEqual([ + entityFrom('NotACatKing', { uid: 'id2', title: 'atcatss' }), + entityFrom('123', { uid: 'id3', title: 'king' }), + ]); + expect(paginatedResponseNext.pageInfo.nextCursor).toBeUndefined(); + expect(paginatedResponseNext.pageInfo.prevCursor).not.toBeUndefined(); + expect(paginatedResponseNext.totalItems).toBe(4); + + const paginatedResponsePrev = await catalog.queryEntities({ + cursor: paginatedResponseNext.pageInfo.prevCursor!, + }); + expect(paginatedResponsePrev).toMatchObject(paginatedResponse); + }, + ); + it.each(databases.eachSupportedId())( 'should include totalItems and empty entities in the response in case limit is zero, %p', async databaseId => { @@ -1577,7 +1764,11 @@ describe('DefaultEntitiesCatalog', () => { function entityFrom( name: string, - { uid, namespace }: { uid?: string; namespace?: string } = {}, + { + uid, + namespace, + title, + }: { uid?: string; namespace?: string; title?: string } = {}, ) { return { apiVersion: 'a', @@ -1586,6 +1777,7 @@ function entityFrom( name, ...(!!namespace && { namespace }), ...(!!uid && { uid }), + ...(!!title && { title }), }, spec: { should_include_this: 'yes' }, }; diff --git a/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.ts b/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.ts index 4e6109423e..ba165f96af 100644 --- a/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.ts +++ b/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.ts @@ -382,11 +382,30 @@ export class DefaultEntitiesCatalog implements EntitiesCatalog { } const normalizedFullTextFilterTerm = cursor.fullTextFilter?.term?.trim(); + const textFilterFields = cursor.fullTextFilter?.fields ?? [sortField.field]; if (normalizedFullTextFilterTerm) { - dbQuery.andWhereRaw( - 'value like ?', - `%${normalizedFullTextFilterTerm.toLocaleLowerCase('en-US')}%`, - ); + if ( + textFilterFields.length === 1 && + textFilterFields[0] === sortField.field + ) { + // If there is one item, apply the like query to the top level query which is already + // filtered based on the singular sortField. + dbQuery.andWhereRaw( + 'value like ?', + `%${normalizedFullTextFilterTerm.toLocaleLowerCase('en-US')}%`, + ); + } else { + const matchQuery = db('search') + .select('search.entity_id') + .whereIn('key', textFilterFields) + .andWhere(function keyFilter() { + this.andWhereRaw( + 'value like ?', + `%${normalizedFullTextFilterTerm.toLocaleLowerCase('en-US')}%`, + ); + }); + dbQuery.andWhere('search.entity_id', 'in', matchQuery); + } } const countQuery = dbQuery.clone(); diff --git a/plugins/catalog-customized/CHANGELOG.md b/plugins/catalog-customized/CHANGELOG.md index c155405317..b71628d43c 100644 --- a/plugins/catalog-customized/CHANGELOG.md +++ b/plugins/catalog-customized/CHANGELOG.md @@ -1,5 +1,13 @@ # @internal/plugin-catalog-customized +## 0.0.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.10.0-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + ## 0.0.8 ### Patch Changes diff --git a/plugins/catalog-customized/package.json b/plugins/catalog-customized/package.json index 59159bfe84..0cca05de5a 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.8", + "version": "0.0.9-next.0", "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 04d714d024..5975f7d319 100644 --- a/plugins/catalog-graph/CHANGELOG.md +++ b/plugins/catalog-graph/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-catalog-graph +## 0.2.29-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + ## 0.2.28 ### Patch Changes diff --git a/plugins/catalog-graph/package.json b/plugins/catalog-graph/package.json index 1ae663f32c..f5cc5f7619 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.28", + "version": "0.2.29-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,7 +30,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "classnames": "^2.3.1", "lodash": "^4.17.15", "p-limit": "^3.1.0", diff --git a/plugins/catalog-graphql/CHANGELOG.md b/plugins/catalog-graphql/CHANGELOG.md index 740ed8905a..041191fcef 100644 --- a/plugins/catalog-graphql/CHANGELOG.md +++ b/plugins/catalog-graphql/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-catalog-graphql +## 0.3.20-next.0 + +### Patch Changes + +- e47e69eadf0: Updated dependency `@apollo/server` to `^4.0.0`. +- Updated dependencies + - @backstage/config@1.0.7 + - @backstage/catalog-model@1.2.1 + - @backstage/types@1.0.2 + ## 0.3.19 ### Patch Changes diff --git a/plugins/catalog-graphql/package.json b/plugins/catalog-graphql/package.json index 274828db86..11b899f528 100644 --- a/plugins/catalog-graphql/package.json +++ b/plugins/catalog-graphql/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-graphql", "description": "An experimental Backstage catalog GraphQL module", - "version": "0.3.19", + "version": "0.3.20-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,10 +34,11 @@ "clean": "backstage-cli package clean" }, "dependencies": { + "@apollo/client": "^3.0.0", + "@apollo/server": "^4.0.0", "@backstage/catalog-model": "workspace:^", "@backstage/config": "workspace:^", "@backstage/types": "workspace:^", - "apollo-server": "^3.0.0", "graphql": "^16.0.0", "graphql-modules": "^2.0.0", "graphql-tag": "^2.11.0", diff --git a/plugins/catalog-graphql/src/graphql/module.test.ts b/plugins/catalog-graphql/src/graphql/module.test.ts index 5490c2030a..d4589a2625 100644 --- a/plugins/catalog-graphql/src/graphql/module.test.ts +++ b/plugins/catalog-graphql/src/graphql/module.test.ts @@ -22,7 +22,7 @@ import { ConfigReader } from '@backstage/config'; import { ReaderEntity } from '../service/client'; import { createLogger } from 'winston'; import { setupRequestMockHandlers } from '@backstage/test-utils'; -import { gql } from 'apollo-server'; +import { gql } from '@apollo/client'; import { Module, createApplication, testkit } from 'graphql-modules'; describe('Catalog Module', () => { diff --git a/plugins/catalog-import/CHANGELOG.md b/plugins/catalog-import/CHANGELOG.md index d29890d836..2298180278 100644 --- a/plugins/catalog-import/CHANGELOG.md +++ b/plugins/catalog-import/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-catalog-import +## 0.9.7-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/integration-react@1.1.12-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/plugin-catalog-common@1.0.12 + ## 0.9.6 ### Patch Changes diff --git a/plugins/catalog-import/package.json b/plugins/catalog-import/package.json index a9e38367b9..d27a6118bd 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.6", + "version": "0.9.7-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -44,7 +44,7 @@ "@backstage/plugin-catalog-react": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "@octokit/rest": "^19.0.3", "git-url-parse": "^13.0.0", "js-base64": "^3.6.0", diff --git a/plugins/catalog-node/CHANGELOG.md b/plugins/catalog-node/CHANGELOG.md index 71333f339c..e38a38d596 100644 --- a/plugins/catalog-node/CHANGELOG.md +++ b/plugins/catalog-node/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-catalog-node +## 1.3.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/types@1.0.2 + - @backstage/plugin-catalog-common@1.0.12 + ## 1.3.4 ### Patch Changes diff --git a/plugins/catalog-node/package.json b/plugins/catalog-node/package.json index e95258f59b..31b7032462 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.3.4", + "version": "1.3.5-next.0", "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 1436ea2b2f..f7a96b5f07 100644 --- a/plugins/catalog-react/CHANGELOG.md +++ b/plugins/catalog-react/CHANGELOG.md @@ -1,5 +1,24 @@ # @backstage/plugin-catalog-react +## 1.4.1-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/integration@1.4.3 + - @backstage/plugin-permission-react@0.4.11 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + - @backstage/types@1.0.2 + - @backstage/version-bridge@1.0.3 + - @backstage/plugin-catalog-common@1.0.12 + - @backstage/plugin-permission-common@0.7.4 + ## 1.4.0 ### Minor Changes diff --git a/plugins/catalog-react/package.json b/plugins/catalog-react/package.json index a905dea1f6..166da09118 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.4.0", + "version": "1.4.1-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -59,7 +59,7 @@ "@backstage/version-bridge": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "classnames": "^2.2.6", "jwt-decode": "^3.1.0", "lodash": "^4.17.21", diff --git a/plugins/catalog/CHANGELOG.md b/plugins/catalog/CHANGELOG.md index 239a7e6057..d7cd7cbe3a 100644 --- a/plugins/catalog/CHANGELOG.md +++ b/plugins/catalog/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-catalog +## 1.10.0-next.0 + +### Minor Changes + +- 4dbf3d3e4da: Added a new EntitySwitch isResourceType to allow different views depending on Resource type +- fc6cab4eb48: Added `isEntityWith` condition helper for `EntitySwitch` case statements. + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-search-react@1.5.2-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/integration-react@1.1.12-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + - @backstage/types@1.0.2 + - @backstage/plugin-catalog-common@1.0.12 + - @backstage/plugin-search-common@1.2.2 + ## 1.9.0 ### Minor Changes diff --git a/plugins/catalog/api-report.md b/plugins/catalog/api-report.md index d891ebb7c8..ca91296913 100644 --- a/plugins/catalog/api-report.md +++ b/plugins/catalog/api-report.md @@ -355,6 +355,14 @@ export const EntityListContainer: (props: { // @public export function EntityOrphanWarning(): JSX.Element; +// @public (undocumented) +export interface EntityPredicates { + // (undocumented) + kind?: string | string[]; + // (undocumented) + type?: string | string[]; +} + // @public export function EntityProcessingErrorsPanel(): JSX.Element | null; @@ -433,6 +441,11 @@ export function isComponentType( types: string | string[], ): (entity: Entity) => boolean; +// @public +export function isEntityWith( + predicate: EntityPredicates, +): (entity: Entity) => boolean; + // @public export function isKind(kinds: string | string[]): (entity: Entity) => boolean; @@ -444,6 +457,11 @@ export function isNamespace( // @public export function isOrphan(entity: Entity): boolean; +// @public +export function isResourceType( + types: string | string[], +): (entity: Entity) => boolean; + // @public (undocumented) export type PluginCatalogComponentsNameToClassKey = { PluginCatalogEntityLinksEmptyState: EntityLinksEmptyStateClassKey; diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json index 782ab6051a..49242b8724 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.9.0", + "version": "1.10.0-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -46,7 +46,7 @@ "@backstage/types": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "history": "^5.0.0", "lodash": "^4.17.21", "pluralize": "^8.0.0", diff --git a/plugins/catalog/src/components/EntitySwitch/conditions.test.ts b/plugins/catalog/src/components/EntitySwitch/conditions.test.ts index dfed546fd8..66408aec18 100644 --- a/plugins/catalog/src/components/EntitySwitch/conditions.test.ts +++ b/plugins/catalog/src/components/EntitySwitch/conditions.test.ts @@ -15,7 +15,34 @@ */ import { Entity } from '@backstage/catalog-model'; -import { isComponentType, isKind, isNamespace } from './conditions'; +import { + isComponentType, + isKind, + isNamespace, + isResourceType, + isEntityWith, +} from './conditions'; + +const kubernetesClusterResource: Entity = { + apiVersion: '', + kind: 'Resource', + metadata: { name: 'aKubernetesCluster' }, + spec: { type: 'kubernetes-cluster' }, +}; + +const databaseResource: Entity = { + apiVersion: '', + kind: 'Resource', + metadata: { name: 'aDatabase' }, + spec: { type: 'database' }, +}; + +const notResource: Entity = { + apiVersion: '', + kind: 'not-Resource', + metadata: { name: 'aService' }, + spec: { type: 'service' }, +}; const serviceComponent: Entity = { apiVersion: '', @@ -38,6 +65,13 @@ const notComponent: Entity = { spec: { type: 'service' }, }; +const missingSpecType: Entity = { + apiVersion: '', + kind: 'another-type', + metadata: { name: 'anEntity' }, + spec: {}, +}; + const apiKind: Entity = { apiVersion: '', kind: 'api', @@ -59,6 +93,26 @@ const bNamespace: Entity = { spec: { type: 'service' }, }; +describe('isResourceType', () => { + it('should false on non resource kinds', () => { + const checkEntity = isResourceType('kubernetes-cluster'); + + expect(checkEntity(notResource)).not.toBeTruthy(); + }); + it('should check for the intended type', () => { + const checkEntity = isResourceType('kubernetes-cluster'); + + expect(checkEntity(databaseResource)).not.toBeTruthy(); + expect(checkEntity(kubernetesClusterResource)).toBeTruthy(); + }); + it('should check for multiple types', () => { + const checkEntity = isResourceType(['database', 'kubernetes-cluster']); + + expect(checkEntity(databaseResource)).toBeTruthy(); + expect(checkEntity(kubernetesClusterResource)).toBeTruthy(); + }); +}); + describe('isComponentType', () => { it('should false on non component kinds', () => { const checkEntity = isComponentType('service'); @@ -79,6 +133,25 @@ describe('isComponentType', () => { }); }); +describe('isEntityWith', () => { + it('allows for a kind-only check (empty type array)', () => { + const checkEntity = isEntityWith({ kind: 'api', type: [] }); + expect(checkEntity(apiKind)).toBeTruthy(); + }); + it('handles missing spec.type field', () => { + const checkEntity = isEntityWith({ kind: 'another-type', type: 'service' }); + expect(checkEntity(missingSpecType)).not.toBeTruthy(); + }); + it('allows a check against no criteria', () => { + const checkEntity = isEntityWith({}); + expect(checkEntity(apiKind)).toBeTruthy(); + }); + it('allows a check against empty criteria', () => { + const checkEntity = isEntityWith({ kind: [], type: [] }); + expect(checkEntity(apiKind)).toBeTruthy(); + }); +}); + describe('isKind', () => { it('should check for the intended kind', () => { const checkEntity = isKind('component'); diff --git a/plugins/catalog/src/components/EntitySwitch/conditions.ts b/plugins/catalog/src/components/EntitySwitch/conditions.ts index 86fd38a900..f834804141 100644 --- a/plugins/catalog/src/components/EntitySwitch/conditions.ts +++ b/plugins/catalog/src/components/EntitySwitch/conditions.ts @@ -14,18 +14,26 @@ * limitations under the License. */ -import { ComponentEntity, Entity } from '@backstage/catalog-model'; +import { Entity } from '@backstage/catalog-model'; -function strCmp(a: string | undefined, b: string | undefined): boolean { +/** @public */ +export interface EntityPredicates { + kind?: string | string[]; + type?: string | string[]; +} + +function strCmp(a: unknown, b: string | undefined): boolean { return Boolean( - a && a?.toLocaleLowerCase('en-US') === b?.toLocaleLowerCase('en-US'), + a && + typeof a === 'string' && + a?.toLocaleLowerCase('en-US') === b?.toLocaleLowerCase('en-US'), ); } -function strCmpAll(value: string | undefined, cmpValues: string | string[]) { +function strCmpAll(value: unknown, cmpValues: string | string[]) { return typeof cmpValues === 'string' ? strCmp(value, cmpValues) - : cmpValues.some(cmpVal => strCmp(value, cmpVal)); + : cmpValues.length === 0 || cmpValues.some(cmpVal => strCmp(value, cmpVal)); } /** @@ -33,7 +41,7 @@ function strCmpAll(value: string | undefined, cmpValues: string | string[]) { * @public */ export function isKind(kinds: string | string[]) { - return (entity: Entity) => strCmpAll(entity.kind, kinds); + return isEntityWith({ kind: kinds }); } /** @@ -41,12 +49,33 @@ export function isKind(kinds: string | string[]) { * @public */ export function isComponentType(types: string | string[]) { + return isEntityWith({ kind: 'component', type: types }); +} + +/** + * For use in EntitySwitch.Case. Matches if the entity is a Resource of a given spec.type. + * @public + */ +export function isResourceType(types: string | string[]) { + return isEntityWith({ kind: 'resource', type: types }); +} + +/** + * For use in EntitySwitch.Case. Matches if the entity is the specified kind and type (if present). + * @public + */ +export function isEntityWith(predicate: EntityPredicates) { return (entity: Entity) => { - if (!strCmp(entity.kind, 'component')) { + if (predicate.kind && !strCmpAll(entity.kind, predicate.kind)) { return false; } - const componentEntity = entity as ComponentEntity; - return strCmpAll(componentEntity.spec.type, types); + + if (predicate.type && !strCmpAll(entity.spec?.type, predicate.type)) { + return false; + } + + // there's no type check, return true + return true; }; } diff --git a/plugins/catalog/src/components/EntitySwitch/index.ts b/plugins/catalog/src/components/EntitySwitch/index.ts index 6cccf4be6e..8848f98866 100644 --- a/plugins/catalog/src/components/EntitySwitch/index.ts +++ b/plugins/catalog/src/components/EntitySwitch/index.ts @@ -16,4 +16,11 @@ export { EntitySwitch } from './EntitySwitch'; export type { EntitySwitchProps, EntitySwitchCaseProps } from './EntitySwitch'; -export { isKind, isNamespace, isComponentType } from './conditions'; +export type { EntityPredicates } from './conditions'; +export { + isKind, + isNamespace, + isComponentType, + isResourceType, + isEntityWith, +} from './conditions'; diff --git a/plugins/cicd-statistics-module-gitlab/CHANGELOG.md b/plugins/cicd-statistics-module-gitlab/CHANGELOG.md index a8519377a6..f68f624292 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.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-cicd-statistics@0.1.19-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + ## 0.1.12 ### Patch Changes diff --git a/plugins/cicd-statistics-module-gitlab/package.json b/plugins/cicd-statistics-module-gitlab/package.json index 8144319eaa..3cef2e0ff7 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.12", + "version": "0.1.13-next.0", "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 bc91b2611b..86c2579da9 100644 --- a/plugins/cicd-statistics/CHANGELOG.md +++ b/plugins/cicd-statistics/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-cicd-statistics +## 0.1.19-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + ## 0.1.18 ### Patch Changes diff --git a/plugins/cicd-statistics/package.json b/plugins/cicd-statistics/package.json index 967aa89f7c..1a531cbf88 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.18", + "version": "0.1.19-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -43,7 +43,7 @@ "@date-io/luxon": "^1.3.13", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "@material-ui/pickers": "^3.3.10", "already": "^3.2.0", "humanize-duration": "^3.27.0", diff --git a/plugins/circleci/CHANGELOG.md b/plugins/circleci/CHANGELOG.md index 93dd50f6be..7dc02638c4 100644 --- a/plugins/circleci/CHANGELOG.md +++ b/plugins/circleci/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-circleci +## 0.3.17-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + ## 0.3.16 ### Patch Changes diff --git a/plugins/circleci/package.json b/plugins/circleci/package.json index 6f093a24b3..5f74d66245 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.16", + "version": "0.3.17-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -40,7 +40,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "circleci-api": "^4.0.0", "humanize-duration": "^3.27.0", "lodash": "^4.17.21", diff --git a/plugins/circleci/src/index.ts b/plugins/circleci/src/index.ts index e20f5c7d6b..442f774b68 100644 --- a/plugins/circleci/src/index.ts +++ b/plugins/circleci/src/index.ts @@ -15,7 +15,7 @@ */ /** - * A Backstage plugin that integrates towards Circle CI + * A Backstage plugin that integrates towards CircleCI. * * @packageDocumentation */ diff --git a/plugins/cloudbuild/CHANGELOG.md b/plugins/cloudbuild/CHANGELOG.md index 935cb3e7bb..e1131349cf 100644 --- a/plugins/cloudbuild/CHANGELOG.md +++ b/plugins/cloudbuild/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-cloudbuild +## 0.3.17-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + ## 0.3.16 ### Patch Changes diff --git a/plugins/cloudbuild/package.json b/plugins/cloudbuild/package.json index 153c0a69b6..87b76043d2 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.16", + "version": "0.3.17-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -40,7 +40,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "luxon": "^3.0.0", "qs": "^6.9.4", "react-use": "^17.2.4" diff --git a/plugins/code-climate/CHANGELOG.md b/plugins/code-climate/CHANGELOG.md index 59599c528e..f84df1f4fd 100644 --- a/plugins/code-climate/CHANGELOG.md +++ b/plugins/code-climate/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-code-climate +## 0.1.17-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + ## 0.1.16 ### Patch Changes diff --git a/plugins/code-climate/package.json b/plugins/code-climate/package.json index 9ba3f290cf..1b75d7c59d 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.16", + "version": "0.1.17-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -29,7 +29,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "humanize-duration": "^3.27.1", "luxon": "^3.0.0", "react-use": "^17.2.4" diff --git a/plugins/code-coverage-backend/CHANGELOG.md b/plugins/code-coverage-backend/CHANGELOG.md index 65a9ce5a60..9f498b3687 100644 --- a/plugins/code-coverage-backend/CHANGELOG.md +++ b/plugins/code-coverage-backend/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-code-coverage-backend +## 0.2.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + ## 0.2.9 ### Patch Changes diff --git a/plugins/code-coverage-backend/package.json b/plugins/code-coverage-backend/package.json index affbfb79b9..dd4dac88c8 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.9", + "version": "0.2.10-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/code-coverage/CHANGELOG.md b/plugins/code-coverage/CHANGELOG.md index 8782089171..dfa39648c7 100644 --- a/plugins/code-coverage/CHANGELOG.md +++ b/plugins/code-coverage/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-code-coverage +## 0.2.10-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/config@1.0.7 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + ## 0.2.9 ### Patch Changes diff --git a/plugins/code-coverage/package.json b/plugins/code-coverage/package.json index b51862702c..e09a20355e 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.9", + "version": "0.2.10-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,7 +32,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "@material-ui/styles": "^4.11.0", "highlight.js": "^10.6.0", "luxon": "^3.0.0", diff --git a/plugins/codescene/CHANGELOG.md b/plugins/codescene/CHANGELOG.md index b6f69daacb..f854b3f22d 100644 --- a/plugins/codescene/CHANGELOG.md +++ b/plugins/codescene/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-codescene +## 0.1.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/config@1.0.7 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + ## 0.1.11 ### Patch Changes diff --git a/plugins/codescene/package.json b/plugins/codescene/package.json index f7d132affa..3e688063fc 100644 --- a/plugins/codescene/package.json +++ b/plugins/codescene/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-codescene", - "version": "0.1.11", + "version": "0.1.12-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -29,7 +29,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "^4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "rc-progress": "3.4.1", "react-use": "^17.2.4" }, diff --git a/plugins/config-schema/CHANGELOG.md b/plugins/config-schema/CHANGELOG.md index e78a82a633..e4e81e46c0 100644 --- a/plugins/config-schema/CHANGELOG.md +++ b/plugins/config-schema/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-config-schema +## 0.1.40-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/config@1.0.7 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + - @backstage/types@1.0.2 + ## 0.1.39 ### Patch Changes diff --git a/plugins/config-schema/package.json b/plugins/config-schema/package.json index cb543cd3a2..13222fd55d 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.39", + "version": "0.1.40-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,7 +31,7 @@ "@backstage/types": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "jsonschema": "^1.2.6", "react-use": "^17.2.4", "zen-observable": "^0.10.0" diff --git a/plugins/cost-insights/CHANGELOG.md b/plugins/cost-insights/CHANGELOG.md index 2cf77c9aa9..8d459fb000 100644 --- a/plugins/cost-insights/CHANGELOG.md +++ b/plugins/cost-insights/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-cost-insights +## 0.12.6-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/config@1.0.7 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + - @backstage/plugin-cost-insights-common@0.1.1 + ## 0.12.5 ### Patch Changes diff --git a/plugins/cost-insights/package.json b/plugins/cost-insights/package.json index 6d35d006a9..aef2c7635e 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.5", + "version": "0.12.6-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -41,7 +41,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "@material-ui/styles": "^4.9.6", "@types/recharts": "^1.8.14", "classnames": "^2.2.6", diff --git a/plugins/dynatrace/CHANGELOG.md b/plugins/dynatrace/CHANGELOG.md index 451da29bf0..46fde4973e 100644 --- a/plugins/dynatrace/CHANGELOG.md +++ b/plugins/dynatrace/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-dynatrace +## 3.0.1-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + ## 3.0.0 ### Patch Changes diff --git a/plugins/dynatrace/README.md b/plugins/dynatrace/README.md index df6bb75f10..b07fe985fe 100644 --- a/plugins/dynatrace/README.md +++ b/plugins/dynatrace/README.md @@ -49,7 +49,7 @@ const serviceEntityPage = ( + > + + - + ) ``` diff --git a/plugins/dynatrace/api-report.md b/plugins/dynatrace/api-report.md index 1677318a9f..1dded736ad 100644 --- a/plugins/dynatrace/api-report.md +++ b/plugins/dynatrace/api-report.md @@ -16,6 +16,4 @@ export const DynatraceTab: () => JSX.Element; // @public export const isDynatraceAvailable: (entity: Entity) => boolean; - -// (No @packageDocumentation comment for this package) ``` diff --git a/plugins/dynatrace/package.json b/plugins/dynatrace/package.json index b4a9e76c59..d01e7eafad 100644 --- a/plugins/dynatrace/package.json +++ b/plugins/dynatrace/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-dynatrace", - "version": "3.0.0", + "version": "3.0.1-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,7 +33,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "react-use": "^17.2.4" }, "peerDependencies": { diff --git a/plugins/dynatrace/src/index.ts b/plugins/dynatrace/src/index.ts index 0c5da219a5..90688a544f 100644 --- a/plugins/dynatrace/src/index.ts +++ b/plugins/dynatrace/src/index.ts @@ -14,4 +14,10 @@ * limitations under the License. */ +/** + * A Backstage plugin that integrates towards Dynatrace. + * + * @packageDocumentation + */ + export { dynatracePlugin, DynatraceTab, isDynatraceAvailable } from './plugin'; diff --git a/plugins/entity-feedback-backend/CHANGELOG.md b/plugins/entity-feedback-backend/CHANGELOG.md index 2bf4189393..f076d9e130 100644 --- a/plugins/entity-feedback-backend/CHANGELOG.md +++ b/plugins/entity-feedback-backend/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-entity-feedback-backend +## 0.1.2-next.0 + +### Patch Changes + +- 7eba760e6f6: Added an endpoint to fetch anonymous aggregated results from an entity +- Updated dependencies + - @backstage/plugin-entity-feedback-common@0.1.1-next.0 + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/plugin-auth-node@0.2.13-next.0 + ## 0.1.1 ### Patch Changes diff --git a/plugins/entity-feedback-backend/package.json b/plugins/entity-feedback-backend/package.json index 48ab43af9f..aa88dea67f 100644 --- a/plugins/entity-feedback-backend/package.json +++ b/plugins/entity-feedback-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-entity-feedback-backend", - "version": "0.1.1", + "version": "0.1.2-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/entity-feedback-backend/src/service/router.test.ts b/plugins/entity-feedback-backend/src/service/router.test.ts index 74fae8248b..5df0c5cf9d 100644 --- a/plugins/entity-feedback-backend/src/service/router.test.ts +++ b/plugins/entity-feedback-backend/src/service/router.test.ts @@ -258,6 +258,22 @@ describe('createRouter', () => { }); }); + describe('GET /ratings/:entityRef/aggregate', () => { + it('should get aggregated ratings for an entity correctly', async () => { + const response = await request(app) + .get('/ratings/component%3Adefault%2Fservice/aggregate') + .send(); + expect(mockDbHandler.getRatings).toHaveBeenCalledWith( + 'component:default/service', + ); + expect(response.status).toEqual(200); + expect(response.body).toEqual({ + DISLIKE: 1, + LIKE: 2, + }); + }); + }); + describe('POST /responses/:entityRef', () => { it('should record a response correctly', async () => { const body = { response: 'blah', comments: 'feedback', consent: true }; diff --git a/plugins/entity-feedback-backend/src/service/router.ts b/plugins/entity-feedback-backend/src/service/router.ts index e1243cedaf..ea759c1639 100644 --- a/plugins/entity-feedback-backend/src/service/router.ts +++ b/plugins/entity-feedback-backend/src/service/router.ts @@ -25,7 +25,10 @@ import { getBearerTokenFromAuthorizationHeader, IdentityApi, } from '@backstage/plugin-auth-node'; -import { EntityRatingsData } from '@backstage/plugin-entity-feedback-common'; +import { + EntityRatingsData, + Ratings, +} from '@backstage/plugin-entity-feedback-common'; import express from 'express'; import Router from 'express-promise-router'; import { Logger } from 'winston'; @@ -167,6 +170,19 @@ export async function createRouter( res.json(ratings.filter(r => accessibleEntityRefs.includes(r.userRef))); }); + router.get('/ratings/:entityRef/aggregate', async (req, res) => { + const entityRatings = ( + await dbHandler.getRatings(req.params.entityRef) + ).reduce((ratings: Ratings, { rating }) => { + ratings[rating] = ratings[rating] ?? 0; + ratings[rating]++; + + return ratings; + }, {}); + + res.json(entityRatings); + }); + router.post('/responses/:entityRef', async (req, res) => { const user = await identity.getIdentity({ request: req }); const { response, comments, consent } = req.body; diff --git a/plugins/entity-feedback-common/CHANGELOG.md b/plugins/entity-feedback-common/CHANGELOG.md index e646a4322d..ef373767ca 100644 --- a/plugins/entity-feedback-common/CHANGELOG.md +++ b/plugins/entity-feedback-common/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/plugin-entity-feedback-common +## 0.1.1-next.0 + +### Patch Changes + +- 7eba760e6f6: Added an endpoint to fetch anonymous aggregated results from an entity + ## 0.1.0 ### Minor Changes diff --git a/plugins/entity-feedback-common/api-report.md b/plugins/entity-feedback-common/api-report.md index 118e6c78f2..f31bb0d041 100644 --- a/plugins/entity-feedback-common/api-report.md +++ b/plugins/entity-feedback-common/api-report.md @@ -10,9 +10,7 @@ export interface EntityRatingsData { // (undocumented) entityTitle?: string; // (undocumented) - ratings: { - [ratingValue: string]: number; - }; + ratings: Ratings; } // @public (undocumented) @@ -38,4 +36,10 @@ export interface Rating { // (undocumented) userRef: string; } + +// @public (undocumented) +export interface Ratings { + // (undocumented) + [ratingValue: string]: number; +} ``` diff --git a/plugins/entity-feedback-common/package.json b/plugins/entity-feedback-common/package.json index 45a5a2b131..b1fbb3f686 100644 --- a/plugins/entity-feedback-common/package.json +++ b/plugins/entity-feedback-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-entity-feedback-common", "description": "Common functionalities for the entity-feedback plugin", - "version": "0.1.0", + "version": "0.1.1-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/entity-feedback-common/src/index.ts b/plugins/entity-feedback-common/src/index.ts index eea289a899..247a5a5d54 100644 --- a/plugins/entity-feedback-common/src/index.ts +++ b/plugins/entity-feedback-common/src/index.ts @@ -40,13 +40,18 @@ export interface FeedbackResponse { userRef: string; } +/** + * @public + */ +export interface Ratings { + [ratingValue: string]: number; +} + /** * @public */ export interface EntityRatingsData { entityRef: string; entityTitle?: string; - ratings: { - [ratingValue: string]: number; - }; + ratings: Ratings; } diff --git a/plugins/entity-feedback/CHANGELOG.md b/plugins/entity-feedback/CHANGELOG.md index e19b5e17b1..1fa0d920ab 100644 --- a/plugins/entity-feedback/CHANGELOG.md +++ b/plugins/entity-feedback/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-entity-feedback +## 0.2.0-next.0 + +### Minor Changes + +- 7eba760e6f6: Added an endpoint to fetch anonymous aggregated results from an entity + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/plugin-entity-feedback-common@0.1.1-next.0 + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + ## 0.1.1 ### Patch Changes diff --git a/plugins/entity-feedback/api-report.md b/plugins/entity-feedback/api-report.md index 06b0166b0d..696536aef4 100644 --- a/plugins/entity-feedback/api-report.md +++ b/plugins/entity-feedback/api-report.md @@ -13,6 +13,7 @@ import { EntityRatingsData } from '@backstage/plugin-entity-feedback-common'; import { FeedbackResponse } from '@backstage/plugin-entity-feedback-common'; import { FetchApi } from '@backstage/core-plugin-api'; import { Rating } from '@backstage/plugin-entity-feedback-common'; +import { Ratings } from '@backstage/plugin-entity-feedback-common'; import { ReactNode } from 'react'; import { RouteRef } from '@backstage/core-plugin-api'; @@ -22,6 +23,7 @@ export interface EntityFeedbackApi { getAllRatings(): Promise; // (undocumented) getOwnedRatings(ownerRef: string): Promise; + getRatingAggregates(entityRef: string): Promise; // (undocumented) getRatings(entityRef: string): Promise[]>; // (undocumented) @@ -48,6 +50,8 @@ export class EntityFeedbackClient implements EntityFeedbackApi { // (undocumented) getOwnedRatings(ownerRef: string): Promise; // (undocumented) + getRatingAggregates(entityRef: string): Promise; + // (undocumented) getRatings(entityRef: string): Promise[]>; // (undocumented) getResponses( diff --git a/plugins/entity-feedback/package.json b/plugins/entity-feedback/package.json index ba88e02b70..bac96f561c 100644 --- a/plugins/entity-feedback/package.json +++ b/plugins/entity-feedback/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-entity-feedback", - "version": "0.1.1", + "version": "0.2.0-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -36,7 +36,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.9.13", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "react-use": "^17.2.4" }, "peerDependencies": { diff --git a/plugins/entity-feedback/src/api/EntityFeedbackApi.ts b/plugins/entity-feedback/src/api/EntityFeedbackApi.ts index d2f1a46f55..7ec6a447f0 100644 --- a/plugins/entity-feedback/src/api/EntityFeedbackApi.ts +++ b/plugins/entity-feedback/src/api/EntityFeedbackApi.ts @@ -19,6 +19,7 @@ import { EntityRatingsData, FeedbackResponse, Rating, + Ratings, } from '@backstage/plugin-entity-feedback-common'; /** @@ -40,6 +41,11 @@ export interface EntityFeedbackApi { getRatings(entityRef: string): Promise[]>; + /** + * Returns anonymized aggregated results for one entityRef + */ + getRatingAggregates(entityRef: string): Promise; + recordResponse( entityRef: string, response: Omit, diff --git a/plugins/entity-feedback/src/api/EntityFeedbackClient.test.ts b/plugins/entity-feedback/src/api/EntityFeedbackClient.test.ts index 694fd66b06..8ef6810115 100644 --- a/plugins/entity-feedback/src/api/EntityFeedbackClient.test.ts +++ b/plugins/entity-feedback/src/api/EntityFeedbackClient.test.ts @@ -121,6 +121,24 @@ describe('EntityFeedbackClient', () => { expect(response).toEqual(ratings); }); + it('getRatingAggregates', async () => { + const ratings = { LIKE: 3, DISLIKE: 5 }; + + server.use( + rest.get( + `${mockBaseUrl}/ratings/${encodeURIComponent( + 'component:default/service', + )}/aggregate`, + (_, res, ctx) => res(ctx.json(ratings)), + ), + ); + + const response = await client.getRatingAggregates( + 'component:default/service', + ); + expect(response).toEqual(ratings); + }); + it('recordResponse', async () => { expect.assertions(1); const response = { diff --git a/plugins/entity-feedback/src/api/EntityFeedbackClient.ts b/plugins/entity-feedback/src/api/EntityFeedbackClient.ts index 34856473c8..f911cdc7f8 100644 --- a/plugins/entity-feedback/src/api/EntityFeedbackClient.ts +++ b/plugins/entity-feedback/src/api/EntityFeedbackClient.ts @@ -20,6 +20,7 @@ import { EntityRatingsData, FeedbackResponse, Rating, + Ratings, } from '@backstage/plugin-entity-feedback-common'; import { EntityFeedbackApi } from './EntityFeedbackApi'; @@ -97,6 +98,22 @@ export class EntityFeedbackClient implements EntityFeedbackApi { return resp.json(); } + async getRatingAggregates(entityRef: string): Promise { + const baseUrl = await this.discoveryApi.getBaseUrl('entity-feedback'); + const resp = await this.fetchApi.fetch( + `${baseUrl}/ratings/${encodeURIComponent(entityRef)}/aggregate`, + { + method: 'GET', + }, + ); + + if (!resp.ok) { + throw await ResponseError.fromResponse(resp); + } + + return resp.json(); + } + async recordResponse( entityRef: string, response: Omit, diff --git a/plugins/entity-validation/CHANGELOG.md b/plugins/entity-validation/CHANGELOG.md index a714918b45..dc7db0eaec 100644 --- a/plugins/entity-validation/CHANGELOG.md +++ b/plugins/entity-validation/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-entity-validation +## 0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + - @backstage/plugin-catalog-common@1.0.12 + ## 0.1.1 ### Patch Changes diff --git a/plugins/entity-validation/package.json b/plugins/entity-validation/package.json index c7cd754547..811f9ab3c8 100644 --- a/plugins/entity-validation/package.json +++ b/plugins/entity-validation/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-entity-validation", - "version": "0.1.1", + "version": "0.1.2-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -40,7 +40,7 @@ "@codemirror/view": "^6.0.0", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "^4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "@react-hookz/web": "^20.0.0", "@uiw/react-codemirror": "^4.9.3", "lodash": "^4.17.21", diff --git a/plugins/events-backend-module-aws-sqs/CHANGELOG.md b/plugins/events-backend-module-aws-sqs/CHANGELOG.md index ac076e463b..2dc726e160 100644 --- a/plugins/events-backend-module-aws-sqs/CHANGELOG.md +++ b/plugins/events-backend-module-aws-sqs/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-events-backend-module-aws-sqs +## 0.1.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/types@1.0.2 + - @backstage/plugin-events-node@0.2.5-next.0 + ## 0.1.5 ### Patch Changes diff --git a/plugins/events-backend-module-aws-sqs/package.json b/plugins/events-backend-module-aws-sqs/package.json index 046d3363d2..a90dafadde 100644 --- a/plugins/events-backend-module-aws-sqs/package.json +++ b/plugins/events-backend-module-aws-sqs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-aws-sqs", - "version": "0.1.5", + "version": "0.1.6-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/events-backend-module-azure/CHANGELOG.md b/plugins/events-backend-module-azure/CHANGELOG.md index cf3de9b750..35560f1156 100644 --- a/plugins/events-backend-module-azure/CHANGELOG.md +++ b/plugins/events-backend-module-azure/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-events-backend-module-azure +## 0.1.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/plugin-events-node@0.2.5-next.0 + ## 0.1.5 ### Patch Changes diff --git a/plugins/events-backend-module-azure/package.json b/plugins/events-backend-module-azure/package.json index 6ac861253a..2b66bd1421 100644 --- a/plugins/events-backend-module-azure/package.json +++ b/plugins/events-backend-module-azure/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-azure", - "version": "0.1.5", + "version": "0.1.6-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md b/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md index be247852e9..8189dc2b99 100644 --- a/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md +++ b/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-events-backend-module-bitbucket-cloud +## 0.1.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/plugin-events-node@0.2.5-next.0 + ## 0.1.5 ### Patch Changes diff --git a/plugins/events-backend-module-bitbucket-cloud/package.json b/plugins/events-backend-module-bitbucket-cloud/package.json index 5a908876cb..e575d325ff 100644 --- a/plugins/events-backend-module-bitbucket-cloud/package.json +++ b/plugins/events-backend-module-bitbucket-cloud/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-bitbucket-cloud", - "version": "0.1.5", + "version": "0.1.6-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/events-backend-module-gerrit/CHANGELOG.md b/plugins/events-backend-module-gerrit/CHANGELOG.md index 7388fe6c96..82bf56ef32 100644 --- a/plugins/events-backend-module-gerrit/CHANGELOG.md +++ b/plugins/events-backend-module-gerrit/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-events-backend-module-gerrit +## 0.1.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/plugin-events-node@0.2.5-next.0 + ## 0.1.5 ### Patch Changes diff --git a/plugins/events-backend-module-gerrit/package.json b/plugins/events-backend-module-gerrit/package.json index 3666179cd1..95612d2aab 100644 --- a/plugins/events-backend-module-gerrit/package.json +++ b/plugins/events-backend-module-gerrit/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-gerrit", - "version": "0.1.5", + "version": "0.1.6-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/events-backend-module-github/CHANGELOG.md b/plugins/events-backend-module-github/CHANGELOG.md index f20041f8d8..d281e432df 100644 --- a/plugins/events-backend-module-github/CHANGELOG.md +++ b/plugins/events-backend-module-github/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-events-backend-module-github +## 0.1.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.0.7 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/plugin-events-node@0.2.5-next.0 + ## 0.1.5 ### Patch Changes diff --git a/plugins/events-backend-module-github/package.json b/plugins/events-backend-module-github/package.json index cbe8713836..7ec3660013 100644 --- a/plugins/events-backend-module-github/package.json +++ b/plugins/events-backend-module-github/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-github", - "version": "0.1.5", + "version": "0.1.6-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/events-backend-module-gitlab/CHANGELOG.md b/plugins/events-backend-module-gitlab/CHANGELOG.md index 6d9895360d..9a47340948 100644 --- a/plugins/events-backend-module-gitlab/CHANGELOG.md +++ b/plugins/events-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-events-backend-module-gitlab +## 0.1.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.0.7 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/plugin-events-node@0.2.5-next.0 + ## 0.1.5 ### Patch Changes diff --git a/plugins/events-backend-module-gitlab/package.json b/plugins/events-backend-module-gitlab/package.json index 420bbb782e..3729fa4f24 100644 --- a/plugins/events-backend-module-gitlab/package.json +++ b/plugins/events-backend-module-gitlab/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-gitlab", - "version": "0.1.5", + "version": "0.1.6-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/events-backend-test-utils/CHANGELOG.md b/plugins/events-backend-test-utils/CHANGELOG.md index dad7faf979..04e373d809 100644 --- a/plugins/events-backend-test-utils/CHANGELOG.md +++ b/plugins/events-backend-test-utils/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-events-backend-test-utils +## 0.1.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.2.5-next.0 + ## 0.1.5 ### Patch Changes diff --git a/plugins/events-backend-test-utils/package.json b/plugins/events-backend-test-utils/package.json index 77cecd0219..6f7ec7c54d 100644 --- a/plugins/events-backend-test-utils/package.json +++ b/plugins/events-backend-test-utils/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-events-backend-test-utils", "description": "The plugin-events-backend-test-utils for @backstage/plugin-events-node", - "version": "0.1.5", + "version": "0.1.6-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/events-backend/CHANGELOG.md b/plugins/events-backend/CHANGELOG.md index 0b72628ccf..af29213c08 100644 --- a/plugins/events-backend/CHANGELOG.md +++ b/plugins/events-backend/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-events-backend +## 0.2.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/plugin-events-node@0.2.5-next.0 + ## 0.2.4 ### Patch Changes diff --git a/plugins/events-backend/package.json b/plugins/events-backend/package.json index d2abad4cb8..7fda105e15 100644 --- a/plugins/events-backend/package.json +++ b/plugins/events-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend", - "version": "0.2.4", + "version": "0.2.5-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/events-node/CHANGELOG.md b/plugins/events-node/CHANGELOG.md index 9b1599c25a..955ad8c4e0 100644 --- a/plugins/events-node/CHANGELOG.md +++ b/plugins/events-node/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-events-node +## 0.2.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.5.1-next.0 + ## 0.2.4 ### Patch Changes diff --git a/plugins/events-node/package.json b/plugins/events-node/package.json index 22c64dd012..930cd439e3 100644 --- a/plugins/events-node/package.json +++ b/plugins/events-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-events-node", "description": "The plugin-events-node module for @backstage/plugin-events-backend", - "version": "0.2.4", + "version": "0.2.5-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/example-todo-list-backend/CHANGELOG.md b/plugins/example-todo-list-backend/CHANGELOG.md index 65488cd80e..c0fd1fcb21 100644 --- a/plugins/example-todo-list-backend/CHANGELOG.md +++ b/plugins/example-todo-list-backend/CHANGELOG.md @@ -1,5 +1,16 @@ # @internal/plugin-todo-list-backend +## 1.0.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/errors@1.1.5 + - @backstage/plugin-auth-node@0.2.13-next.0 + ## 1.0.11 ### Patch Changes diff --git a/plugins/example-todo-list-backend/package.json b/plugins/example-todo-list-backend/package.json index 8baa490b31..d5a4a116e0 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.11", + "version": "1.0.12-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/example-todo-list/CHANGELOG.md b/plugins/example-todo-list/CHANGELOG.md index 022a8e8fb3..87fc367b86 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.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/theme@0.2.18 + ## 1.0.11 ### Patch Changes diff --git a/plugins/example-todo-list/package.json b/plugins/example-todo-list/package.json index 9c90b71b52..27e05d7144 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.11", + "version": "1.0.12-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -28,7 +28,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "react-use": "^17.2.4" }, "peerDependencies": { diff --git a/plugins/explore-backend/CHANGELOG.md b/plugins/explore-backend/CHANGELOG.md index be73174a06..950430d91f 100644 --- a/plugins/explore-backend/CHANGELOG.md +++ b/plugins/explore-backend/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-explore-backend +## 0.0.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/plugin-explore-common@0.0.1 + - @backstage/plugin-search-common@1.2.2 + ## 0.0.5 ### Patch Changes diff --git a/plugins/explore-backend/api-report.md b/plugins/explore-backend/api-report.md index cc112ed3cc..e3933e350b 100644 --- a/plugins/explore-backend/api-report.md +++ b/plugins/explore-backend/api-report.md @@ -3,18 +3,14 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts -/// - -import { Config } from '@backstage/config'; -import { DocumentCollatorFactory } from '@backstage/plugin-search-common'; import { ExploreTool } from '@backstage/plugin-explore-common'; import express from 'express'; import { GetExploreToolsRequest } from '@backstage/plugin-explore-common'; import { GetExploreToolsResponse } from '@backstage/plugin-explore-common'; -import { IndexableDocument } from '@backstage/plugin-search-common'; import { Logger } from 'winston'; -import { PluginEndpointDiscovery } from '@backstage/backend-common'; -import { Readable } from 'stream'; +import type { ToolDocument as ToolDocument_2 } from '@backstage/plugin-search-backend-module-explore'; +import { ToolDocumentCollatorFactory as ToolDocumentCollatorFactory_2 } from '@backstage/plugin-search-backend-module-explore'; +import type { ToolDocumentCollatorFactoryOptions as ToolDocumentCollatorFactoryOptions_2 } from '@backstage/plugin-search-backend-module-explore'; // @public (undocumented) export function createRouter(options: RouterOptions): Promise; @@ -40,27 +36,13 @@ export class StaticExploreToolProvider implements ExploreToolProvider { getTools(request: GetExploreToolsRequest): Promise; } -// @public -export interface ToolDocument extends IndexableDocument, ExploreTool {} +// @public @deprecated (undocumented) +export type ToolDocument = ToolDocument_2; -// @public -export class ToolDocumentCollatorFactory implements DocumentCollatorFactory { - // (undocumented) - execute(): AsyncGenerator; - // (undocumented) - static fromConfig( - _config: Config, - options: ToolDocumentCollatorFactoryOptions, - ): ToolDocumentCollatorFactory; - // (undocumented) - getCollator(): Promise; - // (undocumented) - readonly type: string; -} +// @public @deprecated (undocumented) +export const ToolDocumentCollatorFactory: typeof ToolDocumentCollatorFactory_2; -// @public -export type ToolDocumentCollatorFactoryOptions = { - discovery: PluginEndpointDiscovery; - logger: Logger; -}; +// @public @deprecated (undocumented) +export type ToolDocumentCollatorFactoryOptions = + ToolDocumentCollatorFactoryOptions_2; ``` diff --git a/plugins/explore-backend/package.json b/plugins/explore-backend/package.json index 00629c8da4..30ab27bf07 100644 --- a/plugins/explore-backend/package.json +++ b/plugins/explore-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-explore-backend", - "version": "0.0.5", + "version": "0.0.6-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -25,6 +25,7 @@ "@backstage/backend-common": "workspace:^", "@backstage/config": "workspace:^", "@backstage/plugin-explore-common": "workspace:^", + "@backstage/plugin-search-backend-module-explore": "workspace:^", "@backstage/plugin-search-common": "workspace:^", "@types/express": "*", "express": "^4.18.1", diff --git a/plugins/explore-backend/src/index.ts b/plugins/explore-backend/src/index.ts index a0e7216621..ca501db96b 100644 --- a/plugins/explore-backend/src/index.ts +++ b/plugins/explore-backend/src/index.ts @@ -20,7 +20,6 @@ * @packageDocumentation */ -export * from './search'; export * from './service'; export * from './tools'; @@ -28,3 +27,28 @@ export * from './tools'; * @internal Example only - do not use in production */ export { exampleTools } from './example/exampleTools'; + +import { ToolDocumentCollatorFactory as _ToolDocumentCollatorFactory } from '@backstage/plugin-search-backend-module-explore'; +import type { + ToolDocument as _ToolDocument, + ToolDocumentCollatorFactoryOptions as _ToolDocumentCollatorFactoryOptions, +} from '@backstage/plugin-search-backend-module-explore'; + +/** + * @public + * @deprecated import from `@backstage/search-backend-module-explore` instead + */ +export const ToolDocumentCollatorFactory = _ToolDocumentCollatorFactory; + +/** + * @public + * @deprecated import from `@backstage/search-backend-module-explore` instead + */ +export type ToolDocument = _ToolDocument; + +/** + * @public + * @deprecated import from `@backstage/search-backend-module-explore` instead + */ +export type ToolDocumentCollatorFactoryOptions = + _ToolDocumentCollatorFactoryOptions; diff --git a/plugins/explore/CHANGELOG.md b/plugins/explore/CHANGELOG.md index 46cf23bc90..f5cbde7200 100644 --- a/plugins/explore/CHANGELOG.md +++ b/plugins/explore/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-explore +## 0.4.2-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-search-react@1.5.2-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/plugin-explore-react@0.0.27 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + - @backstage/plugin-explore-common@0.0.1 + - @backstage/plugin-search-common@1.2.2 + ## 0.4.1 ### Patch Changes diff --git a/plugins/explore/package.json b/plugins/explore/package.json index d14a276ecc..eb5e1da5b3 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.4.1", + "version": "0.4.2-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -44,7 +44,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "classnames": "^2.2.6", "react-use": "^17.2.4" }, diff --git a/plugins/firehydrant/CHANGELOG.md b/plugins/firehydrant/CHANGELOG.md index 2987daa5ff..50440aba5d 100644 --- a/plugins/firehydrant/CHANGELOG.md +++ b/plugins/firehydrant/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-firehydrant +## 0.2.1-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + ## 0.2.0 ### Minor Changes diff --git a/plugins/firehydrant/package.json b/plugins/firehydrant/package.json index 0aacc34906..2268ca77a1 100644 --- a/plugins/firehydrant/package.json +++ b/plugins/firehydrant/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-firehydrant", "description": "A Backstage plugin that integrates towards FireHydrant", - "version": "0.2.0", + "version": "0.2.1-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,7 +30,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "luxon": "^3.0.0", "react-use": "^17.2.4" }, diff --git a/plugins/fossa/CHANGELOG.md b/plugins/fossa/CHANGELOG.md index 7c713d6730..3cb8c21d6c 100644 --- a/plugins/fossa/CHANGELOG.md +++ b/plugins/fossa/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-fossa +## 0.2.49-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + ## 0.2.48 ### Patch Changes diff --git a/plugins/fossa/package.json b/plugins/fossa/package.json index 8d4b8bb7aa..f7d14a79aa 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.48", + "version": "0.2.49-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -41,7 +41,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "cross-fetch": "^3.1.5", "luxon": "^3.0.0", "p-limit": "^3.0.2", diff --git a/plugins/gcalendar/CHANGELOG.md b/plugins/gcalendar/CHANGELOG.md index d9d1021f02..e13f9f04eb 100644 --- a/plugins/gcalendar/CHANGELOG.md +++ b/plugins/gcalendar/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-gcalendar +## 0.3.13-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + ## 0.3.12 ### Patch Changes diff --git a/plugins/gcalendar/package.json b/plugins/gcalendar/package.json index 603936d75a..5a0508b41c 100644 --- a/plugins/gcalendar/package.json +++ b/plugins/gcalendar/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-gcalendar", - "version": "0.3.12", + "version": "0.3.13-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -28,7 +28,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "@maxim_mazurok/gapi.client.calendar": "^3.0.20220408", "@tanstack/react-query": "^4.1.3", "classnames": "^2.3.1", diff --git a/plugins/gcp-projects/CHANGELOG.md b/plugins/gcp-projects/CHANGELOG.md index b501db40d7..b952be109f 100644 --- a/plugins/gcp-projects/CHANGELOG.md +++ b/plugins/gcp-projects/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-gcp-projects +## 0.3.36-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/theme@0.2.18 + ## 0.3.35 ### Patch Changes diff --git a/plugins/gcp-projects/package.json b/plugins/gcp-projects/package.json index 162aff640c..516a72cbfa 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.35", + "version": "0.3.36-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -38,7 +38,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "@react-hookz/web": "^20.0.0" }, "peerDependencies": { diff --git a/plugins/git-release-manager/CHANGELOG.md b/plugins/git-release-manager/CHANGELOG.md index cec4a630bc..34e2e430ae 100644 --- a/plugins/git-release-manager/CHANGELOG.md +++ b/plugins/git-release-manager/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-git-release-manager +## 0.3.30-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/integration@1.4.3 + - @backstage/theme@0.2.18 + ## 0.3.29 ### Patch Changes diff --git a/plugins/git-release-manager/package.json b/plugins/git-release-manager/package.json index 53fca75a4f..b43ee73925 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.29", + "version": "0.3.30-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -29,7 +29,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "@octokit/rest": "^19.0.3", "luxon": "^3.0.0", "qs": "^6.10.1", diff --git a/plugins/github-actions/CHANGELOG.md b/plugins/github-actions/CHANGELOG.md index a8cf2cd18f..df186ba39d 100644 --- a/plugins/github-actions/CHANGELOG.md +++ b/plugins/github-actions/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-github-actions +## 0.5.17-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/integration@1.4.3 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + ## 0.5.16 ### Patch Changes diff --git a/plugins/github-actions/package.json b/plugins/github-actions/package.json index 48f20a6722..78c0f5096a 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.16", + "version": "0.5.17-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -42,7 +42,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "@octokit/rest": "^19.0.3", "luxon": "^3.0.0", "react-use": "^17.2.4" diff --git a/plugins/github-deployments/CHANGELOG.md b/plugins/github-deployments/CHANGELOG.md index a66a149b8b..47f7e4d86b 100644 --- a/plugins/github-deployments/CHANGELOG.md +++ b/plugins/github-deployments/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-github-deployments +## 0.1.48-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/integration-react@1.1.12-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/integration@1.4.3 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + ## 0.1.47 ### Patch Changes diff --git a/plugins/github-deployments/package.json b/plugins/github-deployments/package.json index 0d56c6bb1b..e60e3da91a 100644 --- a/plugins/github-deployments/package.json +++ b/plugins/github-deployments/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-github-deployments", "description": "A Backstage plugin that integrates towards GitHub Deployments", - "version": "0.1.47", + "version": "0.1.48-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,7 +33,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "@octokit/graphql": "^5.0.0", "luxon": "^3.0.0", "react-use": "^17.2.4" diff --git a/plugins/github-issues/CHANGELOG.md b/plugins/github-issues/CHANGELOG.md index 46352a55d2..affbf603a6 100644 --- a/plugins/github-issues/CHANGELOG.md +++ b/plugins/github-issues/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-github-issues +## 0.2.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/integration@1.4.3 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + ## 0.2.5 ### Patch Changes diff --git a/plugins/github-issues/package.json b/plugins/github-issues/package.json index 419a5babcb..cac335d9e3 100644 --- a/plugins/github-issues/package.json +++ b/plugins/github-issues/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-github-issues", - "version": "0.2.5", + "version": "0.2.6-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,7 +31,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.4", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "^4.0.0-alpha.61", + "@material-ui/lab": "4.0.0-alpha.61", "luxon": "^3.0.0", "octokit": "^2.0.4", "react-use": "^17.4.0" diff --git a/plugins/github-pull-requests-board/CHANGELOG.md b/plugins/github-pull-requests-board/CHANGELOG.md index 3480ae5f6e..681552a571 100644 --- a/plugins/github-pull-requests-board/CHANGELOG.md +++ b/plugins/github-pull-requests-board/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-github-pull-requests-board +## 0.1.11-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/integration@1.4.3 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + ## 0.1.10 ### Patch Changes diff --git a/plugins/github-pull-requests-board/package.json b/plugins/github-pull-requests-board/package.json index 689359ba1a..1792a6e98c 100644 --- a/plugins/github-pull-requests-board/package.json +++ b/plugins/github-pull-requests-board/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-github-pull-requests-board", "description": "A Backstage plugin that allows you to see all open Pull Requests for all the repositories owned by your team", - "version": "0.1.10", + "version": "0.1.11-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -42,7 +42,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "@octokit/rest": "^19.0.3", "luxon": "^3.0.0", "p-limit": "^4.0.0", diff --git a/plugins/gitops-profiles/CHANGELOG.md b/plugins/gitops-profiles/CHANGELOG.md index 5c7f777ddc..6201080830 100644 --- a/plugins/gitops-profiles/CHANGELOG.md +++ b/plugins/gitops-profiles/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-gitops-profiles +## 0.3.35-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/config@1.0.7 + - @backstage/theme@0.2.18 + ## 0.3.34 ### Patch Changes diff --git a/plugins/gitops-profiles/package.json b/plugins/gitops-profiles/package.json index d61efb7706..2208c6d011 100644 --- a/plugins/gitops-profiles/package.json +++ b/plugins/gitops-profiles/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-gitops-profiles", "description": "A Backstage plugin that helps you manage GitOps profiles", - "version": "0.3.34", + "version": "0.3.35-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,12 +33,13 @@ "clean": "backstage-cli package clean" }, "dependencies": { + "@backstage/config": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "react-use": "^17.2.4" }, "peerDependencies": { diff --git a/plugins/gitops-profiles/src/components/ProfileCatalog/ProfileCatalog.test.tsx b/plugins/gitops-profiles/src/components/ProfileCatalog/ProfileCatalog.test.tsx index 5aa59a1cae..eb58e03580 100644 --- a/plugins/gitops-profiles/src/components/ProfileCatalog/ProfileCatalog.test.tsx +++ b/plugins/gitops-profiles/src/components/ProfileCatalog/ProfileCatalog.test.tsx @@ -14,7 +14,11 @@ * limitations under the License. */ -import { renderInTestApp, TestApiRegistry } from '@backstage/test-utils'; +import { + MockConfigApi, + renderInTestApp, + TestApiRegistry, +} from '@backstage/test-utils'; import React from 'react'; import { gitOpsApiRef, GitOpsRestApi } from '../../api'; import ProfileCatalog from './ProfileCatalog'; @@ -31,6 +35,7 @@ import { githubAuthApiRef } from '@backstage/core-plugin-api'; describe('ProfileCatalog', () => { it('should render', async () => { const oauthRequestApi = new OAuthRequestManager(); + const configApi = new MockConfigApi({}); const apis = TestApiRegistry.from( [gitOpsApiRef, new GitOpsRestApi('http://localhost:3008')], [ @@ -40,6 +45,7 @@ describe('ProfileCatalog', () => { 'http://example.com/{{pluginId}}', ), oauthRequestApi, + configApi: configApi, }), ], ); diff --git a/plugins/gocd/CHANGELOG.md b/plugins/gocd/CHANGELOG.md index 544bb848dc..06ca6ecca7 100644 --- a/plugins/gocd/CHANGELOG.md +++ b/plugins/gocd/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-gocd +## 0.1.23-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + ## 0.1.22 ### Patch Changes diff --git a/plugins/gocd/package.json b/plugins/gocd/package.json index e5727302f6..a8e2599f3b 100644 --- a/plugins/gocd/package.json +++ b/plugins/gocd/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-gocd", "description": "A Backstage plugin that integrates towards GoCD", - "version": "0.1.22", + "version": "0.1.23-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -37,7 +37,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "lodash": "^4.17.21", "luxon": "^3.0.0", "qs": "^6.10.1", diff --git a/plugins/graphiql/CHANGELOG.md b/plugins/graphiql/CHANGELOG.md index 35d00a5080..816962b034 100644 --- a/plugins/graphiql/CHANGELOG.md +++ b/plugins/graphiql/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-graphiql +## 0.2.49-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/theme@0.2.18 + ## 0.2.48 ### Patch Changes diff --git a/plugins/graphiql/api-report.md b/plugins/graphiql/api-report.md index c96966c585..ea765d4d2b 100644 --- a/plugins/graphiql/api-report.md +++ b/plugins/graphiql/api-report.md @@ -16,7 +16,7 @@ import { RouteRef } from '@backstage/core-plugin-api'; export type EndpointConfig = { id: string; title: string; - url: string; + url: string | Promise; method?: 'POST'; headers?: { [name in string]: string; diff --git a/plugins/graphiql/package.json b/plugins/graphiql/package.json index a91f8647ec..fcdf347ba1 100644 --- a/plugins/graphiql/package.json +++ b/plugins/graphiql/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-graphiql", "description": "Backstage plugin for browsing GraphQL APIs", - "version": "0.2.48", + "version": "0.2.49-next.0", "publishConfig": { "access": "public", "main": "dist/index.esm.js", @@ -37,7 +37,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "graphiql": "^1.5.12", "graphql": "^16.0.0", "graphql-ws": "^5.4.1", diff --git a/plugins/graphiql/src/lib/api/GraphQLEndpoints.ts b/plugins/graphiql/src/lib/api/GraphQLEndpoints.ts index 7f9c0ca4ee..52dc40fd81 100644 --- a/plugins/graphiql/src/lib/api/GraphQLEndpoints.ts +++ b/plugins/graphiql/src/lib/api/GraphQLEndpoints.ts @@ -26,7 +26,7 @@ export type EndpointConfig = { id: string; title: string; // Endpoint URL - url: string; + url: string | Promise; // only supports POST right now method?: 'POST'; // Defaults to setting Content-Type to application/json @@ -66,7 +66,7 @@ export class GraphQLEndpoints implements GraphQLBrowseApi { ...config.headers, ...options.headers, }; - const res = await fetch(url, { + const res = await fetch(await url, { method, headers, body, diff --git a/plugins/graphql-backend/CHANGELOG.md b/plugins/graphql-backend/CHANGELOG.md index 87f2fe54e0..1e2f5059eb 100644 --- a/plugins/graphql-backend/CHANGELOG.md +++ b/plugins/graphql-backend/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-graphql-backend +## 0.1.34-next.0 + +### Patch Changes + +- e47e69eadf0: Updated dependency `@apollo/server` to `^4.0.0`. +- Updated dependencies + - @backstage/plugin-catalog-graphql@0.3.20-next.0 + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + ## 0.1.33 ### Patch Changes diff --git a/plugins/graphql-backend/package.json b/plugins/graphql-backend/package.json index 10e3f6eca6..736c057a5b 100644 --- a/plugins/graphql-backend/package.json +++ b/plugins/graphql-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-graphql-backend", "description": "An experimental Backstage backend plugin for GraphQL", - "version": "0.1.33", + "version": "0.1.34-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,13 +33,12 @@ "clean": "backstage-cli package clean" }, "dependencies": { + "@apollo/server": "^4.0.0", "@backstage/backend-common": "workspace:^", "@backstage/config": "workspace:^", "@backstage/plugin-catalog-graphql": "workspace:^", "@graphql-tools/schema": "^9.0.0", "@types/express": "^4.17.6", - "apollo-server": "^3.0.0", - "apollo-server-express": "^3.0.0", "express": "^4.17.1", "express-promise-router": "^4.1.0", "graphql": "^16.0.0", diff --git a/plugins/graphql-backend/src/service/router.ts b/plugins/graphql-backend/src/service/router.ts index aa83b51beb..fbddee435f 100644 --- a/plugins/graphql-backend/src/service/router.ts +++ b/plugins/graphql-backend/src/service/router.ts @@ -19,7 +19,8 @@ import express from 'express'; import Router from 'express-promise-router'; import { Logger } from 'winston'; import { createApplication } from 'graphql-modules'; -import { ApolloServer } from 'apollo-server-express'; +import { ApolloServer } from '@apollo/server'; +import { expressMiddleware } from '@apollo/server/express4'; import { createModule as createCatalogModule } from '@backstage/plugin-catalog-graphql'; import { Config } from '@backstage/config'; import helmet from 'helmet'; @@ -61,8 +62,6 @@ export async function createRouter( response.json({ status: 'ok' }); }); - const apolloMiddleware = server.getMiddleware({ path: '/' }); - if (process.env.NODE_ENV === 'development') router.use( helmet.contentSecurityPolicy({ @@ -72,7 +71,7 @@ export async function createRouter( }), ); - router.use(apolloMiddleware); + router.use(expressMiddleware(server)); router.use(errorHandler()); return router; diff --git a/plugins/graphql-voyager/CHANGELOG.md b/plugins/graphql-voyager/CHANGELOG.md index 43d2b66fd8..480e859caa 100644 --- a/plugins/graphql-voyager/CHANGELOG.md +++ b/plugins/graphql-voyager/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-graphql-voyager +## 0.1.2-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/theme@0.2.18 + ## 0.1.1 ### Patch Changes diff --git a/plugins/graphql-voyager/package.json b/plugins/graphql-voyager/package.json index 25f947e455..deba02b6a4 100644 --- a/plugins/graphql-voyager/package.json +++ b/plugins/graphql-voyager/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-graphql-voyager", "description": "Backstage plugin for GraphQL Voyager", - "version": "0.1.1", + "version": "0.1.2-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -28,7 +28,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "graphql-voyager": "^1.0.0-rc.31", "react-use": "^17.2.4" }, diff --git a/plugins/home/CHANGELOG.md b/plugins/home/CHANGELOG.md index 1deba56290..0c1e662fef 100644 --- a/plugins/home/CHANGELOG.md +++ b/plugins/home/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-home +## 0.4.33-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/config@1.0.7 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + ## 0.4.32 ### Patch Changes diff --git a/plugins/home/package.json b/plugins/home/package.json index 1896a15006..767ed33557 100644 --- a/plugins/home/package.json +++ b/plugins/home/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-home", "description": "A Backstage plugin that helps you build a home page", - "version": "0.4.32", + "version": "0.4.33-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -41,7 +41,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "lodash": "^4.17.21", "react-use": "^17.2.4" }, diff --git a/plugins/ilert/CHANGELOG.md b/plugins/ilert/CHANGELOG.md index ff0683d4a8..ae6e292c85 100644 --- a/plugins/ilert/CHANGELOG.md +++ b/plugins/ilert/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-ilert +## 0.2.6-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + ## 0.2.5 ### Patch Changes diff --git a/plugins/ilert/package.json b/plugins/ilert/package.json index 903b69523e..67573d1e3a 100644 --- a/plugins/ilert/package.json +++ b/plugins/ilert/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-ilert", "description": "A Backstage plugin that integrates towards iLert", - "version": "0.2.5", + "version": "0.2.6-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,7 +32,7 @@ "@date-io/luxon": "1.x", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "@material-ui/pickers": "^3.3.10", "humanize-duration": "^3.26.0", "luxon": "^3.0.0", diff --git a/plugins/jenkins-backend/CHANGELOG.md b/plugins/jenkins-backend/CHANGELOG.md index a9f6bcaac4..0655d6c189 100644 --- a/plugins/jenkins-backend/CHANGELOG.md +++ b/plugins/jenkins-backend/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-jenkins-backend +## 0.1.34-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/plugin-auth-node@0.2.13-next.0 + - @backstage/plugin-jenkins-common@0.1.14 + - @backstage/plugin-permission-common@0.7.4 + ## 0.1.33 ### Patch Changes diff --git a/plugins/jenkins-backend/package.json b/plugins/jenkins-backend/package.json index 9f85185900..54375b6f30 100644 --- a/plugins/jenkins-backend/package.json +++ b/plugins/jenkins-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-jenkins-backend", "description": "A Backstage backend plugin that integrates towards Jenkins", - "version": "0.1.33", + "version": "0.1.34-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/jenkins/CHANGELOG.md b/plugins/jenkins/CHANGELOG.md index 19c41d8931..97bfce2e07 100644 --- a/plugins/jenkins/CHANGELOG.md +++ b/plugins/jenkins/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-jenkins +## 0.7.16-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + - @backstage/plugin-jenkins-common@0.1.14 + ## 0.7.15 ### Patch Changes diff --git a/plugins/jenkins/package.json b/plugins/jenkins/package.json index fbb95c8303..23bbcfedcd 100644 --- a/plugins/jenkins/package.json +++ b/plugins/jenkins/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-jenkins", "description": "A Backstage plugin that integrates towards Jenkins", - "version": "0.7.15", + "version": "0.7.16-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -42,7 +42,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "luxon": "^3.0.0", "react-use": "^17.2.4" }, diff --git a/plugins/kafka-backend/CHANGELOG.md b/plugins/kafka-backend/CHANGELOG.md index a21c47dd96..d844d8339b 100644 --- a/plugins/kafka-backend/CHANGELOG.md +++ b/plugins/kafka-backend/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-kafka-backend +## 0.2.37-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + ## 0.2.36 ### Patch Changes diff --git a/plugins/kafka-backend/package.json b/plugins/kafka-backend/package.json index 3f43fac671..d29ce0fb82 100644 --- a/plugins/kafka-backend/package.json +++ b/plugins/kafka-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kafka-backend", "description": "A Backstage backend plugin that integrates towards Kafka", - "version": "0.2.36", + "version": "0.2.37-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/kafka/CHANGELOG.md b/plugins/kafka/CHANGELOG.md index 0ed581fc62..324b9ae111 100644 --- a/plugins/kafka/CHANGELOG.md +++ b/plugins/kafka/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-kafka +## 0.3.17-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/config@1.0.7 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + ## 0.3.16 ### Patch Changes diff --git a/plugins/kafka/package.json b/plugins/kafka/package.json index d3eab939e6..a39b72c5b9 100644 --- a/plugins/kafka/package.json +++ b/plugins/kafka/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kafka", "description": "A Backstage plugin that integrates towards Kafka", - "version": "0.3.16", + "version": "0.3.17-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,7 +32,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "react-use": "^17.2.4" }, "peerDependencies": { diff --git a/plugins/kubernetes-backend/CHANGELOG.md b/plugins/kubernetes-backend/CHANGELOG.md index 617a9d16f9..75a4567b98 100644 --- a/plugins/kubernetes-backend/CHANGELOG.md +++ b/plugins/kubernetes-backend/CHANGELOG.md @@ -1,5 +1,26 @@ # @backstage/plugin-kubernetes-backend +## 0.10.0-next.0 + +### Minor Changes + +- 804f6d16b0c: **BREAKING**: `KubernetesBuilder.create` now requires a `permissions` field of type `PermissionEvaluator`. The kubernetes `/proxy` endpoint now requires two tokens: the `Backstage-Kubernetes-Authorization` header should contain a bearer token for the target cluster, and the `Authorization` header should contain a backstage identity token. The kubernetes `/proxy` endpoint now requires a `Backstage-Kubernetes-Cluster` header replacing the previously required `X-Kubernetes-Cluster` header. + +### Patch Changes + +- 75d4985f5e8: Fixes bug whereby backstage crashes when bad credentials are provided to the kubernetes plugin. +- 83d250badc6: Fix parsing error when kubernetes api is returning badly structured data. +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/plugin-kubernetes-common@0.6.2-next.0 + - @backstage/config@1.0.7 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/plugin-auth-node@0.2.13-next.0 + - @backstage/plugin-permission-common@0.7.4 + - @backstage/plugin-permission-node@0.7.7-next.0 + ## 0.9.4 ### Patch Changes diff --git a/plugins/kubernetes-backend/api-report.md b/plugins/kubernetes-backend/api-report.md index a6a4bcfc58..449131a26e 100644 --- a/plugins/kubernetes-backend/api-report.md +++ b/plugins/kubernetes-backend/api-report.md @@ -17,6 +17,7 @@ import { KubernetesRequestAuth } from '@backstage/plugin-kubernetes-common'; import type { KubernetesRequestBody } from '@backstage/plugin-kubernetes-common'; import { Logger } from 'winston'; import type { ObjectsByEntityResponse } from '@backstage/plugin-kubernetes-common'; +import { PermissionEvaluator } from '@backstage/plugin-permission-common'; import { PluginEndpointDiscovery } from '@backstage/backend-common'; import type { RequestHandler } from 'express'; import { TokenCredential } from '@azure/identity'; @@ -141,6 +142,9 @@ export class GoogleServiceAccountAuthTranslator ): Promise; } +// @public +export const HEADER_KUBERNETES_AUTH: string; + // @public export const HEADER_KUBERNETES_CLUSTER: string; @@ -200,6 +204,7 @@ export class KubernetesBuilder { clusterSupplier: KubernetesClustersSupplier, catalogApi: CatalogApi, proxy: KubernetesProxy, + permissionApi: PermissionEvaluator, ): express.Router; // (undocumented) protected buildServiceLocator( @@ -271,6 +276,8 @@ export interface KubernetesEnvironment { config: Config; // (undocumented) logger: Logger; + // (undocumented) + permissions: PermissionEvaluator; } // @public @@ -340,9 +347,16 @@ export type KubernetesObjectTypes = export class KubernetesProxy { constructor(logger: Logger, clusterSupplier: KubernetesClustersSupplier); // (undocumented) - createRequestHandler(): RequestHandler; + createRequestHandler( + options: KubernetesProxyCreateRequestHandlerOptions, + ): RequestHandler; } +// @public +export type KubernetesProxyCreateRequestHandlerOptions = { + permissionApi: PermissionEvaluator; +}; + // @public export interface KubernetesServiceLocator { // (undocumented) @@ -418,6 +432,8 @@ export interface RouterOptions { discovery: PluginEndpointDiscovery; // (undocumented) logger: Logger; + // (undocumented) + permissions: PermissionEvaluator; } // @public (undocumented) diff --git a/plugins/kubernetes-backend/examples/dice-roller/metrics-server.yaml b/plugins/kubernetes-backend/examples/dice-roller/metrics-server.yaml index 673064aaf2..06875a5cf1 100644 --- a/plugins/kubernetes-backend/examples/dice-roller/metrics-server.yaml +++ b/plugins/kubernetes-backend/examples/dice-roller/metrics-server.yaml @@ -82,7 +82,7 @@ spec: emptyDir: {} containers: - name: metrics-server - image: k8s.gcr.io/metrics-server-amd64:v0.3.1 + image: registry.k8s.io/metrics-server-amd64:v0.3.1 args: - --kubelet-insecure-tls - --kubelet-preferred-address-types=InternalIP diff --git a/plugins/kubernetes-backend/package.json b/plugins/kubernetes-backend/package.json index 850f3c67f4..8f7b071c9a 100644 --- a/plugins/kubernetes-backend/package.json +++ b/plugins/kubernetes-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kubernetes-backend", "description": "A Backstage backend plugin that integrates towards Kubernetes", - "version": "0.9.4", + "version": "0.10.0-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -42,6 +42,8 @@ "@backstage/errors": "workspace:^", "@backstage/plugin-auth-node": "workspace:^", "@backstage/plugin-kubernetes-common": "workspace:^", + "@backstage/plugin-permission-common": "workspace:^", + "@backstage/plugin-permission-node": "workspace:^", "@google-cloud/container": "^4.0.0", "@jest-mock/express": "^2.0.1", "@kubernetes/client-node": "0.18.1", diff --git a/plugins/kubernetes-backend/src/kubernetes-auth-translator/AwsIamKubernetesAuthTranslator.test.ts b/plugins/kubernetes-backend/src/kubernetes-auth-translator/AwsIamKubernetesAuthTranslator.test.ts index 2696587e69..1f8d525ea8 100644 --- a/plugins/kubernetes-backend/src/kubernetes-auth-translator/AwsIamKubernetesAuthTranslator.test.ts +++ b/plugins/kubernetes-backend/src/kubernetes-auth-translator/AwsIamKubernetesAuthTranslator.test.ts @@ -17,6 +17,13 @@ import AWS from 'aws-sdk'; import AWSMock from 'aws-sdk-mock'; import { AwsIamKubernetesAuthTranslator } from './AwsIamKubernetesAuthTranslator'; +const awsError: AWS.AWSError = { + code: '123', + message: 'no way', + name: 'nope', + time: new Date(), +}; + describe('AwsIamKubernetesAuthTranslator tests', () => { let role: any = undefined; const credentials: any = { @@ -84,6 +91,25 @@ describe('AwsIamKubernetesAuthTranslator tests', () => { expect(response.serviceAccountToken).toBeDefined(); }); + describe('When the credentials is failing', () => { + beforeEach(() => { + jest.spyOn(AWS.config, 'getCredentials').mockImplementation(cb => { + cb(awsError, null); + }); + }); + it('throws the right error', async () => { + const authTranslator = new AwsIamKubernetesAuthTranslator(); + await expect( + authTranslator.decorateClusterDetailsWithAuth({ + assumeRole: role, + name: 'test-cluster', + url: '', + authProvider: 'aws', + }), + ).rejects.toEqual(awsError); + }); + }); + describe('When the role is assumed', () => { // These credentials are not real. // Pulled from example in docs: https://docs.aws.amazon.com/general/latest/gr/aws-sec-cred-types.html diff --git a/plugins/kubernetes-backend/src/kubernetes-auth-translator/AwsIamKubernetesAuthTranslator.ts b/plugins/kubernetes-backend/src/kubernetes-auth-translator/AwsIamKubernetesAuthTranslator.ts index b89945902d..84e60c9c69 100644 --- a/plugins/kubernetes-backend/src/kubernetes-auth-translator/AwsIamKubernetesAuthTranslator.ts +++ b/plugins/kubernetes-backend/src/kubernetes-auth-translator/AwsIamKubernetesAuthTranslator.ts @@ -55,46 +55,44 @@ export class AwsIamKubernetesAuthTranslator assumeRole?: string, externalId?: string, ): Promise { - return new Promise(async (resolve, reject) => { - const awsCreds = await this.awsGetCredentials(); + const awsCreds = await this.awsGetCredentials(); - if (!(awsCreds instanceof Credentials)) - return reject(Error('No AWS credentials found.')); + if (!(awsCreds instanceof Credentials)) + throw new Error('No AWS credentials found.'); - let creds: SigningCreds = { - accessKeyId: awsCreds.accessKeyId, - secretAccessKey: awsCreds.secretAccessKey, - sessionToken: awsCreds.sessionToken, + let creds: SigningCreds = { + accessKeyId: awsCreds.accessKeyId, + secretAccessKey: awsCreds.secretAccessKey, + sessionToken: awsCreds.sessionToken, + }; + + if (!this.validCredentials(creds)) + throw new Error('Invalid AWS credentials found.'); + if (!assumeRole) return creds; + + try { + const params: AWS.STS.Types.AssumeRoleRequest = { + RoleArn: assumeRole, + RoleSessionName: 'backstage-login', }; + if (externalId) params.ExternalId = externalId; - if (!this.validCredentials(creds)) - return reject(Error('Invalid AWS credentials found.')); - if (!assumeRole) return resolve(creds); + const assumedRole = await new AWS.STS().assumeRole(params).promise(); - try { - const params: AWS.STS.Types.AssumeRoleRequest = { - RoleArn: assumeRole, - RoleSessionName: 'backstage-login', - }; - if (externalId) params.ExternalId = externalId; - - const assumedRole = await new AWS.STS().assumeRole(params).promise(); - - if (!assumedRole.Credentials) { - throw new Error(`No credentials returned for role ${assumeRole}`); - } - - creds = { - accessKeyId: assumedRole.Credentials.AccessKeyId, - secretAccessKey: assumedRole.Credentials.SecretAccessKey, - sessionToken: assumedRole.Credentials.SessionToken, - }; - } catch (e) { - console.warn(`There was an error assuming the role: ${e}`); - return reject(Error(`Unable to assume role: ${e}`)); + if (!assumedRole.Credentials) { + throw new Error(`No credentials returned for role ${assumeRole}`); } - return resolve(creds); - }); + + creds = { + accessKeyId: assumedRole.Credentials.AccessKeyId, + secretAccessKey: assumedRole.Credentials.SecretAccessKey, + sessionToken: assumedRole.Credentials.SessionToken, + }; + } catch (e) { + console.warn(`There was an error assuming the role: ${e}`); + throw new Error(`Unable to assume role: ${e}`); + } + return creds; } async getBearerToken( clusterName: string, diff --git a/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts b/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts index cc2dea26c0..8eb7a066df 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts @@ -31,16 +31,24 @@ import { import { KubernetesBuilder } from './KubernetesBuilder'; import { KubernetesFanOutHandler } from './KubernetesFanOutHandler'; import { CatalogApi } from '@backstage/catalog-client'; -import { HEADER_KUBERNETES_CLUSTER } from './KubernetesProxy'; +import { + HEADER_KUBERNETES_CLUSTER, + HEADER_KUBERNETES_AUTH, +} from './KubernetesProxy'; import { setupServer } from 'msw/node'; import { setupRequestMockHandlers } from '@backstage/backend-test-utils'; import { rest } from 'msw'; +import { + AuthorizeResult, + PermissionEvaluator, +} from '@backstage/plugin-permission-common'; describe('KubernetesBuilder', () => { let app: express.Express; let kubernetesFanOutHandler: jest.Mocked; let config: Config; let catalogApi: CatalogApi; + let permissions: jest.Mocked; beforeAll(async () => { const logger = getVoidLogger(); @@ -74,10 +82,16 @@ describe('KubernetesBuilder', () => { getKubernetesObjectsByEntity: jest.fn(), } as any; + permissions = { + authorize: jest.fn(), + authorizeConditional: jest.fn(), + }; + const { router } = await KubernetesBuilder.createBuilder({ config, logger, catalogApi, + permissions, }) .setObjectsProvider(kubernetesFanOutHandler) .setClusterSupplier(clusterSupplier) @@ -250,6 +264,7 @@ describe('KubernetesBuilder', () => { logger, config, catalogApi, + permissions, }) .setClusterSupplier(clusterSupplier) .setServiceLocator(serviceLocator) @@ -271,27 +286,32 @@ describe('KubernetesBuilder', () => { expect(response.status).toEqual(200); }); }); - describe('post /proxy', () => { const worker = setupServer(); setupRequestMockHandlers(worker); beforeEach(() => { worker.use( - rest.post('https://localhost:1234/api/v1/namespaces', (req, res, ctx) => - req - .arrayBuffer() - .then(body => - res( - ctx.set('content-type', `${req.headers.get('content-type')}`), - ctx.body(body), - ), - ), + rest.post( + 'https://localhost:1234/api/v1/namespaces', + (req, res, ctx) => { + if (!req.headers.get('Authorization')) { + return res(ctx.status(401)); + } + return req + .arrayBuffer() + .then(body => + res( + ctx.set('content-type', `${req.headers.get('content-type')}`), + ctx.body(body), + ), + ); + }, ), ); }); - it('returns the given request body', async () => { + it('returns the given request body with permission set to allow', async () => { const requestBody = { kind: 'Namespace', apiVersion: 'v1', @@ -300,9 +320,14 @@ describe('KubernetesBuilder', () => { }, }; + permissions.authorize.mockReturnValue( + Promise.resolve([{ result: AuthorizeResult.ALLOW }]), + ); + const proxyEndpointRequest = request(app) .post('/proxy/api/v1/namespaces') .set(HEADER_KUBERNETES_CLUSTER, 'some-cluster') + .set(HEADER_KUBERNETES_AUTH, 'randomtoken') .send(requestBody); worker.use(rest.all(proxyEndpointRequest.url, req => req.passthrough())); @@ -312,7 +337,7 @@ describe('KubernetesBuilder', () => { expect(response.body).toStrictEqual(requestBody); }); - it('supports yaml content type', async () => { + it('supports yaml content type with permission set to allow', async () => { const requestBody = `--- kind: Namespace apiVersion: v1 @@ -320,9 +345,14 @@ metadata: name: new-ns `; + permissions.authorize.mockReturnValue( + Promise.resolve([{ result: AuthorizeResult.ALLOW }]), + ); + const proxyEndpointRequest = request(app) .post('/proxy/api/v1/namespaces') .set(HEADER_KUBERNETES_CLUSTER, 'some-cluster') + .set(HEADER_KUBERNETES_AUTH, 'randomtoken') .set('content-type', 'application/yaml') .send(requestBody); @@ -331,5 +361,50 @@ metadata: const response = await proxyEndpointRequest; expect(response.text).toEqual(requestBody); }); + + it('returns a 403 response if Permission Policy is in place that blocks endpoint', async () => { + const requestBody = { + kind: 'Namespace', + apiVersion: 'v1', + metadata: { + name: 'new-ns', + }, + }; + + permissions.authorize.mockReturnValue( + Promise.resolve([{ result: AuthorizeResult.DENY }]), + ); + + const proxyEndpointRequest = request(app) + .post('/proxy/api/v1/namespaces') + .set(HEADER_KUBERNETES_CLUSTER, 'some-cluster') + .set(HEADER_KUBERNETES_AUTH, 'randomtoken') + .send(requestBody); + + worker.use(rest.all(proxyEndpointRequest.url, req => req.passthrough())); + + const response = await proxyEndpointRequest; + + expect(response.status).toEqual(403); + }); + }); + describe('get /.well-known/backstage/permissions/metadata', () => { + it('lists permissions supported by the kubernetes plugin', async () => { + const response = await request(app).get( + '/.well-known/backstage/permissions/metadata', + ); + + expect(response.status).toEqual(200); + expect(response.body).toMatchObject({ + permissions: [ + { + type: 'basic', + name: 'kubernetes.proxy', + attributes: {}, + }, + ], + rules: [], + }); + }); }); }); diff --git a/plugins/kubernetes-backend/src/service/KubernetesBuilder.ts b/plugins/kubernetes-backend/src/service/KubernetesBuilder.ts index 74ec9eada2..367e5edef3 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesBuilder.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesBuilder.ts @@ -15,6 +15,9 @@ */ import { CatalogApi } from '@backstage/catalog-client'; import { Config } from '@backstage/config'; +import { kubernetesPermissions } from '@backstage/plugin-kubernetes-common'; +import { PermissionEvaluator } from '@backstage/plugin-permission-common'; +import { createPermissionIntegrationRouter } from '@backstage/plugin-permission-node'; import express from 'express'; import Router from 'express-promise-router'; import { Duration } from 'luxon'; @@ -49,6 +52,7 @@ export interface KubernetesEnvironment { logger: Logger; config: Config; catalogApi: CatalogApi; + permissions: PermissionEvaluator; } /** @@ -89,6 +93,7 @@ export class KubernetesBuilder { public async build(): KubernetesBuilderReturn { const logger = this.env.logger; const config = this.env.config; + const permissions = this.env.permissions; logger.info('Initializing Kubernetes backend'); @@ -126,6 +131,7 @@ export class KubernetesBuilder { clusterSupplier, this.env.catalogApi, proxy, + permissions, ); return { @@ -262,12 +268,17 @@ export class KubernetesBuilder { clusterSupplier: KubernetesClustersSupplier, catalogApi: CatalogApi, proxy: KubernetesProxy, + permissionApi: PermissionEvaluator, ): express.Router { const logger = this.env.logger; const router = Router(); - router.use('/proxy', proxy.createRequestHandler()); + router.use('/proxy', proxy.createRequestHandler({ permissionApi })); router.use(express.json()); - + router.use( + createPermissionIntegrationRouter({ + permissions: kubernetesPermissions, + }), + ); // @deprecated router.post('/services/:serviceId', async (req, res) => { const serviceId = req.params.serviceId; diff --git a/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.ts b/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.ts index e0a6c21c4a..f71c6506bd 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.ts @@ -49,6 +49,14 @@ import { PodStatus, } from '@kubernetes/client-node'; +const isRejected = ( + input: PromiseSettledResult, +): input is PromiseRejectedResult => input.status === 'rejected'; + +const isFulfilled = ( + input: PromiseSettledResult, +): input is PromiseFulfilledResult => input.status === 'fulfilled'; + /** * * @public @@ -298,12 +306,12 @@ export class KubernetesFanOutHandler { auth: KubernetesRequestAuth, requestContext: ServiceLocatorRequestContext, ) { - const clusterDetails: ClusterDetails[] = await ( + const clusterDetails: ClusterDetails[] = ( await this.serviceLocator.getClustersByEntity(entity, requestContext) ).clusters; // Execute all of these async actions simultaneously/without blocking sequentially as no common object is modified by them - return await Promise.all( + const promiseResults = await Promise.allSettled( clusterDetails.map(cd => { const kubernetesAuthTranslator: KubernetesAuthTranslator = this.getAuthTranslator(cd.authProvider); @@ -313,6 +321,11 @@ export class KubernetesFanOutHandler { ); }), ); + + promiseResults.filter(isRejected).map(item => { + this.logger.info(`Failed to decorate cluster details: ${item.reason}`); + }); + return promiseResults.filter(isFulfilled).map(item => item.value); } toObjectsByEntityResponse( diff --git a/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts b/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts index 4254bb33da..d2404af839 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts @@ -30,6 +30,10 @@ import { HEADER_KUBERNETES_CLUSTER, KubernetesProxy, } from './KubernetesProxy'; +import { + AuthorizeResult, + PermissionEvaluator, +} from '@backstage/plugin-permission-common'; describe('KubernetesProxy', () => { let proxy: KubernetesProxy; @@ -64,6 +68,11 @@ describe('KubernetesProxy', () => { getClusters: jest.fn(), }; + const permissionApi: jest.Mocked = { + authorize: jest.fn(), + authorizeConditional: jest.fn(), + }; + beforeEach(() => { jest.resetAllMocks(); proxy = new KubernetesProxy(getVoidLogger(), clusterSupplier); @@ -71,13 +80,16 @@ describe('KubernetesProxy', () => { it('should return a ERROR_NOT_FOUND if no clusters are found', async () => { clusterSupplier.getClusters.mockResolvedValue([]); + permissionApi.authorize.mockReturnValue( + Promise.resolve([{ result: AuthorizeResult.ALLOW }]), + ); const req = buildMockRequest('test', 'api'); const { res, next } = getMockRes(); - await expect(proxy.createRequestHandler()(req, res, next)).rejects.toThrow( - NotFoundError, - ); + await expect( + proxy.createRequestHandler({ permissionApi })(req, res, next), + ).rejects.toThrow(NotFoundError); }); it('should pass the exact response from Kubernetes', async () => { @@ -100,7 +112,13 @@ describe('KubernetesProxy', () => { authProvider: 'serviceAccount', }, ] as ClusterDetails[]); - const app = express().use('/mountpath', proxy.createRequestHandler()); + const app = express().use( + '/mountpath', + proxy.createRequestHandler({ permissionApi }), + ); + permissionApi.authorize.mockReturnValue( + Promise.resolve([{ result: AuthorizeResult.ALLOW }]), + ); const requestPromise = request(app) .get('/mountpath/api') .set(HEADER_KUBERNETES_CLUSTER, 'cluster1'); diff --git a/plugins/kubernetes-backend/src/service/KubernetesProxy.ts b/plugins/kubernetes-backend/src/service/KubernetesProxy.ts index 178105ef79..49a381b75a 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesProxy.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesProxy.ts @@ -18,9 +18,16 @@ import { ErrorResponseBody, ForwardedError, InputError, + NotAllowedError, NotFoundError, serializeError, } from '@backstage/errors'; +import { getBearerTokenFromAuthorizationHeader } from '@backstage/plugin-auth-node'; +import { kubernetesProxyPermission } from '@backstage/plugin-kubernetes-common'; +import { + PermissionEvaluator, + AuthorizeResult, +} from '@backstage/plugin-permission-common'; import { bufferFromFileOrString } from '@kubernetes/client-node'; import type { Request, RequestHandler } from 'express'; import { createProxyMiddleware } from 'http-proxy-middleware'; @@ -34,7 +41,24 @@ export const APPLICATION_JSON: string = 'application/json'; * * @public */ -export const HEADER_KUBERNETES_CLUSTER: string = 'X-Kubernetes-Cluster'; +export const HEADER_KUBERNETES_CLUSTER: string = 'Backstage-Kubernetes-Cluster'; + +/** + * The header that is used to specify the Authentication Authorities token. + * e.x if using the google auth provider as your authentication authority then this field would be the google provided bearer token. + * @public + */ +export const HEADER_KUBERNETES_AUTH: string = + 'Backstage-Kubernetes-Authorization'; + +/** + * The options object expected to be passed as a parameter to KubernetesProxy.createRequestHandler(). + * + * @public + */ +export type KubernetesProxyCreateRequestHandlerOptions = { + permissionApi: PermissionEvaluator; +}; /** * A proxy that routes requests to the Kubernetes API. @@ -49,8 +73,29 @@ export class KubernetesProxy { private readonly clusterSupplier: KubernetesClustersSupplier, ) {} - public createRequestHandler(): RequestHandler { + public createRequestHandler( + options: KubernetesProxyCreateRequestHandlerOptions, + ): RequestHandler { + const { permissionApi } = options; return async (req, res, next) => { + const token = getBearerTokenFromAuthorizationHeader( + req.header('authorization'), + ); + + const authorizeResponse = ( + await permissionApi.authorize( + [{ permission: kubernetesProxyPermission }], + { + token, + }, + ) + )[0]; + + if (authorizeResponse.result === AuthorizeResult.DENY) { + res.status(403).json({ error: new NotAllowedError('Unauthorized') }); + return; + } + const middleware = await this.getMiddleware(req); middleware(req, res, next); }; @@ -104,6 +149,11 @@ export class KubernetesProxy { res.status(500).json(body); }, + onProxyReq: (proxyReq, req) => { + // the kubernetes proxy endpoint expects a header field labeled `Backstage-Kubernetes-Authorization` that will be used to authenticate with the Kubernetes Api. The token provided as a value should be an bearer token for the target cluster. + const token = req.header(HEADER_KUBERNETES_AUTH) ?? ''; + proxyReq.setHeader('Authorization', token); + }, }); this.middlewareForClusterName.set(originalCluster.name, middleware); diff --git a/plugins/kubernetes-backend/src/service/index.ts b/plugins/kubernetes-backend/src/service/index.ts index 620f788ac2..2f3e907879 100644 --- a/plugins/kubernetes-backend/src/service/index.ts +++ b/plugins/kubernetes-backend/src/service/index.ts @@ -16,5 +16,10 @@ export * from './KubernetesBuilder'; export { DEFAULT_OBJECTS } from './KubernetesFanOutHandler'; -export { HEADER_KUBERNETES_CLUSTER, KubernetesProxy } from './KubernetesProxy'; +export { + HEADER_KUBERNETES_CLUSTER, + KubernetesProxy, + HEADER_KUBERNETES_AUTH, +} from './KubernetesProxy'; +export type { KubernetesProxyCreateRequestHandlerOptions } from './KubernetesProxy'; export * from './router'; diff --git a/plugins/kubernetes-backend/src/service/router.ts b/plugins/kubernetes-backend/src/service/router.ts index 341956553e..f7e58f535c 100644 --- a/plugins/kubernetes-backend/src/service/router.ts +++ b/plugins/kubernetes-backend/src/service/router.ts @@ -21,6 +21,7 @@ import express from 'express'; import { KubernetesBuilder } from './KubernetesBuilder'; import { PluginEndpointDiscovery } from '@backstage/backend-common'; import { CatalogApi } from '@backstage/catalog-client'; +import { PermissionEvaluator } from '@backstage/plugin-permission-common'; /** * @@ -32,6 +33,7 @@ export interface RouterOptions { catalogApi: CatalogApi; clusterSupplier?: KubernetesClustersSupplier; discovery: PluginEndpointDiscovery; + permissions: PermissionEvaluator; } /** diff --git a/plugins/kubernetes-backend/src/service/standaloneApplication.ts b/plugins/kubernetes-backend/src/service/standaloneApplication.ts index 8234f89d48..e3afb5a385 100644 --- a/plugins/kubernetes-backend/src/service/standaloneApplication.ts +++ b/plugins/kubernetes-backend/src/service/standaloneApplication.ts @@ -28,6 +28,7 @@ import { Logger } from 'winston'; import { createRouter } from './router'; import { ConfigReader } from '@backstage/config'; import { CatalogClient } from '@backstage/catalog-client'; +import { PermissionEvaluator } from '@backstage/plugin-permission-common'; export interface ApplicationOptions { enableCors: boolean; @@ -47,6 +48,8 @@ export async function createStandaloneApplication( discoveryApi: SingleHostDiscovery.fromConfig(config), }); + const permissions = {} as PermissionEvaluator; + app.use(helmet()); if (enableCors) { app.use(cors()); @@ -54,7 +57,10 @@ export async function createStandaloneApplication( app.use(compression()); app.use(express.json()); app.use(requestLoggingHandler()); - app.use('/', await createRouter({ logger, config, discovery, catalogApi })); + app.use( + '/', + await createRouter({ logger, config, discovery, catalogApi, permissions }), + ); app.use(notFoundHandler()); app.use(errorHandler()); diff --git a/plugins/kubernetes-common/CHANGELOG.md b/plugins/kubernetes-common/CHANGELOG.md index d12719a9f2..862899600e 100644 --- a/plugins/kubernetes-common/CHANGELOG.md +++ b/plugins/kubernetes-common/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-kubernetes-common +## 0.6.2-next.0 + +### Patch Changes + +- 804f6d16b0c: Introduced proxy permission types to be used with the kubernetes proxy endpoint's permission framework integration. +- Updated dependencies + - @backstage/catalog-model@1.2.1 + - @backstage/plugin-permission-common@0.7.4 + ## 0.6.1 ### Patch Changes diff --git a/plugins/kubernetes-common/api-report.md b/plugins/kubernetes-common/api-report.md index fb41895f1a..6c88074e50 100644 --- a/plugins/kubernetes-common/api-report.md +++ b/plugins/kubernetes-common/api-report.md @@ -3,6 +3,7 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +import { BasicPermission } from '@backstage/plugin-permission-common'; import { Entity } from '@backstage/catalog-model'; import type { JsonObject } from '@backstage/types'; import { PodStatus } from '@kubernetes/client-node'; @@ -217,6 +218,12 @@ export type KubernetesErrorTypes = // @public (undocumented) export type KubernetesFetchError = StatusError | RawFetchError; +// @public +export const kubernetesPermissions: BasicPermission[]; + +// @public +export const kubernetesProxyPermission: BasicPermission; + // @public (undocumented) export interface KubernetesRequestAuth { // (undocumented) diff --git a/plugins/kubernetes-common/package.json b/plugins/kubernetes-common/package.json index 2d83db84d4..4eb4a02bf9 100644 --- a/plugins/kubernetes-common/package.json +++ b/plugins/kubernetes-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kubernetes-common", "description": "Common functionalities for kubernetes, to be shared between kubernetes and kubernetes-backend plugin", - "version": "0.6.1", + "version": "0.6.2-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -39,6 +39,7 @@ }, "dependencies": { "@backstage/catalog-model": "workspace:^", + "@backstage/plugin-permission-common": "workspace:^", "@kubernetes/client-node": "0.18.1" }, "devDependencies": { diff --git a/plugins/kubernetes-common/src/index.ts b/plugins/kubernetes-common/src/index.ts index ade73e4f79..d5cf8dcf61 100644 --- a/plugins/kubernetes-common/src/index.ts +++ b/plugins/kubernetes-common/src/index.ts @@ -22,3 +22,7 @@ export * from './types'; export * from './catalog-entity-constants'; +export { + kubernetesProxyPermission, + kubernetesPermissions, +} from './permissions'; diff --git a/plugins/kubernetes-common/src/permissions.ts b/plugins/kubernetes-common/src/permissions.ts new file mode 100644 index 0000000000..d3ccbe8171 --- /dev/null +++ b/plugins/kubernetes-common/src/permissions.ts @@ -0,0 +1,31 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createPermission } from '@backstage/plugin-permission-common'; + +/** This permission is used to check access to the proxy endpoint + * @public + */ +export const kubernetesProxyPermission = createPermission({ + name: 'kubernetes.proxy', + attributes: {}, +}); + +/** + * List of all Kubernetes permissions. + * @public + */ +export const kubernetesPermissions = [kubernetesProxyPermission]; diff --git a/plugins/kubernetes/CHANGELOG.md b/plugins/kubernetes/CHANGELOG.md index 02dbba634d..cc8131b399 100644 --- a/plugins/kubernetes/CHANGELOG.md +++ b/plugins/kubernetes/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-kubernetes +## 0.7.10-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/plugin-kubernetes-common@0.6.2-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/config@1.0.7 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + ## 0.7.9 ### Patch Changes diff --git a/plugins/kubernetes/package.json b/plugins/kubernetes/package.json index b22d50681d..f674402545 100644 --- a/plugins/kubernetes/package.json +++ b/plugins/kubernetes/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kubernetes", "description": "A Backstage plugin that integrates towards Kubernetes", - "version": "0.7.9", + "version": "0.7.10-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -43,7 +43,7 @@ "@kubernetes/client-node": "0.18.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "@types/react": "^16.13.1 || ^17.0.0", "cronstrue": "^2.2.0", "js-yaml": "^4.0.0", diff --git a/plugins/lighthouse-backend/CHANGELOG.md b/plugins/lighthouse-backend/CHANGELOG.md index 860493f57b..7320fc7b77 100644 --- a/plugins/lighthouse-backend/CHANGELOG.md +++ b/plugins/lighthouse-backend/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-lighthouse-backend +## 0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/types@1.0.2 + - @backstage/plugin-lighthouse-common@0.1.1 + ## 0.1.1 ### Patch Changes diff --git a/plugins/lighthouse-backend/package.json b/plugins/lighthouse-backend/package.json index d13e1487e9..523f3837f5 100644 --- a/plugins/lighthouse-backend/package.json +++ b/plugins/lighthouse-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-lighthouse-backend", "description": "Backend functionalities for lighthouse", - "version": "0.1.1", + "version": "0.1.2-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/lighthouse/CHANGELOG.md b/plugins/lighthouse/CHANGELOG.md index df404fb220..e662f3d81d 100644 --- a/plugins/lighthouse/CHANGELOG.md +++ b/plugins/lighthouse/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-lighthouse +## 0.4.2-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/config@1.0.7 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + - @backstage/plugin-lighthouse-common@0.1.1 + ## 0.4.1 ### Patch Changes diff --git a/plugins/lighthouse/package.json b/plugins/lighthouse/package.json index e9c70378e5..c46fcffe57 100644 --- a/plugins/lighthouse/package.json +++ b/plugins/lighthouse/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-lighthouse", "description": "A Backstage plugin that integrates towards Lighthouse", - "version": "0.4.1", + "version": "0.4.2-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -42,7 +42,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "react-use": "^17.2.4" }, "peerDependencies": { diff --git a/plugins/linguist-backend/CHANGELOG.md b/plugins/linguist-backend/CHANGELOG.md index e94a176158..5f38af055f 100644 --- a/plugins/linguist-backend/CHANGELOG.md +++ b/plugins/linguist-backend/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-linguist-backend +## 0.2.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/types@1.0.2 + - @backstage/plugin-auth-node@0.2.13-next.0 + - @backstage/plugin-linguist-common@0.1.0 + ## 0.2.0 ### Minor Changes diff --git a/plugins/linguist-backend/package.json b/plugins/linguist-backend/package.json index 755b1b959a..d9f971d178 100644 --- a/plugins/linguist-backend/package.json +++ b/plugins/linguist-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-linguist-backend", - "version": "0.2.0", + "version": "0.2.1-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/linguist/CHANGELOG.md b/plugins/linguist/CHANGELOG.md index d289a06299..1670d80f97 100644 --- a/plugins/linguist/CHANGELOG.md +++ b/plugins/linguist/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-linguist +## 0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + - @backstage/plugin-linguist-common@0.1.0 + ## 0.1.1 ### Patch Changes diff --git a/plugins/linguist/package.json b/plugins/linguist/package.json index f589b26bd3..0a36244b81 100644 --- a/plugins/linguist/package.json +++ b/plugins/linguist/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-linguist", - "version": "0.1.1", + "version": "0.1.2-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -37,7 +37,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.9.13", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "^4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "luxon": "^2.0.2", "react-use": "^17.2.4", "slugify": "^1.6.4" diff --git a/plugins/microsoft-calendar/CHANGELOG.md b/plugins/microsoft-calendar/CHANGELOG.md index 93d51a338c..1cb17d787b 100644 --- a/plugins/microsoft-calendar/CHANGELOG.md +++ b/plugins/microsoft-calendar/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-microsoft-calendar +## 0.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + ## 0.1.1 ### Patch Changes diff --git a/plugins/microsoft-calendar/README.md b/plugins/microsoft-calendar/README.md index 219a7cf2dc..92421046e2 100644 --- a/plugins/microsoft-calendar/README.md +++ b/plugins/microsoft-calendar/README.md @@ -1,7 +1,6 @@ # Microsoft-Calendar Plugin -Welcome to the Microsoft calendar plugin! -_This plugin was created through the Backstage CLI_ +This plugin is contributed by [StatusNeo](https://statusneo.com/) ## Features diff --git a/plugins/microsoft-calendar/package.json b/plugins/microsoft-calendar/package.json index cb125480f2..8170c7847f 100644 --- a/plugins/microsoft-calendar/package.json +++ b/plugins/microsoft-calendar/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-microsoft-calendar", - "version": "0.1.1", + "version": "0.1.2-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -13,10 +13,24 @@ "role": "frontend-plugin" }, "author": { - "name": "Abhay Soni", - "email": "abhaysoni.developer@gmail.com", - "url": "https://github.com/Abhay-soni-developer" + "name": "Statusneo", + "email": "reach@statusneo.com", + "url": "https://statusneo.com/" }, + "contributors": [ + { + "email": "abhaysoni.developer@gmail.com", + "url": "https://github.com/Abhay-soni-developer", + "name": "abhaysoni" + } + ], + "maintainers": [ + { + "email": "abhaysoni.developer@gmail.com", + "url": "https://github.com/Abhay-soni-developer", + "name": "abhaysoni" + } + ], "scripts": { "start": "backstage-cli package start", "build": "backstage-cli package build", diff --git a/plugins/newrelic-dashboard/CHANGELOG.md b/plugins/newrelic-dashboard/CHANGELOG.md index 44122710e5..81112322fb 100644 --- a/plugins/newrelic-dashboard/CHANGELOG.md +++ b/plugins/newrelic-dashboard/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-newrelic-dashboard +## 0.2.10-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + ## 0.2.9 ### Patch Changes diff --git a/plugins/newrelic-dashboard/package.json b/plugins/newrelic-dashboard/package.json index 83aa0811b6..8718cbfe70 100644 --- a/plugins/newrelic-dashboard/package.json +++ b/plugins/newrelic-dashboard/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-newrelic-dashboard", - "version": "0.2.9", + "version": "0.2.10-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -29,7 +29,7 @@ "@backstage/plugin-catalog-react": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "react-use": "^17.2.4" }, "devDependencies": { diff --git a/plugins/newrelic/CHANGELOG.md b/plugins/newrelic/CHANGELOG.md index d241da2d28..60ccace53b 100644 --- a/plugins/newrelic/CHANGELOG.md +++ b/plugins/newrelic/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-newrelic +## 0.3.35-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/theme@0.2.18 + ## 0.3.34 ### Patch Changes diff --git a/plugins/newrelic/package.json b/plugins/newrelic/package.json index 08d4ad0970..89823c559b 100644 --- a/plugins/newrelic/package.json +++ b/plugins/newrelic/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-newrelic", "description": "A Backstage plugin that integrates towards New Relic", - "version": "0.3.34", + "version": "0.3.35-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -38,7 +38,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "react-use": "^17.2.4" }, "peerDependencies": { diff --git a/plugins/octopus-deploy/CHANGELOG.md b/plugins/octopus-deploy/CHANGELOG.md index 8ab8d174db..8b39119ce2 100644 --- a/plugins/octopus-deploy/CHANGELOG.md +++ b/plugins/octopus-deploy/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-octopus-deploy +## 0.1.1-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + ## 0.1.0 ### Minor Changes diff --git a/plugins/octopus-deploy/package.json b/plugins/octopus-deploy/package.json index 4cbe40b006..ce36c80678 100644 --- a/plugins/octopus-deploy/package.json +++ b/plugins/octopus-deploy/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-octopus-deploy", - "version": "0.1.0", + "version": "0.1.1-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -29,7 +29,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.9.13", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "react-use": "^17.2.4" }, "peerDependencies": { diff --git a/plugins/org-react/CHANGELOG.md b/plugins/org-react/CHANGELOG.md index a8b59a4bc1..cdb4ef0b9e 100644 --- a/plugins/org-react/CHANGELOG.md +++ b/plugins/org-react/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-org-react +## 0.1.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + ## 0.1.5 ### Patch Changes diff --git a/plugins/org-react/package.json b/plugins/org-react/package.json index 027e34c391..6b48a9c381 100644 --- a/plugins/org-react/package.json +++ b/plugins/org-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-org-react", - "version": "0.1.5", + "version": "0.1.6-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -38,7 +38,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "^4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "react-use": "^17.2.4" }, "peerDependencies": { diff --git a/plugins/org/CHANGELOG.md b/plugins/org/CHANGELOG.md index 4251195733..d4db2bcc61 100644 --- a/plugins/org/CHANGELOG.md +++ b/plugins/org/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-org +## 0.6.7-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + ## 0.6.6 ### Patch Changes diff --git a/plugins/org/package.json b/plugins/org/package.json index 1e948703c5..43a102e1dd 100644 --- a/plugins/org/package.json +++ b/plugins/org/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-org", "description": "A Backstage plugin that helps you create entity pages for your organization", - "version": "0.6.6", + "version": "0.6.7-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -35,7 +35,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "p-limit": "^3.1.0", "pluralize": "^8.0.0", "qs": "^6.10.1", 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 f183ab4d8e..526d7c9c4c 100644 --- a/plugins/org/src/components/Cards/Group/GroupProfile/GroupProfileCard.stories.tsx +++ b/plugins/org/src/components/Cards/Group/GroupProfile/GroupProfileCard.stories.tsx @@ -128,3 +128,33 @@ export const ExtraDetails = () => ( ); + +const groupWithTitle: GroupEntity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Group', + metadata: { + name: 'team-a', + description: 'Team A description', + title: 'Team A title', + }, + spec: { + profile: { + 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 UseGroupTitle = () => ( + + + + + + + +); diff --git a/plugins/org/src/components/Cards/Group/GroupProfile/GroupProfileCard.tsx b/plugins/org/src/components/Cards/Group/GroupProfile/GroupProfileCard.tsx index 5e795b2710..e8f06e49b3 100644 --- a/plugins/org/src/components/Cards/Group/GroupProfile/GroupProfileCard.tsx +++ b/plugins/org/src/components/Cards/Group/GroupProfile/GroupProfileCard.tsx @@ -81,7 +81,7 @@ export const GroupProfileCard = (props: { } const { - metadata: { name, description, annotations, links }, + metadata: { name, description, title, annotations, links }, spec: { profile }, } = group; @@ -99,7 +99,7 @@ export const GroupProfileCard = (props: { const entityMetadataEditUrl = group.metadata.annotations?.[ANNOTATION_EDIT_URL]; - const displayName = profile?.displayName ?? name; + const displayName = profile?.displayName ?? title ?? name; const emailHref = profile?.email ? `mailto:${profile.email}` : '#'; const infoCardAction = entityMetadataEditUrl ? ( { describe('applyConditions', () => { - let server: SetupServerApi; + let server: SetupServer; const mockConditions: PermissionCriteria = { not: { diff --git a/plugins/permission-node/CHANGELOG.md b/plugins/permission-node/CHANGELOG.md index 472fa004a1..3bd2cf06c4 100644 --- a/plugins/permission-node/CHANGELOG.md +++ b/plugins/permission-node/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-permission-node +## 0.7.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/errors@1.1.5 + - @backstage/plugin-auth-node@0.2.13-next.0 + - @backstage/plugin-permission-common@0.7.4 + ## 0.7.6 ### Patch Changes diff --git a/plugins/permission-node/api-report.md b/plugins/permission-node/api-report.md index f89ff0a8d5..b3d06efdc7 100644 --- a/plugins/permission-node/api-report.md +++ b/plugins/permission-node/api-report.md @@ -73,6 +73,11 @@ export type ConditionTransformer = ( conditions: PermissionCriteria, ) => PermissionCriteria; +// @public +export const createConditionAuthorizer: ( + rules: PermissionRule[], +) => (decision: PolicyDecision, resource: TResource | undefined) => boolean; + // @public export const createConditionExports: < TResourceType extends string, diff --git a/plugins/permission-node/package.json b/plugins/permission-node/package.json index 1473de80b2..e4b2229bbc 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.6", + "version": "0.7.7-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.test.ts b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.test.ts index 1a7462665e..6e28c5ddc4 100644 --- a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.test.ts +++ b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.test.ts @@ -25,6 +25,7 @@ import { z } from 'zod'; import { createPermissionIntegrationRouter, CreatePermissionIntegrationRouterResourceOptions, + createConditionAuthorizer, } from './createPermissionIntegrationRouter'; import { createPermissionRule } from './createPermissionRule'; @@ -33,6 +34,9 @@ const testPermission: Permission = createPermission({ attributes: {}, }); +const mockTestRule1Apply = jest + .fn() + .mockImplementation((_resource: any, _params) => true); const testRule1 = createPermissionRule({ name: 'test-rule-1', description: 'Test rule 1', @@ -41,15 +45,18 @@ const testRule1 = createPermissionRule({ foo: z.string(), bar: z.number().describe('bar'), }), - apply: (_resource: any, _params) => true, + apply: mockTestRule1Apply, toQuery: _params => ({}), }); +const mockTestRule2Apply = jest + .fn() + .mockImplementation((_resource: any) => false); const testRule2 = createPermissionRule({ name: 'test-rule-2', description: 'Test rule 2', resourceType: 'test-resource', - apply: (_resource: any) => false, + apply: mockTestRule2Apply, toQuery: () => ({}), }); @@ -625,3 +632,72 @@ describe('createPermissionIntegrationRouter', () => { }); }); }); + +describe('createConditionAuthorizer', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should return true in case of allowed decision', () => { + const isAuthorized = createConditionAuthorizer([testRule1, testRule2]); + expect( + isAuthorized( + { + result: AuthorizeResult.ALLOW, + }, + {}, + ), + ).toBe(true); + + expect(mockTestRule1Apply).not.toHaveBeenCalled(); + expect(mockTestRule2Apply).not.toHaveBeenCalled(); + }); + it('should return false in case of denied decision', () => { + const isAuthorized = createConditionAuthorizer([testRule1, testRule2]); + expect( + isAuthorized( + { + result: AuthorizeResult.DENY, + }, + {}, + ), + ).toBe(false); + + expect(mockTestRule1Apply).not.toHaveBeenCalled(); + expect(mockTestRule2Apply).not.toHaveBeenCalled(); + }); + + it('should apply conditions to a resource in case of conditional decision', () => { + const isAuthorized = createConditionAuthorizer([testRule1, testRule2]); + expect( + isAuthorized( + { + pluginId: 'plugin', + resourceType: 'test-resource', + result: AuthorizeResult.CONDITIONAL, + conditions: { + allOf: [ + { + rule: 'test-rule-1', + resourceType: 'test-resource', + params: { + foo: 'a', + bar: 1, + }, + }, + { + rule: 'test-rule-2', + resourceType: 'test-resource', + params: {}, + }, + ], + }, + }, + {}, + ), + ).toBe(false); + + expect(mockTestRule1Apply).toHaveBeenCalledTimes(1); + expect(mockTestRule2Apply).toHaveBeenCalledTimes(1); + }); +}); diff --git a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts index 087de23198..850123d55e 100644 --- a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts +++ b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts @@ -27,6 +27,7 @@ import { Permission, PermissionCondition, PermissionCriteria, + PolicyDecision, } from '@backstage/plugin-permission-common'; import { PermissionRule } from '../types'; import { @@ -160,6 +161,30 @@ const applyConditions = ( return rule.apply(resource, criteria.params ?? {}); }; +/** + + * Takes some permission conditions and returns a definitive authorization result + * on the resource to which they apply. + * + * @public + */ +export const createConditionAuthorizer = ( + rules: PermissionRule[], +) => { + const getRule = createGetRule(rules); + + return ( + decision: PolicyDecision, + resource: TResource | undefined, + ): boolean => { + if (decision.result === AuthorizeResult.CONDITIONAL) { + return applyConditions(decision.conditions, resource, getRule); + } + + return decision.result === AuthorizeResult.ALLOW; + }; +}; + /** * Options for creating a permission integration router specific * for a particular resource type. diff --git a/plugins/playlist-backend/CHANGELOG.md b/plugins/playlist-backend/CHANGELOG.md index 195cdb1f50..51e419f0fb 100644 --- a/plugins/playlist-backend/CHANGELOG.md +++ b/plugins/playlist-backend/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-playlist-backend +## 0.2.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/plugin-auth-node@0.2.13-next.0 + - @backstage/plugin-permission-common@0.7.4 + - @backstage/plugin-permission-node@0.7.7-next.0 + - @backstage/plugin-playlist-common@0.1.5 + ## 0.2.6 ### Patch Changes diff --git a/plugins/playlist-backend/package.json b/plugins/playlist-backend/package.json index 90e5813247..870284f364 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.6", + "version": "0.2.7-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/playlist/CHANGELOG.md b/plugins/playlist/CHANGELOG.md index 43a7ff4e4d..6e09f280bd 100644 --- a/plugins/playlist/CHANGELOG.md +++ b/plugins/playlist/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-playlist +## 0.1.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-search-react@1.5.2-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/plugin-permission-react@0.4.11 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + - @backstage/plugin-catalog-common@1.0.12 + - @backstage/plugin-permission-common@0.7.4 + - @backstage/plugin-playlist-common@0.1.5 + ## 0.1.7 ### Patch Changes diff --git a/plugins/playlist/package.json b/plugins/playlist/package.json index 59cde3f246..4bf202bdba 100644 --- a/plugins/playlist/package.json +++ b/plugins/playlist/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-playlist", - "version": "0.1.7", + "version": "0.1.8-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -40,7 +40,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "^4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "lodash": "^4.17.21", "qs": "^6.9.4", "react-hook-form": "^7.13.0", diff --git a/plugins/proxy-backend/CHANGELOG.md b/plugins/proxy-backend/CHANGELOG.md index 8c4ef92ea5..58d68eceab 100644 --- a/plugins/proxy-backend/CHANGELOG.md +++ b/plugins/proxy-backend/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-proxy-backend +## 0.2.38-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/backend-plugin-api@0.5.1-next.0 + ## 0.2.37 ### Patch Changes diff --git a/plugins/proxy-backend/package.json b/plugins/proxy-backend/package.json index 6b9c115dbb..11caccbff3 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.37", + "version": "0.2.38-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/rollbar-backend/CHANGELOG.md b/plugins/rollbar-backend/CHANGELOG.md index f69c395c83..f7f91fea98 100644 --- a/plugins/rollbar-backend/CHANGELOG.md +++ b/plugins/rollbar-backend/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-rollbar-backend +## 0.1.41-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + ## 0.1.40 ### Patch Changes diff --git a/plugins/rollbar-backend/package.json b/plugins/rollbar-backend/package.json index 0bba2d3888..bec3819121 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.40", + "version": "0.1.41-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/rollbar/CHANGELOG.md b/plugins/rollbar/CHANGELOG.md index 2693bf4b5b..24e85c8e77 100644 --- a/plugins/rollbar/CHANGELOG.md +++ b/plugins/rollbar/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-rollbar +## 0.4.17-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + ## 0.4.16 ### Patch Changes diff --git a/plugins/rollbar/package.json b/plugins/rollbar/package.json index 9b46d91db6..4abd1b90f2 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.16", + "version": "0.4.17-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -40,7 +40,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "lodash": "^4.17.21", "react-sparklines": "^1.7.0", "react-use": "^17.2.4" diff --git a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md index 284e381553..b03b35dc72 100644 --- a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-scaffolder-backend-module-cookiecutter +## 0.2.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.12.1-next.0 + - @backstage/plugin-scaffolder-node@0.1.2-next.0 + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/errors@1.1.5 + - @backstage/types@1.0.2 + ## 0.2.18 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-cookiecutter/package.json b/plugins/scaffolder-backend-module-cookiecutter/package.json index da8f92da5c..c78cdae972 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.18", + "version": "0.2.19-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder-backend-module-gitlab/.eslintrc.js b/plugins/scaffolder-backend-module-gitlab/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/scaffolder-backend-module-gitlab/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md b/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md new file mode 100644 index 0000000000..9bd33f6aae --- /dev/null +++ b/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md @@ -0,0 +1,15 @@ +# @backstage/plugin-scaffolder-backend-module-gitlab + +## 0.1.0-next.0 + +### Minor Changes + +- 1ad400bb2de: Add Gitlab Scaffolder Plugin + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.1.2-next.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/errors@1.1.5 diff --git a/plugins/scaffolder-backend-module-gitlab/README.md b/plugins/scaffolder-backend-module-gitlab/README.md new file mode 100644 index 0000000000..35353cf9c1 --- /dev/null +++ b/plugins/scaffolder-backend-module-gitlab/README.md @@ -0,0 +1,162 @@ +# scaffolder-backend-module-gitlab + +Welcome to the Gitlab Module for Scaffolder. + +Here you can find all Gitlab related features to improve your scaffolder: + +## Getting started + +## From your Backstage root directory + +```bash +# From your Backstage root directory +yarn add --cwd packages/backend @backstage/plugin-scaffolder-backend-module-gitlab +``` + +Configure the action: +(you can check the [docs](https://backstage.io/docs/features/software-templates/writing-custom-actions#registering-custom-actions) to see all options): + +```typescript +// packages/backend/src/plugins/scaffolder.ts + +import { + createGitlabProjectAccessTokenAction, + createGitlabProjectAccessTokenAction, + createGitlabProjectDeployTokenAction, +} from '@backstage/plugin-scaffolder-backend-module-gitlab'; + +// Create BuiltIn Actions +const builtInActions = createBuiltinActions({ + integrations, + catalogClient, + config: env.config, + reader: env.reader, +}); + +// Add Gitlab Actions +const actions = [ + ...builtInActions, + createGitlabProjectAccessTokenAction({ + integrations: integrations, + }), + createGitlabProjectAccessTokenAction({ + integrations: integrations, + }), + createGitlabProjectDeployTokenAction({ + integrations: integrations, + }), +]; + +// Create Scaffolder Router +return await createRouter({ + containerRunner, + catalogClient, + actions, + logger: env.logger, + config: env.config, + database: env.database, + reader: env.reader, +}); +``` + +After that you can use the action in your template: + +```yaml +apiVersion: scaffolder.backstage.io/v1beta3 +kind: Template +metadata: + name: gitlab-demo + title: Gitlab DEMO + description: Scaffolder Gitlab Demo +spec: + owner: backstage/techdocs-core + type: service + + parameters: + - title: Fill in some steps + required: + - name + properties: + name: + title: Name + type: string + description: Unique name of the component + ui:autofocus: true + ui:options: + rows: 5 + - title: Choose a location + required: + - repoUrl + properties: + repoUrl: + title: Repository Location + type: string + ui:field: RepoUrlPicker + ui:options: + allowedHosts: + - gitlab.com + + steps: + - id: fetch + name: Fetch + action: fetch:template + input: + url: https://github.com/TEMPLATE + values: + name: ${{ parameters.name }} + + - id: publish + name: Publish + action: publish:gitlab + input: + description: This is ${{ parameters.name }} + repoUrl: ${{ parameters.repoUrl }} + sourcePath: pimcore + defaultBranch: main + + - id: gitlab-deploy-token + name: Create Deploy Token + action: gitlab:projectDeployToken:create + input: + repoUrl: ${{ parameters.repoUrl }} + projectId: "${{ steps['publish'].output.projectId }}" + name: ${{ parameters.name }}-secret + username: ${{ parameters.name }}-secret + scopes: ['read_registry'] + + - id: gitlab-access-token + name: Gitlab Project Access Token + action: gitlab:projectAccessToken:create + input: + repoUrl: ${{ parameters.repoUrl }} + projectId: "${{ steps['publish-manifest'].output.projectId }}" + name: ${{ parameters.name }}-access-token + accessLevel: 40 + scopes: ['read_repository', 'write_repository'] + + - id: gitlab-project-variable + name: Gitlab Project Variable + action: gitlab:projectVariable:create + input: + repoUrl: ${{ parameters.repoUrl }} + projectId: "${{ steps['publish'].output.projectId }}" + key: 'VARIABLE_NAME' + value: "${{ steps['gitlab-access-token'].output.access_token }}" + variableType: 'env_var' + masked: true + variableProtected: false + raw: false + environmentScope: '*' + + - id: register + name: Register + action: catalog:register + input: + repoContentsUrl: ${{ steps['publish'].output.repoContentsUrl }} + catalogInfoPath: '/catalog-info.yaml' + + output: + links: + - title: Repository + url: ${{ steps['publish'].output.remoteUrl }} +``` diff --git a/plugins/scaffolder-backend-module-gitlab/api-report.md b/plugins/scaffolder-backend-module-gitlab/api-report.md new file mode 100644 index 0000000000..6db732fdcc --- /dev/null +++ b/plugins/scaffolder-backend-module-gitlab/api-report.md @@ -0,0 +1,48 @@ +## API Report File for "@backstage/plugin-scaffolder-backend-module-gitlab" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { ScmIntegrationRegistry } from '@backstage/integration'; +import { TemplateAction } from '@backstage/plugin-scaffolder-node'; + +// @public +export const createGitlabProjectAccessTokenAction: (options: { + integrations: ScmIntegrationRegistry; +}) => TemplateAction<{ + repoUrl: string; + projectId: string | number; + name: string; + accessLevel: number; + scopes: string[]; + token?: string | undefined; +}>; + +// @public +export const createGitlabProjectDeployTokenAction: (options: { + integrations: ScmIntegrationRegistry; +}) => TemplateAction<{ + repoUrl: string; + projectId: string | number; + name: string; + username: string; + scopes: string[]; + token?: string | undefined; +}>; + +// @public +export const createGitlabProjectVariableAction: (options: { + integrations: ScmIntegrationRegistry; +}) => TemplateAction<{ + repoUrl: string; + projectId: string | number; + key: string; + value: string; + variableType: string; + variableProtected: boolean; + masked: boolean; + raw: boolean; + environmentScope: string; + token?: string | undefined; +}>; +``` diff --git a/plugins/scaffolder-backend-module-gitlab/package.json b/plugins/scaffolder-backend-module-gitlab/package.json new file mode 100644 index 0000000000..e870ba57a0 --- /dev/null +++ b/plugins/scaffolder-backend-module-gitlab/package.json @@ -0,0 +1,48 @@ +{ + "name": "@backstage/plugin-scaffolder-backend-module-gitlab", + "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": "backend-plugin-module" + }, + "homepage": "https://backstage.io", + "repository": { + "type": "git", + "url": "https://github.com/backstage/backstage", + "directory": "plugins/scaffolder-backend-module-gitlab" + }, + "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/config": "workspace:^", + "@backstage/errors": "workspace:^", + "@backstage/integration": "workspace:^", + "@backstage/plugin-scaffolder-node": "workspace:^", + "@gitbeaker/node": "^35.8.0" + }, + "devDependencies": { + "@backstage/backend-common": "workspace:^", + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^" + }, + "files": [ + "dist" + ] +} diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabProjectAccessTokenAction.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabProjectAccessTokenAction.ts new file mode 100644 index 0000000000..0f39e3bc33 --- /dev/null +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabProjectAccessTokenAction.ts @@ -0,0 +1,112 @@ +/* + * 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 { createTemplateAction } from '@backstage/plugin-scaffolder-node'; +import { ScmIntegrationRegistry } from '@backstage/integration'; +import { getToken } from '../util'; + +/** + * Creates a `gitlab:create-project-access-token` Scaffolder action. + * + * @param options - Templating configuration. + * @public + */ +export const createGitlabProjectAccessTokenAction = (options: { + integrations: ScmIntegrationRegistry; +}) => { + const { integrations } = options; + return createTemplateAction<{ + repoUrl: string; + projectId: string | number; + name: string; + accessLevel: number; + scopes: string[]; + token?: string; + }>({ + id: 'gitlab:projectAccessToken:create', + schema: { + input: { + required: ['projectId', 'repoUrl'], + type: 'object', + properties: { + repoUrl: { + title: 'Repository Location', + type: 'string', + }, + projectId: { + title: 'Project ID', + type: ['string', 'number'], + }, + name: { + title: 'Deploy Token Name', + type: 'string', + }, + accessLevel: { + title: 'Access Level of the Token', + type: 'number', + }, + scopes: { + title: 'Scopes', + type: 'array', + }, + token: { + title: 'Authentication Token', + type: 'string', + description: 'The token to use for authorization to GitLab', + }, + }, + }, + output: { + type: 'object', + properties: { + access_token: { + title: 'Access Token', + type: 'string', + }, + }, + }, + }, + async handler(ctx) { + ctx.logger.info(`Creating Token for Project "${ctx.input.projectId}"`); + const { repoUrl, projectId, name, accessLevel, scopes } = ctx.input; + const { token, integrationConfig } = getToken( + repoUrl, + ctx.input.token, + integrations, + ); + + const response = await fetch( + `${integrationConfig.config.baseUrl}/api/v4/projects/${projectId}/access_tokens`, + { + method: 'POST', // *GET, POST, PUT, DELETE, etc. + headers: { + 'PRIVATE-TOKEN': token, + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + name: name, + scopes: scopes, + access_level: accessLevel, + }), + }, + ); + + const result = await response.json(); + + ctx.output('access_token', result.token); + }, + }); +}; diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabProjectDeployTokenAction.test.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabProjectDeployTokenAction.test.ts new file mode 100644 index 0000000000..1d3ae804c1 --- /dev/null +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabProjectDeployTokenAction.test.ts @@ -0,0 +1,101 @@ +/* + * 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 { createGitlabProjectDeployTokenAction } from './createGitlabProjectDeployTokenAction'; +import { ScmIntegrations } from '@backstage/integration'; +import { ConfigReader } from '@backstage/config'; +import { getVoidLogger } from '@backstage/backend-common'; +import { PassThrough } from 'stream'; + +const mockGitlabClient = { + ProjectDeployTokens: { + add: jest.fn(), + }, +}; +jest.mock('@gitbeaker/node', () => ({ + Gitlab: class { + constructor() { + return mockGitlabClient; + } + }, +})); + +describe('gitlab:create-deploy-token', () => { + const config = new ConfigReader({ + integrations: { + gitlab: [ + { + host: 'gitlab.com', + token: 'tokenlols', + apiBaseUrl: 'https://api.gitlab.com', + }, + { + host: 'hosted.gitlab.com', + apiBaseUrl: 'https://api.hosted.gitlab.com', + }, + ], + }, + }); + + const integrations = ScmIntegrations.fromConfig(config); + const action = createGitlabProjectDeployTokenAction({ integrations }); + const mockContext = { + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + projectId: '123', + name: 'tokenname', + username: 'tokenuser', + scopes: ['read_repository'], + }, + workspacePath: 'lol', + logger: getVoidLogger(), + logStream: new PassThrough(), + output: jest.fn(), + createTemporaryDirectory: jest.fn(), + }; + + beforeEach(() => { + jest.resetAllMocks(); + }); + + it('should work when there is a token provided through ctx.input', async () => { + mockGitlabClient.ProjectDeployTokens.add.mockResolvedValue({ + token: 'TOKEN', + username: 'User', + }); + + await action.handler({ + ...mockContext, + input: { + repoUrl: 'hosted.gitlab.com?repo=bob&owner=owner', + projectId: '123', + name: 'tokenname', + username: 'tokenuser', + scopes: ['read_repository'], + }, + }); + + expect(mockGitlabClient.ProjectDeployTokens.add).toHaveBeenCalledWith( + '123', + 'tokenname', + ['read_repository'], + { username: 'tokenuser' }, + ); + + expect(mockContext.output).toHaveBeenCalledWith('deploy_token', 'TOKEN'); + expect(mockContext.output).toHaveBeenCalledWith('user', 'User'); + }); +}); diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabProjectDeployTokenAction.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabProjectDeployTokenAction.ts new file mode 100644 index 0000000000..35a53c87e2 --- /dev/null +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabProjectDeployTokenAction.ts @@ -0,0 +1,120 @@ +/* + * 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 { createTemplateAction } from '@backstage/plugin-scaffolder-node'; +import { Gitlab } from '@gitbeaker/node'; +import { ScmIntegrationRegistry } from '@backstage/integration'; +import { DeployTokenScope } from '@gitbeaker/core/dist/types/templates/ResourceDeployTokens'; +import { getToken } from '../util'; +import { InputError } from '@backstage/errors'; + +/** + * Creates a `gitlab:create-project-deploy-token` Scaffolder action. + * + * @param options - Templating configuration. + * @public + */ +export const createGitlabProjectDeployTokenAction = (options: { + integrations: ScmIntegrationRegistry; +}) => { + const { integrations } = options; + return createTemplateAction<{ + repoUrl: string; + projectId: string | number; + name: string; + username: string; + scopes: string[]; + token?: string; + }>({ + id: 'gitlab:projectDeployToken:create', + schema: { + input: { + required: ['projectId', 'repoUrl'], + type: 'object', + properties: { + repoUrl: { + title: 'Repository Location', + type: 'string', + }, + projectId: { + title: 'Project ID', + type: ['string', 'number'], + }, + name: { + title: 'Deploy Token Name', + type: 'string', + }, + username: { + title: 'Deploy Token Username', + type: 'string', + }, + scopes: { + title: 'Scopes', + type: 'array', + }, + token: { + title: 'Authentication Token', + type: 'string', + description: 'The token to use for authorization to GitLab', + }, + }, + }, + output: { + type: 'object', + properties: { + deploy_token: { + title: 'Deploy Token', + type: 'string', + }, + user: { + title: 'User', + type: 'string', + }, + }, + }, + }, + async handler(ctx) { + ctx.logger.info(`Creating Token for Project "${ctx.input.projectId}"`); + const { repoUrl, projectId, name, username, scopes } = ctx.input; + const { token, integrationConfig } = getToken( + repoUrl, + ctx.input.token, + integrations, + ); + + const api = new Gitlab({ + host: integrationConfig.config.baseUrl, + token: token, + }); + + const deployToken = await api.ProjectDeployTokens.add( + projectId, + name, + scopes as DeployTokenScope[], + { + username: username, + }, + ); + + if (!deployToken.hasOwnProperty('token')) { + throw new InputError(`No deploy_token given from gitlab instance`); + } + + ctx.output('deploy_token', deployToken.token as string); + ctx.output('user', deployToken.username); + }, + }); +}; diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabProjectVariableAction.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabProjectVariableAction.ts new file mode 100644 index 0000000000..847bbc2057 --- /dev/null +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabProjectVariableAction.ts @@ -0,0 +1,139 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createTemplateAction } from '@backstage/plugin-scaffolder-node'; +import { ScmIntegrationRegistry } from '@backstage/integration'; +import { getToken } from '../util'; +import { Gitlab } from '@gitbeaker/node'; + +/** + * Creates a `gitlab:create-project-variable` Scaffolder action. + * + * @param options - Templating configuration. + * @public + */ +export const createGitlabProjectVariableAction = (options: { + integrations: ScmIntegrationRegistry; +}) => { + const { integrations } = options; + return createTemplateAction<{ + repoUrl: string; + projectId: string | number; + key: string; + value: string; + variableType: string; + variableProtected: boolean; + masked: boolean; + raw: boolean; + environmentScope: string; + token?: string; + }>({ + id: 'gitlab:projectVariable:create', + schema: { + input: { + required: [ + 'repoUrl', + 'projectId', + 'key', + 'value', + 'variableType', + 'variableProtected', + 'masked', + 'raw', + 'environmentScope', + ], + type: 'object', + properties: { + repoUrl: { + title: 'Repository Location', + type: 'string', + }, + projectId: { + title: 'Project ID', + type: ['string', 'number'], + }, + key: { + title: + 'The key of a variable; must have no more than 255 characters; only A-Z, a-z, 0-9, and _ are allowed', + type: 'string', + }, + value: { + title: 'The value of a variable', + type: 'string', + }, + variableType: { + title: 'Variable Type (env_var or file)', + type: 'string', + }, + variableProtected: { + title: 'Whether the variable is protected. Default: false', + type: 'boolean', + }, + masked: { + title: 'Whether the variable is masked. Default: false', + type: 'boolean', + }, + raw: { + title: 'Whether the variable is expandable. Default: false', + type: 'boolean', + }, + environmentScope: { + title: 'The environment_scope of the variable. Default: *', + type: 'string', + }, + token: { + title: 'Authentication Token', + type: 'string', + description: 'The token to use for authorization to GitLab', + }, + }, + }, + }, + async handler(ctx) { + const { + repoUrl, + projectId, + key, + value, + variableType, + variableProtected, + masked, + raw, + environmentScope, + } = ctx.input; + const { token, integrationConfig } = getToken( + repoUrl, + ctx.input.token, + integrations, + ); + + const api = new Gitlab({ + host: integrationConfig.config.baseUrl, + token: token, + }); + + await api.ProjectVariables.create(projectId, { + key: key, + value: value, + variable_type: variableType, + protected: variableProtected, + masked: masked, + raw: raw, + environment_scope: environmentScope, + }); + }, + }); +}; diff --git a/plugins/scaffolder-backend-module-gitlab/src/index.ts b/plugins/scaffolder-backend-module-gitlab/src/index.ts new file mode 100644 index 0000000000..11209e19bd --- /dev/null +++ b/plugins/scaffolder-backend-module-gitlab/src/index.ts @@ -0,0 +1,24 @@ +/* + * 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. + */ +/** + * A module for the scaffolder backend that lets you create gitlab project access tokens or deploy tokens + * + * @packageDocumentation + */ + +export * from './actions/createGitlabProjectDeployTokenAction'; +export * from './actions/createGitlabProjectAccessTokenAction'; +export * from './actions/createGitlabProjectVariableAction'; diff --git a/plugins/scaffolder-backend-module-gitlab/src/util.ts b/plugins/scaffolder-backend-module-gitlab/src/util.ts new file mode 100644 index 0000000000..fc6667d6d3 --- /dev/null +++ b/plugins/scaffolder-backend-module-gitlab/src/util.ts @@ -0,0 +1,57 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { InputError } from '@backstage/errors'; +import { + GitLabIntegration, + ScmIntegrationRegistry, +} from '@backstage/integration'; + +export const parseRepoHost = (repoUrl: string): string => { + let parsed; + try { + parsed = new URL(`https://${repoUrl}`); + } catch (error) { + throw new InputError( + `Invalid repo URL passed to publisher, got ${repoUrl}, ${error}`, + ); + } + return parsed.host; +}; + +export const getToken = ( + repoUrl: string, + inputToken: string | null | undefined, + integrations: ScmIntegrationRegistry, +): { token: string; integrationConfig: GitLabIntegration } => { + const host = parseRepoHost(repoUrl); + const integrationConfig = integrations.gitlab.byHost(host); + + if (!integrationConfig) { + throw new InputError( + `No matching integration configuration for host ${host}, please check your integrations config`, + ); + } + + const token = inputToken || integrationConfig.config.token!; + const tokenType = inputToken ? 'oauthToken' : 'token'; + + if (tokenType === 'oauthToken') { + throw new InputError(`OAuth Token is currently not supported`); + } + + return { token: token, integrationConfig: integrationConfig }; +}; diff --git a/plugins/scaffolder-backend-module-rails/CHANGELOG.md b/plugins/scaffolder-backend-module-rails/CHANGELOG.md index 457cef36bb..bd3509dbd0 100644 --- a/plugins/scaffolder-backend-module-rails/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-rails/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-scaffolder-backend-module-rails +## 0.4.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.12.1-next.0 + - @backstage/plugin-scaffolder-node@0.1.2-next.0 + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/errors@1.1.5 + - @backstage/types@1.0.2 + ## 0.4.11 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-rails/package.json b/plugins/scaffolder-backend-module-rails/package.json index 96da1120e8..aa1a178d9d 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.11", + "version": "0.4.12-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder-backend-module-sentry/CHANGELOG.md b/plugins/scaffolder-backend-module-sentry/CHANGELOG.md index 5207cdec38..67772961ab 100644 --- a/plugins/scaffolder-backend-module-sentry/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-sentry/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-scaffolder-backend-module-sentry +## 0.1.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.1.2-next.0 + - @backstage/config@1.0.7 + - @backstage/errors@1.1.5 + ## 0.1.3 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-sentry/package.json b/plugins/scaffolder-backend-module-sentry/package.json index bff7043171..6f04036110 100644 --- a/plugins/scaffolder-backend-module-sentry/package.json +++ b/plugins/scaffolder-backend-module-sentry/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-sentry", - "version": "0.1.3", + "version": "0.1.4-next.0", "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 36e965218d..2948bbc79b 100644 --- a/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-scaffolder-backend-module-yeoman +## 0.2.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.1.2-next.0 + - @backstage/config@1.0.7 + - @backstage/types@1.0.2 + ## 0.2.16 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-yeoman/package.json b/plugins/scaffolder-backend-module-yeoman/package.json index 9aeee3ec51..50db3c38d0 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.16", + "version": "0.2.17-next.0", "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 0cd0e43f9d..89bfc23549 100644 --- a/plugins/scaffolder-backend/CHANGELOG.md +++ b/plugins/scaffolder-backend/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-scaffolder-backend +## 1.12.1-next.0 + +### Patch Changes + +- e23abb37ec1: Rename output parameter `mergeRequestURL` of `publish:gitlab:merge-request` action to `mergeRequestUrl`. +- e27ddc36dad: Added a possibility to cancel the running task (executing of a scaffolder template) +- c9a0fdcd2c8: Fix deprecated types. +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.1.2-next.0 + - @backstage/plugin-scaffolder-common@1.2.7-next.0 + - @backstage/plugin-catalog-backend@1.8.1-next.0 + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/types@1.0.2 + - @backstage/plugin-auth-node@0.2.13-next.0 + - @backstage/plugin-catalog-common@1.0.12 + - @backstage/plugin-catalog-node@1.3.5-next.0 + ## 1.12.0 ### Minor Changes diff --git a/plugins/scaffolder-backend/alpha-api-report.md b/plugins/scaffolder-backend/alpha-api-report.md index 3199444c6b..2ecd2cc800 100644 --- a/plugins/scaffolder-backend/alpha-api-report.md +++ b/plugins/scaffolder-backend/alpha-api-report.md @@ -4,14 +4,43 @@ ```ts import { BackendFeature } from '@backstage/backend-plugin-api'; +import { ConditionalPolicyDecision } from '@backstage/plugin-permission-common'; +import { Conditions } from '@backstage/plugin-permission-node'; +import { PermissionCondition } from '@backstage/plugin-permission-common'; +import { PermissionCriteria } from '@backstage/plugin-permission-common'; +import { PermissionRule } from '@backstage/plugin-permission-node'; +import { PermissionRuleParams } from '@backstage/plugin-permission-common'; +import { ResourcePermission } from '@backstage/plugin-permission-common'; import { TaskBroker } from '@backstage/plugin-scaffolder-backend'; import { TemplateAction } from '@backstage/plugin-scaffolder-node'; +import { TemplateEntityStepV1beta3 } from '@backstage/plugin-scaffolder-common'; import { TemplateFilter } from '@backstage/plugin-scaffolder-backend'; import { TemplateGlobal } from '@backstage/plugin-scaffolder-backend'; +import { TemplateParametersV1beta3 } from '@backstage/plugin-scaffolder-common'; // @alpha export const catalogModuleTemplateKind: () => BackendFeature; +// @alpha +export const createScaffolderConditionalDecision: ( + permission: ResourcePermission<'scaffolder-template'>, + conditions: PermissionCriteria< + PermissionCondition<'scaffolder-template', PermissionRuleParams> + >, +) => ConditionalPolicyDecision; + +// @alpha +export const scaffolderConditions: Conditions<{ + hasTag: PermissionRule< + TemplateParametersV1beta3 | TemplateEntityStepV1beta3, + {}, + 'scaffolder-template', + { + tag: string; + } + >; +}>; + // @alpha export const scaffolderPlugin: ( options: ScaffolderPluginOptions, diff --git a/plugins/scaffolder-backend/api-report.md b/plugins/scaffolder-backend/api-report.md index 452689c2ea..be24be46cc 100644 --- a/plugins/scaffolder-backend/api-report.md +++ b/plugins/scaffolder-backend/api-report.md @@ -7,23 +7,29 @@ import { ActionContext as ActionContext_2 } from '@backstage/plugin-scaffolder-node'; import { CatalogApi } from '@backstage/catalog-client'; -import { CatalogProcessor } from '@backstage/plugin-catalog-backend'; -import { CatalogProcessorEmit } from '@backstage/plugin-catalog-backend'; +import { CatalogProcessor } from '@backstage/plugin-catalog-node'; +import { CatalogProcessorEmit } from '@backstage/plugin-catalog-node'; import { Config } from '@backstage/config'; import { createPullRequest } from 'octokit-plugin-create-pull-request'; +import { Duration } from 'luxon'; import { Entity } from '@backstage/catalog-model'; import express from 'express'; import { GithubCredentialsProvider } from '@backstage/integration'; +import { HumanDuration } from '@backstage/types'; import { IdentityApi } from '@backstage/plugin-auth-node'; import { JsonObject } from '@backstage/types'; import { JsonValue } from '@backstage/types'; import { Knex } from 'knex'; -import { LocationSpec } from '@backstage/plugin-catalog-backend'; +import { LocationSpec } from '@backstage/plugin-catalog-common'; import { Logger } from 'winston'; import { Observable } from '@backstage/types'; import { Octokit } from 'octokit'; +import { PermissionEvaluator } from '@backstage/plugin-permission-common'; +import { PermissionRule } from '@backstage/plugin-permission-node'; +import { PermissionRuleParams } from '@backstage/plugin-permission-common'; import { PluginDatabaseManager } from '@backstage/backend-common'; import { PluginTaskScheduler } from '@backstage/backend-tasks'; +import { RESOURCE_TYPE_SCAFFOLDER_TEMPLATE } from '@backstage/plugin-scaffolder-common/alpha'; import { Schema } from 'jsonschema'; import { ScmIntegrationRegistry } from '@backstage/integration'; import { ScmIntegrations } from '@backstage/integration'; @@ -33,6 +39,8 @@ import { TaskSpec } from '@backstage/plugin-scaffolder-common'; import { TaskSpecV1beta3 } from '@backstage/plugin-scaffolder-common'; import { TemplateAction as TemplateAction_2 } from '@backstage/plugin-scaffolder-node'; import { TemplateActionOptions } from '@backstage/plugin-scaffolder-node'; +import { TemplateEntityStepV1beta3 } from '@backstage/plugin-scaffolder-common'; +import { TemplateParametersV1beta3 } from '@backstage/plugin-scaffolder-common'; import { UrlReader } from '@backstage/backend-common'; import { Writable } from 'stream'; import { ZodType } from 'zod'; @@ -103,6 +111,15 @@ export function createFetchPlainAction(options: { targetPath?: string | undefined; }>; +// @public +export function createFetchPlainFileAction(options: { + reader: UrlReader; + integrations: ScmIntegrations; +}): TemplateAction_2<{ + url: string; + targetPath: string; +}>; + // @public export function createFetchTemplateAction(options: { reader: UrlReader; @@ -528,6 +545,11 @@ export const createTemplateAction: < action: TemplateActionOptions, ) => TemplateAction_2; +// @public +export function createWaitAction(options?: { + maxWaitTime?: Duration | HumanDuration; +}): TemplateAction_2; + // @public export type CreateWorkerOptions = { taskBroker: TaskBroker; @@ -550,6 +572,14 @@ export interface CurrentClaimedTask { // @public export class DatabaseTaskStore implements TaskStore { + // (undocumented) + cancelTask( + options: TaskStoreEmitOptions< + { + message: string; + } & JsonObject + >, + ): Promise; // (undocumented) claimTask(): Promise; // (undocumented) @@ -641,6 +671,10 @@ export interface RouterOptions { // (undocumented) logger: Logger; // (undocumented) + permissionApi?: PermissionEvaluator; + // (undocumented) + permissionRules?: TemplatePermissionRuleInput[]; + // (undocumented) reader: UrlReader; // (undocumented) scheduler?: PluginTaskScheduler; @@ -694,6 +728,8 @@ export type SerializedTaskEvent = { // @public export interface TaskBroker { + // (undocumented) + cancel?(taskId: string): Promise; // (undocumented) claim(): Promise; // (undocumented) @@ -731,6 +767,8 @@ export type TaskCompletionState = 'failed' | 'completed'; // @public export interface TaskContext { + // (undocumented) + cancelSignal: AbortSignal; // (undocumented) complete(result: TaskCompletionState, metadata?: JsonObject): Promise; // (undocumented) @@ -750,16 +788,19 @@ export interface TaskContext { } // @public -export type TaskEventType = 'completion' | 'log'; +export type TaskEventType = 'completion' | 'log' | 'cancelled'; // @public export class TaskManager implements TaskContext { + // (undocumented) + get cancelSignal(): AbortSignal; // (undocumented) complete(result: TaskCompletionState, metadata?: JsonObject): Promise; // (undocumented) static create( task: CurrentClaimedTask, storage: TaskStore, + abortSignal: AbortSignal, logger: Logger, ): TaskManager; // (undocumented) @@ -781,14 +822,16 @@ export type TaskSecrets = TaskSecrets_2; // @public export type TaskStatus = - | 'open' - | 'processing' - | 'failed' | 'cancelled' - | 'completed'; + | 'completed' + | 'failed' + | 'open' + | 'processing'; // @public export interface TaskStore { + // (undocumented) + cancelTask?(options: TaskStoreEmitOptions): Promise; // (undocumented) claimTask(): Promise; // (undocumented) @@ -887,4 +930,14 @@ export type TemplateFilter = (...args: JsonValue[]) => JsonValue | undefined; export type TemplateGlobal = | ((...args: JsonValue[]) => JsonValue | undefined) | JsonValue; + +// @public (undocumented) +export type TemplatePermissionRuleInput< + TParams extends PermissionRuleParams = PermissionRuleParams, +> = PermissionRule< + TemplateEntityStepV1beta3 | TemplateParametersV1beta3, + {}, + typeof RESOURCE_TYPE_SCAFFOLDER_TEMPLATE, + TParams +>; ``` diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index d7eae0580a..93506eb01c 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.12.0", + "version": "1.12.1-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -56,7 +56,10 @@ "@backstage/integration": "workspace:^", "@backstage/plugin-auth-node": "workspace:^", "@backstage/plugin-catalog-backend": "workspace:^", + "@backstage/plugin-catalog-common": "workspace:^", "@backstage/plugin-catalog-node": "workspace:^", + "@backstage/plugin-permission-common": "workspace:^", + "@backstage/plugin-permission-node": "workspace:^", "@backstage/plugin-scaffolder-common": "workspace:^", "@backstage/plugin-scaffolder-node": "workspace:^", "@backstage/types": "workspace:^", @@ -64,6 +67,7 @@ "@gitbeaker/node": "^35.1.0", "@octokit/webhooks": "^10.0.0", "@types/express": "^4.17.6", + "@types/luxon": "^3.0.0", "azure-devops-node-api": "^11.0.1", "command-exists": "^1.2.9", "compression": "^1.7.4", @@ -109,6 +113,7 @@ "mock-fs": "^5.1.0", "msw": "^1.0.0", "supertest": "^6.1.3", + "wait-for-expect": "^3.0.2", "yaml": "^2.0.0" }, "files": [ diff --git a/plugins/scaffolder-backend/src/ScaffolderPlugin.ts b/plugins/scaffolder-backend/src/ScaffolderPlugin.ts index 182bb60223..97abf41828 100644 --- a/plugins/scaffolder-backend/src/ScaffolderPlugin.ts +++ b/plugins/scaffolder-backend/src/ScaffolderPlugin.ts @@ -94,6 +94,7 @@ export const scaffolderPlugin = createBackendPlugin( database, httpRouter, catalogClient, + permissions, }) { const { additionalTemplateFilters, @@ -131,6 +132,7 @@ export const scaffolderPlugin = createBackendPlugin( taskWorkers, additionalTemplateFilters, additionalTemplateGlobals, + permissionApi: permissions, }); httpRouter.use(router); }, diff --git a/plugins/scaffolder-backend/src/alpha.ts b/plugins/scaffolder-backend/src/alpha.ts index ac96f081ad..713f2569aa 100644 --- a/plugins/scaffolder-backend/src/alpha.ts +++ b/plugins/scaffolder-backend/src/alpha.ts @@ -15,5 +15,6 @@ */ export * from './modules'; +export * from './service'; export { scaffolderPlugin } from './ScaffolderPlugin'; export type { ScaffolderPluginOptions } from './ScaffolderPlugin'; diff --git a/plugins/scaffolder-backend/src/processor/ScaffolderEntitiesProcessor.ts b/plugins/scaffolder-backend/src/processor/ScaffolderEntitiesProcessor.ts index d095b77b4c..1de381a8ff 100644 --- a/plugins/scaffolder-backend/src/processor/ScaffolderEntitiesProcessor.ts +++ b/plugins/scaffolder-backend/src/processor/ScaffolderEntitiesProcessor.ts @@ -24,9 +24,9 @@ import { import { CatalogProcessor, CatalogProcessorEmit, - LocationSpec, processingResult, -} from '@backstage/plugin-catalog-backend'; +} from '@backstage/plugin-catalog-node'; +import { LocationSpec } from '@backstage/plugin-catalog-common'; import { TemplateEntityV1beta3, templateEntityV1beta3Validator, diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts index 9ba4a27b1a..747b5cdaed 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts @@ -30,8 +30,12 @@ import { } from './catalog'; import { TemplateFilter, TemplateGlobal } from '../../../lib'; -import { createDebugLogAction } from './debug'; -import { createFetchPlainAction, createFetchTemplateAction } from './fetch'; +import { createDebugLogAction, createWaitAction } from './debug'; +import { + createFetchPlainAction, + createFetchPlainFileAction, + createFetchTemplateAction, +} from './fetch'; import { createFilesystemDeleteAction, createFilesystemRenameAction, @@ -112,6 +116,10 @@ export const createBuiltinActions = ( reader, integrations, }), + createFetchPlainFileAction({ + reader, + integrations, + }), createFetchTemplateAction({ integrations, reader, @@ -159,6 +167,7 @@ export const createBuiltinActions = ( config, }), createDebugLogAction(), + createWaitAction(), createCatalogRegisterAction({ catalogClient, integrations }), createFetchCatalogEntityAction({ catalogClient }), createCatalogWriteAction(), diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/debug/index.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/debug/index.ts index 8cc50a7eba..3776ce7f03 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/debug/index.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/debug/index.ts @@ -15,3 +15,4 @@ */ export { createDebugLogAction } from './log'; +export { createWaitAction } from './wait'; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/debug/wait.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/debug/wait.test.ts new file mode 100644 index 0000000000..0d4cdaba4b --- /dev/null +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/debug/wait.test.ts @@ -0,0 +1,76 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { getVoidLogger } from '@backstage/backend-common'; +import mockFs from 'mock-fs'; +import { createWaitAction } from './wait'; +import { Writable } from 'stream'; +import os from 'os'; + +describe('debug:wait', () => { + const action = createWaitAction(); + + const logStream = { + write: jest.fn(), + } as jest.Mocked> as jest.Mocked; + + const mockTmpDir = os.tmpdir(); + const mockContext = { + input: {}, + baseUrl: 'somebase', + workspacePath: mockTmpDir, + logger: getVoidLogger(), + logStream, + output: jest.fn(), + createTemporaryDirectory: jest.fn().mockResolvedValue(mockTmpDir), + }; + + beforeEach(() => { + jest.resetAllMocks(); + }); + + afterEach(() => { + mockFs.restore(); + }); + + it('should wait for specified period of time', async () => { + const context = { + ...mockContext, + input: { + milliseconds: 50, + }, + }; + const start = new Date().getTime(); + await action.handler(context); + const end = new Date().getTime(); + expect(end - start).toBeGreaterThanOrEqual(50); + }); + + it('should not allow to set waiting time longer than the max waiting time', async () => { + const context = { + ...mockContext, + input: { + minutes: 11, + }, + }; + + await expect(async () => { + await action.handler(context); + }).rejects.toThrow( + 'Waiting duration is longer than the maximum threshold of 0 hours, 0 minutes, 30 seconds', + ); + }); +}); diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/debug/wait.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/debug/wait.ts new file mode 100644 index 0000000000..02cab239cb --- /dev/null +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/debug/wait.ts @@ -0,0 +1,131 @@ +/* + * 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 { createTemplateAction } from '@backstage/plugin-scaffolder-node'; +import { HumanDuration } from '@backstage/types'; +import yaml from 'yaml'; +import { Duration } from 'luxon'; + +const id = 'debug:wait'; + +const MAX_WAIT_TIME_IN_ISO = 'T00:00:30'; + +const examples = [ + { + description: 'Waiting for 5 seconds', + example: yaml.stringify({ + steps: [ + { + action: id, + id: 'wait-5sec', + name: 'Waiting for 5 seconds', + input: { + seconds: 5, + }, + }, + ], + }), + }, + { + description: 'Waiting for 5 minutes', + example: yaml.stringify({ + steps: [ + { + action: id, + id: 'wait-5min', + name: 'Waiting for 5 minutes', + input: { + minutes: 5, + }, + }, + ], + }), + }, +]; + +/** + * Waits for a certain period of time. + * + * @remarks + * + * This task is useful to give some waiting time for manual intervention. + * Has to be used in a combination with other actions. + * + * @public + */ +export function createWaitAction(options?: { + maxWaitTime?: Duration | HumanDuration; +}) { + const toDuration = ( + maxWaitTime: Duration | HumanDuration | undefined, + ): Duration => { + if (maxWaitTime) { + if (maxWaitTime instanceof Duration) { + return maxWaitTime; + } + return Duration.fromObject(maxWaitTime); + } + return Duration.fromISOTime(MAX_WAIT_TIME_IN_ISO); + }; + + return createTemplateAction({ + id, + description: 'Waits for a certain period of time.', + examples, + schema: { + input: { + type: 'object', + properties: { + minutes: { + title: 'Waiting period in minutes.', + type: 'number', + }, + seconds: { + title: 'Waiting period in seconds.', + type: 'number', + }, + milliseconds: { + title: 'Waiting period in milliseconds.', + type: 'number', + }, + }, + }, + }, + async handler(ctx) { + const delayTime = Duration.fromObject(ctx.input); + const maxWait = toDuration(options?.maxWaitTime); + + if (delayTime.minus(maxWait).toMillis() > 0) { + throw new Error( + `Waiting duration is longer than the maximum threshold of ${maxWait.toHuman()}`, + ); + } + + await new Promise(resolve => { + const controller = new AbortController(); + const timeoutHandle = setTimeout(abort, delayTime.toMillis()); + ctx.signal?.addEventListener('abort', abort); + + function abort() { + ctx.signal?.removeEventListener('abort', abort); + clearTimeout(timeoutHandle!); + controller.abort(); + resolve('finished'); + } + }); + }, + }); +} diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/helpers.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/helpers.test.ts index 86d5f17803..3c4a677d4d 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/helpers.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/helpers.test.ts @@ -21,7 +21,7 @@ import { resolve as resolvePath } from 'path'; import { UrlReader } from '@backstage/backend-common'; import { ConfigReader } from '@backstage/config'; import { ScmIntegrations } from '@backstage/integration'; -import { fetchContents } from './helpers'; +import { fetchContents, fetchFile } from './helpers'; import os from 'os'; describe('fetchContent helper', () => { @@ -37,9 +37,10 @@ describe('fetchContent helper', () => { }), ); + const readUrl = jest.fn(); const readTree = jest.fn(); const reader: UrlReader = { - readUrl: jest.fn(), + readUrl, readTree, search: jest.fn(), }; @@ -50,73 +51,165 @@ describe('fetchContent helper', () => { outputPath: os.tmpdir(), }; - it('should reject absolute file locations', async () => { - await expect( - fetchContents({ - ...options, - baseUrl: 'file:///some/path', - fetchUrl: '/etc/passwd', - }), - ).rejects.toThrow( - 'Relative path is not allowed to refer to a directory outside its parent', - ); - }); - - it('should reject relative file locations that exit the baseUrl', async () => { - await expect( - fetchContents({ - ...options, - baseUrl: 'file:///some/path', - fetchUrl: '../test', - }), - ).rejects.toThrow( - 'Relative path is not allowed to refer to a directory outside its parent', - ); - }); - - it('should copy file to outputpath', async () => { - await fetchContents({ - ...options, - baseUrl: 'file:///some/path', - fetchUrl: 'foo', - outputPath: 'somepath', + describe('fetch contents', () => { + it('should reject absolute file locations', async () => { + await expect( + fetchContents({ + ...options, + baseUrl: 'file:///some/path', + fetchUrl: '/etc/passwd', + }), + ).rejects.toThrow( + 'Relative path is not allowed to refer to a directory outside its parent', + ); }); - expect(fs.copy).toHaveBeenCalledWith(resolvePath('/some/foo'), 'somepath'); - }); - it('should reject if no integration matches location', async () => { - await expect( - fetchContents({ - ...options, - baseUrl: 'http://example.com/some/folder', - }), - ).rejects.toThrow( - 'No integration found for location http://example.com/some/folder', - ); - }); + it('should reject relative file locations that exit the baseUrl', async () => { + await expect( + fetchContents({ + ...options, + baseUrl: 'file:///some/path', + fetchUrl: '../test', + }), + ).rejects.toThrow( + 'Relative path is not allowed to refer to a directory outside its parent', + ); + }); - it('should reject if fetch url is relative and no base url is specified', async () => { - await expect( - fetchContents({ + it('should copy file to outputpath', async () => { + await fetchContents({ ...options, + baseUrl: 'file:///some/path', fetchUrl: 'foo', - }), - ).rejects.toThrow( - 'Failed to fetch, template location could not be determined and the fetch URL is relative, foo', - ); + outputPath: 'somepath', + }); + expect(fs.copy).toHaveBeenCalledWith( + resolvePath('/some/foo'), + 'somepath', + ); + }); + + it('should reject if no integration matches location', async () => { + await expect( + fetchContents({ + ...options, + baseUrl: 'http://example.com/some/folder', + }), + ).rejects.toThrow( + 'No integration found for location http://example.com/some/folder', + ); + }); + + it('should reject if fetch url is relative and no base url is specified', async () => { + await expect( + fetchContents({ + ...options, + fetchUrl: 'foo', + }), + ).rejects.toThrow( + 'Failed to fetch, template location could not be determined and the fetch URL is relative, foo', + ); + }); + + it('should fetch url contents', async () => { + const dirFunction = jest.fn(); + readTree.mockResolvedValue({ + dir: dirFunction, + }); + await fetchContents({ + ...options, + outputPath: 'foo', + fetchUrl: 'https://github.com/backstage/foo', + }); + expect(fs.ensureDir).toHaveBeenCalledWith('foo'); + expect(dirFunction).toHaveBeenCalledWith({ targetDir: 'foo' }); + }); }); - it('should fetch url contents', async () => { - const dirFunction = jest.fn(); - readTree.mockResolvedValue({ - dir: dirFunction, + describe('fetch file', () => { + it('should reject absolute file locations', async () => { + await expect( + fetchFile({ + ...options, + baseUrl: 'file:///some/path', + fetchUrl: '/etc/passwd', + }), + ).rejects.toThrow( + 'Relative path is not allowed to refer to a directory outside its parent', + ); }); - await fetchContents({ - ...options, - outputPath: 'foo', - fetchUrl: 'https://github.com/backstage/foo', + + it('should reject relative file locations that exit the baseUrl', async () => { + await expect( + fetchFile({ + ...options, + baseUrl: 'file:///some/path', + fetchUrl: '../test', + }), + ).rejects.toThrow( + 'Relative path is not allowed to refer to a directory outside its parent', + ); + }); + + it('should copy file to outputpath', async () => { + await fetchFile({ + ...options, + baseUrl: 'file:///some/path', + fetchUrl: 'foo', + outputPath: 'somepath', + }); + expect(fs.copyFile).toHaveBeenCalledWith( + resolvePath('/some/foo'), + 'somepath', + ); + }); + + it('should reject if no integration matches location', async () => { + await expect( + fetchFile({ + ...options, + baseUrl: 'http://example.com/some/folder', + }), + ).rejects.toThrow( + 'No integration found for location http://example.com/some/folder', + ); + }); + + it('should reject if fetch url is relative and no base url is specified', async () => { + await expect( + fetchFile({ + ...options, + fetchUrl: 'foo', + }), + ).rejects.toThrow( + 'Failed to fetch, template location could not be determined and the fetch URL is relative, foo', + ); + }); + + it('should fetch content from url', async () => { + readUrl.mockResolvedValue({ + buffer: () => Buffer.from('test', 'utf8'), + }); + await fetchFile({ + ...options, + outputPath: 'foo', + fetchUrl: 'https://github.com/backstage/foo', + }); + expect(fs.ensureDir).toHaveBeenCalledWith('.'); + expect(fs.outputFile).toHaveBeenCalledWith('foo', 'test'); + }); + + it('should fetch content from url into directory', async () => { + readUrl.mockResolvedValue({ + buffer: () => Buffer.from('test', 'utf8'), + }); + await fetchFile({ + ...options, + outputPath: 'mydir/foo', + fetchUrl: 'https://github.com/backstage/foo', + }); + expect(fs.ensureDir).toHaveBeenCalledWith('mydir'); + expect(fs.outputFile).toHaveBeenCalledWith('mydir/foo', 'test'); }); - expect(fs.ensureDir).toHaveBeenCalled(); - expect(dirFunction).toHaveBeenCalledWith({ targetDir: 'foo' }); }); }); diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/helpers.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/helpers.ts index 4b82595cfd..301c9991c4 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/helpers.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/helpers.ts @@ -35,6 +35,53 @@ export async function fetchContents(options: { }) { const { reader, integrations, baseUrl, fetchUrl = '.', outputPath } = options; + const fetchUrlIsAbsolute = isFetchUrlAbsolute(fetchUrl); + + // We handle both file locations and url ones + if (!fetchUrlIsAbsolute && baseUrl?.startsWith('file://')) { + const basePath = baseUrl.slice('file://'.length); + const srcDir = resolveSafeChildPath(path.dirname(basePath), fetchUrl); + await fs.copy(srcDir, outputPath); + } else { + const readUrl = getReadUrl(fetchUrl, baseUrl, integrations); + + const res = await reader.readTree(readUrl); + await fs.ensureDir(outputPath); + await res.dir({ targetDir: outputPath }); + } +} + +/** + * A helper function that reads the content of a single file from the given URL. + * Can be used in your own actions, and also used behind `fetch:plain:file` + */ +export async function fetchFile(options: { + reader: UrlReader; + integrations: ScmIntegrations; + baseUrl?: string; + fetchUrl?: string; + outputPath: string; +}) { + const { reader, integrations, baseUrl, fetchUrl = '.', outputPath } = options; + + const fetchUrlIsAbsolute = isFetchUrlAbsolute(fetchUrl); + + // We handle both file locations and url ones + if (!fetchUrlIsAbsolute && baseUrl?.startsWith('file://')) { + const basePath = baseUrl.slice('file://'.length); + const src = resolveSafeChildPath(path.dirname(basePath), fetchUrl); + await fs.copyFile(src, outputPath); + } else { + const readUrl = getReadUrl(fetchUrl, baseUrl, integrations); + + const res = await reader.readUrl(readUrl); + await fs.ensureDir(path.dirname(outputPath)); + const buffer = await res.buffer(); + await fs.outputFile(outputPath, buffer.toString()); + } +} + +function isFetchUrlAbsolute(fetchUrl: string) { let fetchUrlIsAbsolute = false; try { // eslint-disable-next-line no-new @@ -43,35 +90,28 @@ export async function fetchContents(options: { } catch { /* ignored */ } + return fetchUrlIsAbsolute; +} - // We handle both file locations and url ones - if (!fetchUrlIsAbsolute && baseUrl?.startsWith('file://')) { - const basePath = baseUrl.slice('file://'.length); - const srcDir = resolveSafeChildPath(path.dirname(basePath), fetchUrl); - await fs.copy(srcDir, outputPath); - } else { - let readUrl; - - if (fetchUrlIsAbsolute) { - readUrl = fetchUrl; - } else if (baseUrl) { - const integration = integrations.byUrl(baseUrl); - if (!integration) { - throw new InputError(`No integration found for location ${baseUrl}`); - } - - readUrl = integration.resolveUrl({ - url: fetchUrl, - base: baseUrl, - }); - } else { - throw new InputError( - `Failed to fetch, template location could not be determined and the fetch URL is relative, ${fetchUrl}`, - ); +function getReadUrl( + fetchUrl: string, + baseUrl: string | undefined, + integrations: ScmIntegrations, +) { + if (isFetchUrlAbsolute(fetchUrl)) { + return fetchUrl; + } else if (baseUrl) { + const integration = integrations.byUrl(baseUrl); + if (!integration) { + throw new InputError(`No integration found for location ${baseUrl}`); } - const res = await reader.readTree(readUrl); - await fs.ensureDir(outputPath); - await res.dir({ targetDir: outputPath }); + return integration.resolveUrl({ + url: fetchUrl, + base: baseUrl, + }); } + throw new InputError( + `Failed to fetch, template location could not be determined and the fetch URL is relative, ${fetchUrl}`, + ); } diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/index.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/index.ts index c9a16c274e..14a40f53c3 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/index.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/index.ts @@ -15,5 +15,6 @@ */ export { createFetchPlainAction } from './plain'; +export { createFetchPlainFileAction } from './plainFile'; export { createFetchTemplateAction } from './template'; export { fetchContents } from './helpers'; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/plainFile.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/plainFile.test.ts new file mode 100644 index 0000000000..5d9e99fc7d --- /dev/null +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/plainFile.test.ts @@ -0,0 +1,85 @@ +/* + * 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. + */ + +jest.mock('./helpers'); + +import os from 'os'; +import { resolve as resolvePath } from 'path'; +import { getVoidLogger, UrlReader } from '@backstage/backend-common'; +import { ConfigReader } from '@backstage/config'; +import { ScmIntegrations } from '@backstage/integration'; +import { createFetchPlainFileAction } from './plainFile'; +import { PassThrough } from 'stream'; +import { fetchFile } from './helpers'; + +describe('fetch:plain:file', () => { + const integrations = ScmIntegrations.fromConfig( + new ConfigReader({ + integrations: { + github: [{ host: 'github.com', token: 'token' }], + }, + }), + ); + const reader: UrlReader = { + readUrl: jest.fn(), + readTree: jest.fn(), + search: jest.fn(), + }; + + beforeEach(() => { + jest.resetAllMocks(); + }); + + const action = createFetchPlainFileAction({ integrations, reader }); + const mockContext = { + workspacePath: os.tmpdir(), + logger: getVoidLogger(), + logStream: new PassThrough(), + output: jest.fn(), + createTemporaryDirectory: jest.fn(), + }; + + it('should disallow a target path outside working directory', async () => { + await expect( + action.handler({ + ...mockContext, + input: { + url: 'https://github.com/backstage/community/tree/main/backstage-community-sessions/assets/Backstage%20Community%20Sessions.png', + targetPath: '/foobar', + }, + }), + ).rejects.toThrow( + /Relative path is not allowed to refer to a directory outside its parent/, + ); + }); + + it('should fetch plain', async () => { + await action.handler({ + ...mockContext, + input: { + url: 'https://github.com/backstage/community/tree/main/backstage-community-sessions/assets/Backstage%20Community%20Sessions.png', + targetPath: 'lol', + }, + }); + expect(fetchFile).toHaveBeenCalledWith( + expect.objectContaining({ + outputPath: resolvePath(mockContext.workspacePath, 'lol'), + fetchUrl: + 'https://github.com/backstage/community/tree/main/backstage-community-sessions/assets/Backstage%20Community%20Sessions.png', + }), + ); + }); +}); diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/plainFile.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/plainFile.ts new file mode 100644 index 0000000000..7b33ad93b4 --- /dev/null +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/plainFile.ts @@ -0,0 +1,75 @@ +/* + * 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 { UrlReader, resolveSafeChildPath } from '@backstage/backend-common'; +import { ScmIntegrations } from '@backstage/integration'; +import { fetchFile } from './helpers'; +import { createTemplateAction } from '@backstage/plugin-scaffolder-node'; + +/** + * Downloads content and places it in the workspace, or optionally + * in a subdirectory specified by the 'targetPath' input option. + * @public + */ +export function createFetchPlainFileAction(options: { + reader: UrlReader; + integrations: ScmIntegrations; +}) { + const { reader, integrations } = options; + + return createTemplateAction<{ url: string; targetPath: string }>({ + id: 'fetch:plain:file', + description: 'Downloads single file and places it in the workspace.', + schema: { + input: { + type: 'object', + required: ['url', 'targetPath'], + properties: { + url: { + title: 'Fetch URL', + description: + 'Relative path or absolute URL pointing to the single file to fetch.', + type: 'string', + }, + targetPath: { + title: 'Target Path', + description: + 'Target path within the working directory to download the file as.', + type: 'string', + }, + }, + }, + }, + supportsDryRun: true, + async handler(ctx) { + ctx.logger.info('Fetching plain content from remote URL'); + + // Finally move the template result into the task workspace + const outputPath = resolveSafeChildPath( + ctx.workspacePath, + ctx.input.targetPath, + ); + + await fetchFile({ + reader, + integrations, + baseUrl: ctx.templateInfo?.baseUrl, + fetchUrl: ctx.input.url, + outputPath, + }); + }, + }); +} 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 bb27410402..06e056cda3 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts @@ -127,7 +127,7 @@ export const createPublishGitlabMergeRequestAction = (options: { title: 'Gitlab Project path', type: 'string', }, - mergeRequestURL: { + mergeRequestUrl: { title: 'MergeRequest(MR) URL', type: 'string', description: 'Link to the merge request in GitLab', diff --git a/plugins/scaffolder-backend/src/scaffolder/dryrun/createDryRunner.ts b/plugins/scaffolder-backend/src/scaffolder/dryrun/createDryRunner.ts index 1929e3b8ac..d9302f4d74 100644 --- a/plugins/scaffolder-backend/src/scaffolder/dryrun/createDryRunner.ts +++ b/plugins/scaffolder-backend/src/scaffolder/dryrun/createDryRunner.ts @@ -25,7 +25,7 @@ import { SerializedFile, serializeDirectoryContents, } from '../../lib/files'; -import { TemplateFilter, TemplateGlobal } from '../../lib/templating'; +import { TemplateFilter, TemplateGlobal } from '../../lib'; import { TemplateActionRegistry } from '../actions'; import { NunjucksWorkflowRunner } from '../tasks/NunjucksWorkflowRunner'; import { DecoratedActionsRegistry } from './DecoratedActionsRegistry'; @@ -94,6 +94,8 @@ export function createDryRunner(options: TemplateTesterCreateOptions) { try { await deserializeDirectoryContents(contentsPath, input.directoryContents); + const abortSignal = new AbortController().signal; + const result = await workflowRunner.execute({ spec: { ...input.spec, @@ -117,6 +119,7 @@ export function createDryRunner(options: TemplateTesterCreateOptions) { done: false, isDryRun: true, getWorkspaceName: async () => `dry-run-${dryRunId}`, + cancelSignal: abortSignal, async emitLog(message: string, logMetadata?: JsonObject) { if (logMetadata?.stepId === dryRunId) { return; @@ -128,7 +131,7 @@ export function createDryRunner(options: TemplateTesterCreateOptions) { }, }); }, - async complete() { + complete: async () => { throw new Error('Not implemented'); }, }); diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.test.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.test.ts new file mode 100644 index 0000000000..4c0eb94c82 --- /dev/null +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.test.ts @@ -0,0 +1,191 @@ +/* + * 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 { DatabaseManager } from '@backstage/backend-common'; +import { ConfigReader } from '@backstage/config'; +import { DatabaseTaskStore } from './DatabaseTaskStore'; +import { TaskSpec } from '@backstage/plugin-scaffolder-common'; +import { ConflictError } from '@backstage/errors'; + +const createStore = async () => { + const manager = DatabaseManager.fromConfig( + new ConfigReader({ + backend: { + database: { + client: 'better-sqlite3', + connection: ':memory:', + }, + }, + }), + ).forPlugin('scaffolder'); + const store = await DatabaseTaskStore.create({ + database: manager, + }); + return { store, manager }; +}; + +describe('DatabaseTaskStore', () => { + it('should create the database store and run migration', async () => { + const { store, manager } = await createStore(); + expect(store).toBeDefined(); + + const client = await manager.getClient(); + expect(client.schema.hasTable('tasks')).toBeTruthy(); + expect(client.schema.hasTable('task_events')).toBeTruthy(); + }); + + it('should list all created tasks', async () => { + const { store } = await createStore(); + await store.createTask({ + spec: {} as TaskSpec, + createdBy: 'me', + }); + + const { tasks } = await store.list({}); + expect(tasks.length).toBe(1); + expect(tasks[0].createdBy).toBe('me'); + expect(tasks[0].status).toBe('open'); + expect(tasks[0].id).toBeDefined(); + }); + + it('should list filtered created tasks by createdBy', async () => { + const { store } = await createStore(); + + await store.createTask({ + spec: {} as TaskSpec, + createdBy: 'me', + }); + + await store.createTask({ + spec: {} as TaskSpec, + createdBy: 'him', + }); + + const { tasks } = await store.list({ createdBy: 'him' }); + expect(tasks.length).toBe(1); + expect(tasks[0].createdBy).toBe('him'); + expect(tasks[0].status).toBe('open'); + expect(tasks[0].id).toBeDefined(); + }); + + it('should sent an event to start cancelling the task', async () => { + const { store } = await createStore(); + + const { taskId } = await store.createTask({ + spec: {} as TaskSpec, + createdBy: 'me', + }); + const task = await store.getTask(taskId); + expect(task.status).toBe('open'); + + await store.cancelTask({ + taskId, + body: { + message: `Step 2 has been cancelled.`, + stepId: 2, + status: 'cancelled', + }, + }); + + const { events } = await store.listEvents({ taskId }); + const event = events[0]; + expect(event.taskId).toBe(taskId); + expect(event.body.status).toBe('cancelled'); + }); + + it('should emit a log event', async () => { + const { store } = await createStore(); + const { taskId } = await store.createTask({ + spec: {} as TaskSpec, + createdBy: 'me', + }); + await store.emitLogEvent({ + taskId, + body: { + message: 'Step #2 failed', + stepId: 2, + status: 'failed', + }, + }); + const { events } = await store.listEvents({ taskId }); + const event = events[0]; + expect(event.taskId).toBe(taskId); + expect(event.body.status).toBe('failed'); + expect(event.type).toBe('log'); + }); + + it('should complete the task', async () => { + const { store } = await createStore(); + const { taskId } = await store.createTask({ + spec: {} as TaskSpec, + createdBy: 'me', + }); + const task = await store.getTask(taskId); + expect(task.status).toBe('open'); + + const message = `This task was marked as stale as it exceeded its timeout`; + await store.completeTask({ + taskId, + status: 'cancelled', + eventBody: { message }, + }); + + const taskAfterCompletion = await store.getTask(taskId); + expect(taskAfterCompletion.status).toBe('cancelled'); + }); + + it('should claim a new task', async () => { + const { store } = await createStore(); + const { taskId } = await store.createTask({ + spec: {} as TaskSpec, + createdBy: 'me', + }); + const task = await store.getTask(taskId); + expect(task.status).toBe('open'); + await store.claimTask(); + + const claimedTask = await store.getTask(taskId); + expect(claimedTask.status).toBe('processing'); + }); + + it('should shutdown the running task', async () => { + const { store } = await createStore(); + const { taskId } = await store.createTask({ + spec: {} as TaskSpec, + createdBy: 'me', + }); + const task = await store.getTask(taskId); + expect(task.status).toBe('open'); + await store.claimTask(); + await store.shutdownTask({ taskId }); + + const claimedTask = await store.getTask(taskId); + expect(claimedTask.status).toBe('failed'); + }); + + it('should be not possible to shutdown not running task', async () => { + const { store } = await createStore(); + const { taskId } = await store.createTask({ + spec: {} as TaskSpec, + createdBy: 'me', + }); + const task = await store.getTask(taskId); + expect(task.status).toBe('open'); + await expect(async () => { + await store.shutdownTask({ taskId }); + }).rejects.toThrow(ConflictError); + }); +}); diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.ts index 879b457544..f3cb9b645e 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.ts @@ -220,7 +220,7 @@ export class DatabaseTaskStore implements TaskStore { .update({ status: 'processing', last_heartbeat_at: this.db.fn.now(), - // remove the secrets when moving moving to processing state. + // remove the secrets when moving to processing state. secrets: null, }); @@ -287,13 +287,14 @@ export class DatabaseTaskStore implements TaskStore { const { taskId, status, eventBody } = options; let oldStatus: string; - if (status === 'failed' || status === 'completed') { + if (['failed', 'completed', 'cancelled'].includes(status)) { oldStatus = 'processing'; } else { throw new Error( `Invalid status update of run '${taskId}' to status '${status}'`, ); } + await this.db.transaction(async tx => { const [task] = await tx('tasks') .where({ @@ -302,6 +303,40 @@ export class DatabaseTaskStore implements TaskStore { .limit(1) .select(); + const updateTask = async (criteria: { + id: string; + status?: TaskStatus; + }) => { + const updateCount = await tx('tasks') + .where(criteria) + .update({ + status, + }); + + if (updateCount !== 1) { + throw new ConflictError( + `Failed to update status to '${status}' for taskId ${taskId}`, + ); + } + + await tx('task_events').insert({ + task_id: taskId, + event_type: 'completion', + body: JSON.stringify(eventBody), + }); + }; + + if (status === 'cancelled') { + await updateTask({ + id: taskId, + }); + return; + } + + if (task.status === 'cancelled') { + return; + } + if (!task) { throw new Error(`No task with taskId ${taskId} found`); } @@ -311,25 +346,10 @@ export class DatabaseTaskStore implements TaskStore { `as it is currently '${task.status}', expected '${oldStatus}'`, ); } - const updateCount = await tx('tasks') - .where({ - id: taskId, - status: oldStatus, - }) - .update({ - status, - }); - if (updateCount !== 1) { - throw new ConflictError( - `Failed to update status to '${status}' for taskId ${taskId}`, - ); - } - - await tx('task_events').insert({ - task_id: taskId, - event_type: 'completion', - body: JSON.stringify(eventBody), + await updateTask({ + id: taskId, + status: oldStatus, }); }); } @@ -419,4 +439,16 @@ export class DatabaseTaskStore implements TaskStore { }, }); } + + async cancelTask( + options: TaskStoreEmitOptions<{ message: string } & JsonObject>, + ): Promise { + const { taskId, body } = options; + const serializedBody = JSON.stringify(body); + await this.db('task_events').insert({ + task_id: taskId, + event_type: 'cancelled', + body: serializedBody, + }); + } } diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.test.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.test.ts index 0d2246ed36..3b6ec54249 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.test.ts @@ -70,6 +70,7 @@ describe('DefaultWorkflowRunner', () => { complete: async () => {}, done: false, emitLog: async () => {}, + cancelSignal: new AbortController().signal, getWorkspaceName: () => Promise.resolve('test-workspace'), }); @@ -166,7 +167,7 @@ describe('DefaultWorkflowRunner', () => { }); await expect(runner.execute(task)).rejects.toThrow( - /Invalid input passed to action jest-validated-action, instance requires property \"foo\"/, + /Invalid input passed to action jest-validated-action, instance requires property "foo"/, ); }); diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts index 88abe05cad..629c730d48 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts @@ -15,7 +15,12 @@ */ import { ScmIntegrations } from '@backstage/integration'; -import { TaskContext, WorkflowResponse, WorkflowRunner } from './types'; +import { + TaskContext, + TaskTrackType, + WorkflowResponse, + WorkflowRunner, +} from './types'; import * as winston from 'winston'; import fs from 'fs-extra'; import path from 'path'; @@ -99,6 +104,7 @@ const createStepLogger = ({ export class NunjucksWorkflowRunner implements WorkflowRunner { constructor(private readonly options: NunjucksWorkflowRunnerOptions) {} + private readonly tracker = scaffoldingTracker(); private isSingleTemplateString(input: string) { @@ -180,6 +186,138 @@ export class NunjucksWorkflowRunner implements WorkflowRunner { }); } + async executeStep( + task: TaskContext, + step: TaskStep, + context: TemplateContext, + renderTemplate: (template: string, values: unknown) => string, + taskTrack: TaskTrackType, + workspacePath: string, + ) { + const stepTrack = await this.tracker.stepStart(task, step); + + if (task.cancelSignal.aborted) { + throw new Error(`Step ${step.name} has been cancelled.`); + } + + try { + if (step.if) { + const ifResult = await this.render(step.if, context, renderTemplate); + if (!isTruthy(ifResult)) { + await stepTrack.skipFalsy(); + return; + } + } + + const action: TemplateAction = + this.options.actionRegistry.get(step.action); + const { taskLogger, streamLogger } = createStepLogger({ task, step }); + + if (task.isDryRun) { + const redactedSecrets = Object.fromEntries( + Object.entries(task.secrets ?? {}).map(secret => [ + secret[0], + '[REDACTED]', + ]), + ); + const debugInput = + (step.input && + this.render( + step.input, + { + ...context, + secrets: redactedSecrets, + }, + renderTemplate, + )) ?? + {}; + taskLogger.info( + `Running ${ + action.id + } in dry-run mode with inputs (secrets redacted): ${JSON.stringify( + debugInput, + undefined, + 2, + )}`, + ); + if (!action.supportsDryRun) { + await taskTrack.skipDryRun(step, action); + const outputSchema = action.schema?.output; + if (outputSchema) { + context.steps[step.id] = { + output: generateExampleOutput(outputSchema) as { + [name in string]: JsonValue; + }, + }; + } else { + context.steps[step.id] = { output: {} }; + } + return; + } + } + + // Secrets are only passed when templating the input to actions for security reasons + const input = + (step.input && + this.render( + step.input, + { ...context, secrets: task.secrets ?? {} }, + renderTemplate, + )) ?? + {}; + + if (action.schema?.input) { + const validateResult = validateJsonSchema(input, action.schema.input); + if (!validateResult.valid) { + const errors = validateResult.errors.join(', '); + throw new InputError( + `Invalid input passed to action ${action.id}, ${errors}`, + ); + } + } + + const tmpDirs = new Array(); + const stepOutput: { [outputName: string]: JsonValue } = {}; + + await action.handler({ + input, + secrets: task.secrets ?? {}, + logger: taskLogger, + logStream: streamLogger, + workspacePath, + createTemporaryDirectory: async () => { + const tmpDir = await fs.mkdtemp(`${workspacePath}_step-${step.id}-`); + tmpDirs.push(tmpDir); + return tmpDir; + }, + output(name: string, value: JsonValue) { + stepOutput[name] = value; + }, + templateInfo: task.spec.templateInfo, + user: task.spec.user, + isDryRun: task.isDryRun, + signal: task.cancelSignal, + }); + + // Remove all temporary directories that were created when executing the action + for (const tmpDir of tmpDirs) { + await fs.remove(tmpDir); + } + + context.steps[step.id] = { output: stepOutput }; + + if (task.cancelSignal.aborted) { + throw new Error(`Step ${step.name} has been cancelled.`); + } + + await stepTrack.markSuccessful(); + } catch (err) { + await taskTrack.markFailed(step, err); + await stepTrack.markFailed(); + throw err; + } + } + async execute(task: TaskContext): Promise { if (!isValidTaskSpec(task.spec)) { throw new InputError( @@ -191,7 +329,12 @@ export class NunjucksWorkflowRunner implements WorkflowRunner { await task.getWorkspaceName(), ); - const { integrations } = this.options; + const { + additionalTemplateFilters, + additionalTemplateGlobals, + integrations, + } = this.options; + const renderTemplate = await SecureTemplater.loadRenderer({ // TODO(blam): let's work out how we can deprecate this. // We shouldn't really need to be exposing these now we can deal with @@ -200,8 +343,8 @@ export class NunjucksWorkflowRunner implements WorkflowRunner { parseRepoUrl(url: string) { return parseRepoUrl(url, integrations); }, - additionalTemplateFilters: this.options.additionalTemplateFilters, - additionalTemplateGlobals: this.options.additionalTemplateGlobals, + additionalTemplateFilters, + additionalTemplateGlobals, }); try { @@ -215,126 +358,14 @@ export class NunjucksWorkflowRunner implements WorkflowRunner { }; for (const step of task.spec.steps) { - const stepTrack = await this.tracker.stepStart(task, step); - try { - if (step.if) { - const ifResult = await this.render( - step.if, - context, - renderTemplate, - ); - if (!isTruthy(ifResult)) { - await stepTrack.skipFalsy(); - continue; - } - } - - const action = this.options.actionRegistry.get(step.action); - const { taskLogger, streamLogger } = createStepLogger({ task, step }); - - if (task.isDryRun) { - const redactedSecrets = Object.fromEntries( - Object.entries(task.secrets ?? {}).map(secret => [ - secret[0], - '[REDACTED]', - ]), - ); - const debugInput = - (step.input && - this.render( - step.input, - { - ...context, - secrets: redactedSecrets, - }, - renderTemplate, - )) ?? - {}; - taskLogger.info( - `Running ${ - action.id - } in dry-run mode with inputs (secrets redacted): ${JSON.stringify( - debugInput, - undefined, - 2, - )}`, - ); - if (!action.supportsDryRun) { - await taskTrack.skipDryRun(step, action); - const outputSchema = action.schema?.output; - if (outputSchema) { - context.steps[step.id] = { - output: generateExampleOutput(outputSchema) as { - [name in string]: JsonValue; - }, - }; - } else { - context.steps[step.id] = { output: {} }; - } - continue; - } - } - - // Secrets are only passed when templating the input to actions for security reasons - const input = - (step.input && - this.render( - step.input, - { ...context, secrets: task.secrets ?? {} }, - renderTemplate, - )) ?? - {}; - - if (action.schema?.input) { - const validateResult = validateJsonSchema( - input, - action.schema.input, - ); - if (!validateResult.valid) { - const errors = validateResult.errors.join(', '); - throw new InputError( - `Invalid input passed to action ${action.id}, ${errors}`, - ); - } - } - - const tmpDirs = new Array(); - const stepOutput: { [outputName: string]: JsonValue } = {}; - - await action.handler({ - input, - secrets: task.secrets ?? {}, - logger: taskLogger, - logStream: streamLogger, - workspacePath, - createTemporaryDirectory: async () => { - const tmpDir = await fs.mkdtemp( - `${workspacePath}_step-${step.id}-`, - ); - tmpDirs.push(tmpDir); - return tmpDir; - }, - output(name: string, value: JsonValue) { - stepOutput[name] = value; - }, - templateInfo: task.spec.templateInfo, - user: task.spec.user, - isDryRun: task.isDryRun, - }); - - // Remove all temporary directories that were created when executing the action - for (const tmpDir of tmpDirs) { - await fs.remove(tmpDir); - } - - context.steps[step.id] = { output: stepOutput }; - - await stepTrack.markSuccessful(); - } catch (err) { - await taskTrack.markFailed(step, err); - await stepTrack.markFailed(); - throw err; - } + await this.executeStep( + task, + step, + context, + renderTemplate, + taskTrack, + workspacePath, + ); } const output = this.render(task.spec.output, context, renderTemplate); @@ -380,7 +411,10 @@ function scaffoldingTracker() { template, }); - async function skipDryRun(step: TaskStep, action: TemplateAction) { + async function skipDryRun( + step: TaskStep, + action: TemplateAction, + ) { task.emitLog(`Skipping because ${action.id} does not support dry-run`, { stepId: step.id, status: 'skipped', @@ -409,8 +443,22 @@ function scaffoldingTracker() { taskTimer({ result: 'failed' }); } + async function markCancelled(step: TaskStep) { + await task.emitLog(`Step ${step.id} has been cancelled.`, { + stepId: step.id, + status: 'cancelled', + }); + taskCount.inc({ + template, + user, + result: 'cancelled', + }); + taskTimer({ result: 'cancelled' }); + } + return { skipDryRun, + markCancelled, markSuccessful, markFailed, }; @@ -441,6 +489,15 @@ function scaffoldingTracker() { stepTimer({ result: 'ok' }); } + async function markCancelled() { + stepCount.inc({ + template, + step: step.name, + result: 'cancelled', + }); + stepTimer({ result: 'cancelled' }); + } + async function markFailed() { stepCount.inc({ template, @@ -459,8 +516,9 @@ function scaffoldingTracker() { } return { - markSuccessful, + markCancelled, markFailed, + markSuccessful, skipFalsy, }; } diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.ts index d01351d8ae..fc5a724e47 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.ts @@ -39,8 +39,13 @@ export class TaskManager implements TaskContext { private heartbeatTimeoutId?: ReturnType; - static create(task: CurrentClaimedTask, storage: TaskStore, logger: Logger) { - const agent = new TaskManager(task, storage, logger); + static create( + task: CurrentClaimedTask, + storage: TaskStore, + abortSignal: AbortSignal, + logger: Logger, + ) { + const agent = new TaskManager(task, storage, abortSignal, logger); agent.startTimeout(); return agent; } @@ -49,6 +54,7 @@ export class TaskManager implements TaskContext { private constructor( private readonly task: CurrentClaimedTask, private readonly storage: TaskStore, + private readonly signal: AbortSignal, private readonly logger: Logger, ) {} @@ -56,6 +62,10 @@ export class TaskManager implements TaskContext { return this.task.spec; } + get cancelSignal() { + return this.signal; + } + get secrets() { return this.task.secrets; } @@ -165,6 +175,33 @@ export class StorageTaskBroker implements TaskBroker { private deferredDispatch = defer(); + private async registerCancellable( + taskId: string, + abortController: AbortController, + ) { + let shouldUnsubscribe = false; + const subscription = this.event$({ taskId, after: undefined }).subscribe({ + error: _ => { + subscription.unsubscribe(); + }, + next: ({ events }) => { + for (const event of events) { + if (event.type === 'cancelled') { + abortController.abort(); + shouldUnsubscribe = true; + } + + if (event.type === 'completion') { + shouldUnsubscribe = true; + } + } + if (shouldUnsubscribe) { + subscription.unsubscribe(); + } + }, + }); + } + /** * {@inheritdoc TaskBroker.claim} */ @@ -172,6 +209,8 @@ export class StorageTaskBroker implements TaskBroker { for (;;) { const pendingTask = await this.storage.claimTask(); if (pendingTask) { + const abortController = new AbortController(); + await this.registerCancellable(pendingTask.id, abortController); return TaskManager.create( { taskId: pendingTask.id, @@ -180,6 +219,7 @@ export class StorageTaskBroker implements TaskBroker { createdBy: pendingTask.createdBy, }, this.storage, + abortController.signal, this.logger, ); } @@ -271,4 +311,24 @@ export class StorageTaskBroker implements TaskBroker { this.deferredDispatch.resolve(); this.deferredDispatch = defer(); } + + async cancel(taskId: string) { + const { events } = await this.storage.listEvents({ taskId }); + const currentStepId = + events.length > 0 + ? events + .filter(({ body }) => body?.stepId) + .reduce((prev, curr) => (prev.id > curr.id ? prev : curr)).body + .stepId + : 0; + + await this.storage.cancelTask?.({ + taskId, + body: { + message: `Step ${currentStepId} has been cancelled.`, + stepId: currentStepId, + status: 'cancelled', + }, + }); + } } diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/TaskWorker.test.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/TaskWorker.test.ts index d39671cb67..e886b31369 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/TaskWorker.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/TaskWorker.test.ts @@ -15,7 +15,7 @@ */ import os from 'os'; -import { getVoidLogger, DatabaseManager } from '@backstage/backend-common'; +import { DatabaseManager, getVoidLogger } from '@backstage/backend-common'; import { ConfigReader } from '@backstage/config'; import { DatabaseTaskStore } from './DatabaseTaskStore'; import { StorageTaskBroker } from './StorageTaskBroker'; @@ -23,7 +23,14 @@ import { TaskWorker, TaskWorkerOptions } from './TaskWorker'; import { ScmIntegrations } from '@backstage/integration'; import { TemplateActionRegistry } from '../actions'; import { NunjucksWorkflowRunner } from './NunjucksWorkflowRunner'; -import { TaskBroker, TaskContext, WorkflowRunner } from './types'; +import { + SerializedTaskEvent, + TaskBroker, + TaskContext, + WorkflowRunner, +} from './types'; +import ObservableImpl from 'zen-observable'; +import waitForExpect from 'wait-for-expect'; jest.mock('./NunjucksWorkflowRunner'); const MockedNunjucksWorkflowRunner = @@ -198,6 +205,67 @@ describe('Concurrent TaskWorker', () => { }); }); +describe('Cancellable TaskWorker', () => { + let storage: DatabaseTaskStore; + const integrations: ScmIntegrations = {} as ScmIntegrations; + const actionRegistry: TemplateActionRegistry = {} as TemplateActionRegistry; + const workingDirectory = os.tmpdir(); + + let myTask: TaskContext | undefined = undefined; + + const workflowRunner: NunjucksWorkflowRunner = { + execute: (task: TaskContext) => { + myTask = task; + }, + } as unknown as NunjucksWorkflowRunner; + + beforeAll(async () => { + storage = await createStore(); + }); + + beforeEach(() => { + jest.resetAllMocks(); + MockedNunjucksWorkflowRunner.mockImplementation(() => workflowRunner); + }); + + const logger = getVoidLogger(); + + it('should be able to cancel the running task', async () => { + const taskBroker = new StorageTaskBroker(storage, logger); + const taskWorker = await TaskWorker.create({ + logger, + workingDirectory, + integrations, + taskBroker, + actionRegistry, + }); + + const steps = [...Array(10)].map(n => ({ + id: `test${n}`, + name: `test${n}`, + action: 'not-found-action', + })); + + const { taskId } = await taskBroker.dispatch({ + spec: { + apiVersion: 'scaffolder.backstage.io/v1beta3', + steps, + output: { + result: '{{ steps.test.output.testOutput }}', + }, + parameters: {}, + }, + }); + + await taskWorker.start(); + await taskBroker.cancel(taskId); + + await waitForExpect(() => { + expect(myTask?.cancelSignal.aborted).toBeTruthy(); + }); + }); +}); + describe('TaskWorker internals', () => { const TaskWorkerConstructor = TaskWorker as unknown as { new (options: TaskWorkerOptions): TaskWorker; @@ -219,10 +287,24 @@ describe('TaskWorker internals', () => { }, }; + const subscribers = new Set< + ZenObservable.SubscriptionObserver<{ events: SerializedTaskEvent[] }> + >(); + let claimedTaskCount = 0; const taskWorker = new TaskWorkerConstructor({ runners: { workflowRunner }, taskBroker: { + event$() { + return new ObservableImpl<{ events: SerializedTaskEvent[] }>( + subscriber => { + subscribers.add(subscriber); + return () => { + subscribers.delete(subscriber); + }; + }, + ); + }, async claim() { claimedTaskCount++; return { @@ -233,7 +315,7 @@ describe('TaskWorker internals', () => { async complete(_result, _metadata) {}, } as TaskContext; }, - } as TaskBroker, + } as unknown as TaskBroker, concurrentTasksLimit: 2, }); diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/TaskWorker.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/TaskWorker.ts index 82829665a3..5723e7136f 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/TaskWorker.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/TaskWorker.ts @@ -21,10 +21,7 @@ import { Logger } from 'winston'; import { TemplateActionRegistry } from '../actions'; import { ScmIntegrations } from '@backstage/integration'; import { assertError } from '@backstage/errors'; -import { - TemplateFilter, - TemplateGlobal, -} from '../../lib/templating/SecureTemplater'; +import { TemplateFilter, TemplateGlobal } from '../../lib'; /** * TaskWorkerOptions diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/types.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/types.ts index 5a91802f3e..112276b9dd 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/types.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/types.ts @@ -15,8 +15,9 @@ */ import { JsonValue, JsonObject, Observable } from '@backstage/types'; -import { TaskSpec } from '@backstage/plugin-scaffolder-common'; +import { TaskSpec, TaskStep } from '@backstage/plugin-scaffolder-common'; import { TaskSecrets } from '@backstage/plugin-scaffolder-node'; +import { TemplateAction } from '@backstage/plugin-scaffolder-node'; /** * The status of each step of the Task @@ -24,11 +25,11 @@ import { TaskSecrets } from '@backstage/plugin-scaffolder-node'; * @public */ export type TaskStatus = - | 'open' - | 'processing' - | 'failed' | 'cancelled' - | 'completed'; + | 'completed' + | 'failed' + | 'open' + | 'processing'; /** * The state of a completed task. @@ -57,7 +58,7 @@ export type SerializedTask = { * * @public */ -export type TaskEventType = 'completion' | 'log'; +export type TaskEventType = 'completion' | 'log' | 'cancelled'; /** * SerializedTaskEvent @@ -99,13 +100,17 @@ export type TaskBrokerDispatchOptions = { * @public */ export interface TaskContext { + cancelSignal: AbortSignal; spec: TaskSpec; secrets?: TaskSecrets; createdBy?: string; done: boolean; isDryRun?: boolean; - emitLog(message: string, logMetadata?: JsonObject): Promise; + complete(result: TaskCompletionState, metadata?: JsonObject): Promise; + + emitLog(message: string, logMetadata?: JsonObject): Promise; + getWorkspaceName(): Promise; } @@ -115,16 +120,23 @@ export interface TaskContext { * @public */ export interface TaskBroker { + cancel?(taskId: string): Promise; + claim(): Promise; + dispatch( options: TaskBrokerDispatchOptions, ): Promise; + vacuumTasks(options: { timeoutS: number }): Promise; + event$(options: { taskId: string; after: number | undefined; }): Observable<{ events: SerializedTaskEvent[] }>; + get(taskId: string): Promise; + list?(options?: { createdBy?: string }): Promise<{ tasks: SerializedTask[] }>; } @@ -181,30 +193,51 @@ export type TaskStoreCreateTaskResult = { * @public */ export interface TaskStore { + cancelTask?(options: TaskStoreEmitOptions): Promise; + createTask( options: TaskStoreCreateTaskOptions, ): Promise; + getTask(taskId: string): Promise; + claimTask(): Promise; + completeTask(options: { taskId: string; status: TaskStatus; eventBody: JsonObject; }): Promise; + heartbeatTask(taskId: string): Promise; + listStaleTasks(options: { timeoutS: number }): Promise<{ tasks: { taskId: string }[]; }>; + list?(options: { createdBy?: string }): Promise<{ tasks: SerializedTask[] }>; emitLogEvent(options: TaskStoreEmitOptions): Promise; + listEvents( options: TaskStoreListEventsOptions, ): Promise<{ events: SerializedTaskEvent[] }>; + shutdownTask?(options: TaskStoreShutDownTaskOptions): Promise; } export type WorkflowResponse = { output: { [key: string]: JsonValue } }; + export interface WorkflowRunner { execute(task: TaskContext): Promise; } + +export type TaskTrackType = { + markCancelled: (step: TaskStep) => Promise; + markFailed: (step: TaskStep, err: Error) => Promise; + markSuccessful: () => Promise; + skipDryRun: ( + step: TaskStep, + action: TemplateAction, + ) => Promise; +}; diff --git a/plugins/scaffolder-backend/src/service/conditionExports.ts b/plugins/scaffolder-backend/src/service/conditionExports.ts new file mode 100644 index 0000000000..0c502c6075 --- /dev/null +++ b/plugins/scaffolder-backend/src/service/conditionExports.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 { RESOURCE_TYPE_SCAFFOLDER_TEMPLATE } from '@backstage/plugin-scaffolder-common/alpha'; +import { createConditionExports } from '@backstage/plugin-permission-node'; +import { scaffolderTemplateRules } from './rules'; + +const { conditions, createConditionalDecision } = createConditionExports({ + pluginId: 'scaffolder', + resourceType: RESOURCE_TYPE_SCAFFOLDER_TEMPLATE, + rules: scaffolderTemplateRules, +}); + +/** + * These conditions are used when creating conditional decisions for scaffolder + * templates that are returned by authorization policies. + * + * @alpha + */ +export const scaffolderConditions = conditions; + +/** + * `createScaffolderConditionalDecision` can be used when authoring policies to + * create conditional decisions. It requires a permission of type + * `ResourcePermission<'scaffolder-template'>` to be passed as the first parameter. + * It's recommended that you use the provided `isResourcePermission` and + * `isPermission` helper methods to narrow the type of the permission passed to + * the handle method as shown below. + * + * ``` + * // MyAuthorizationPolicy.ts + * ... + * import { createScaffolderPolicyDecision } from '@backstage/plugin-scaffolder-backend'; + * import { RESOURCE_TYPE_SCAFFOLDER_TEMPLATE } from '@backstage/plugin-scaffolder-common'; + * + * class MyAuthorizationPolicy implements PermissionPolicy { + * async handle(request, user) { + * ... + * + * if (isResourcePermission(request.permission, RESOURCE_TYPE_SCAFFOLDER_TEMPLATE)) { + * return createScaffolderConditionalDecision( + * request.permission, + * { anyOf: [...insert conditions here...] } + * ); + * } + * + * ... + * } + * + * ``` + * + * @alpha + */ +export const createScaffolderConditionalDecision = createConditionalDecision; diff --git a/plugins/scaffolder-backend/src/service/helpers.ts b/plugins/scaffolder-backend/src/service/helpers.ts index 3412fec2d3..97d4ab93aa 100644 --- a/plugins/scaffolder-backend/src/service/helpers.ts +++ b/plugins/scaffolder-backend/src/service/helpers.ts @@ -107,3 +107,7 @@ export async function findTemplate(options: { return template as TemplateEntityV1beta3; } + +export type TemplateTransform = ( + template: TemplateEntityV1beta3, +) => TemplateEntityV1beta3; diff --git a/plugins/scaffolder-backend/src/service/index.ts b/plugins/scaffolder-backend/src/service/index.ts new file mode 100644 index 0000000000..dc5508d47f --- /dev/null +++ b/plugins/scaffolder-backend/src/service/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './conditionExports'; diff --git a/plugins/scaffolder-backend/src/service/router.test.ts b/plugins/scaffolder-backend/src/service/router.test.ts index 5e3c1c7278..4f5ed0fe22 100644 --- a/plugins/scaffolder-backend/src/service/router.test.ts +++ b/plugins/scaffolder-backend/src/service/router.test.ts @@ -44,6 +44,10 @@ import { IdentityApiGetIdentityRequest, BackstageIdentityResponse, } from '@backstage/plugin-auth-node'; +import { + AuthorizeResult, + PermissionEvaluator, +} from '@backstage/plugin-permission-common'; const mockAccess = jest.fn(); @@ -85,8 +89,12 @@ describe('createRouter', () => { let loggerSpy: jest.SpyInstance; let taskBroker: TaskBroker; const catalogClient = { getEntityByRef: jest.fn() } as unknown as CatalogApi; + const permissionApi = { + authorize: jest.fn(), + authorizeConditional: jest.fn(), + } as unknown as PermissionEvaluator; - const mockTemplate: TemplateEntityV1beta3 = { + const getMockTemplate = (): TemplateEntityV1beta3 => ({ apiVersion: 'scaffolder.backstage.io/v1beta3', kind: 'Template', metadata: { @@ -101,19 +109,54 @@ describe('createRouter', () => { spec: { owner: 'web@example.com', type: 'website', - steps: [], - parameters: { - type: 'object', - required: ['required'], - properties: { - required: { - type: 'string', - description: 'Required parameter', + steps: [ + { + id: 'step-one', + name: 'First log', + action: 'debug:log', + input: { + message: 'hello', }, }, - }, + { + id: 'step-two', + name: 'Second log', + action: 'debug:log', + input: { + message: 'world', + }, + 'backstage:permissions': { + tags: ['steps-tag'], + }, + }, + ], + parameters: [ + { + type: 'object', + required: ['requiredParameter1'], + properties: { + requiredParameter1: { + type: 'string', + description: 'Required parameter 1', + }, + }, + }, + { + type: 'object', + required: ['requiredParameter2'], + 'backstage:permissions': { + tags: ['parameters-tag'], + }, + properties: { + requiredParameter2: { + type: 'string', + description: 'Required parameter 2', + }, + }, + }, + ], }, - }; + }); const mockUser: UserEntity = { apiVersion: 'backstage.io/v1alpha1', @@ -152,6 +195,7 @@ describe('createRouter', () => { catalogClient, reader: mockUrlReader, taskBroker, + permissionApi, }); app = express().use(router); @@ -160,15 +204,27 @@ describe('createRouter', () => { .mockImplementation(async ref => { const { kind } = parseEntityRef(ref); - if (kind === 'template') { - return mockTemplate; + if (kind.toLocaleLowerCase() === 'template') { + return getMockTemplate(); } - if (kind === 'user') { + if (kind.toLocaleLowerCase() === 'user') { return mockUser; } + throw new Error(`no mock found for kind: ${kind}`); }); + + jest + .spyOn(permissionApi, 'authorizeConditional') + .mockImplementation(async () => [ + { + result: AuthorizeResult.ALLOW, + }, + { + result: AuthorizeResult.ALLOW, + }, + ]); }); afterEach(() => { @@ -216,12 +272,13 @@ describe('createRouter', () => { name: 'create-react-app-template', }), values: { - required: 'required-value', + requiredParameter1: 'required-value-1', + requiredParameter2: 'required-value-2', }, }); - expect(response.body.id).toBe('a-random-id'); expect(response.status).toEqual(201); + expect(response.body.id).toBe('a-random-id'); }); it('should call the broker with a correct spec', async () => { @@ -229,6 +286,7 @@ describe('createRouter', () => { taskBroker.dispatch as jest.Mocked['dispatch']; const mockToken = 'blob.eyJzdWIiOiJ1c2VyOmRlZmF1bHQvZ3Vlc3QiLCJuYW1lIjoiSm9obiBEb2UifQ.blob'; + const mockTemplate = getMockTemplate(); await request(app) .post('/v2/tasks') @@ -239,7 +297,8 @@ describe('createRouter', () => { name: 'create-react-app-template', }), values: { - required: 'required-value', + requiredParameter1: 'required-value-1', + requiredParameter2: 'required-value-2', }, }); expect(broker).toHaveBeenCalledWith( @@ -258,7 +317,8 @@ describe('createRouter', () => { })), output: mockTemplate.spec.output ?? {}, parameters: { - required: 'required-value', + requiredParameter1: 'required-value-1', + requiredParameter2: 'required-value-2', }, user: { entity: mockUser, @@ -284,6 +344,7 @@ describe('createRouter', () => { const broker = taskBroker.dispatch as jest.Mocked['dispatch']; const mockToken = 'blob.eyJzdWIiOiIiLCJuYW1lIjoiSm9obiBEb2UifQ.blob'; + const mockTemplate = getMockTemplate(); await request(app) .post('/v2/tasks') @@ -294,7 +355,8 @@ describe('createRouter', () => { name: 'create-react-app-template', }), values: { - required: 'required-value', + requiredParameter1: 'required-value-1', + requiredParameter2: 'required-value-2', }, }); expect(broker).toHaveBeenCalledWith( @@ -313,7 +375,8 @@ describe('createRouter', () => { })), output: mockTemplate.spec.output ?? {}, parameters: { - required: 'required-value', + requiredParameter1: 'required-value-1', + requiredParameter2: 'required-value-2', }, user: { entity: undefined, @@ -347,7 +410,8 @@ describe('createRouter', () => { name: 'create-react-app-template', }), values: { - required: 'required-value', + requiredParameter1: 'required-value-1', + requiredParameter2: 'required-value-2', }, }); @@ -370,7 +434,8 @@ describe('createRouter', () => { name: 'create-react-app-template', }), values: { - required: 'required-value', + requiredParameter1: 'required-value-1', + requiredParameter2: 'required-value-2', }, }); @@ -393,7 +458,8 @@ describe('createRouter', () => { name: 'create-react-app-template', }), values: { - required: 'required-value', + requiredParameter1: 'required-value-1', + requiredParameter2: 'required-value-2', }, }); @@ -713,6 +779,7 @@ data: {"id":1,"taskId":"a-random-id","type":"completion","createdAt":"","body":{ }); }); }); + describe('providing an identity api', () => { beforeEach(async () => { const logger = getVoidLogger(); @@ -752,6 +819,7 @@ data: {"id":1,"taskId":"a-random-id","type":"completion","createdAt":"","body":{ reader: mockUrlReader, taskBroker, identity: { getIdentity }, + permissionApi, }); app = express().use(router); @@ -760,15 +828,26 @@ data: {"id":1,"taskId":"a-random-id","type":"completion","createdAt":"","body":{ .mockImplementation(async ref => { const { kind } = parseEntityRef(ref); - if (kind === 'template') { - return mockTemplate; + if (kind.toLocaleLowerCase() === 'template') { + return getMockTemplate(); } - if (kind === 'user') { + if (kind.toLocaleLowerCase() === 'user') { return mockUser; } throw new Error(`no mock found for kind: ${kind}`); }); + + jest + .spyOn(permissionApi, 'authorizeConditional') + .mockImplementation(async () => [ + { + result: AuthorizeResult.ALLOW, + }, + { + result: AuthorizeResult.ALLOW, + }, + ]); }); afterEach(() => { @@ -784,6 +863,125 @@ data: {"id":1,"taskId":"a-random-id","type":"completion","createdAt":"","body":{ }); }); + describe('GET /v2/templates/:namespace/:kind/:name/parameter-schema', () => { + it('returns the parameter schema', async () => { + const response = await request(app) + .get( + '/v2/templates/default/Template/create-react-app-template/parameter-schema', + ) + .send(); + + expect(response.status).toEqual(200); + expect(response.body).toEqual({ + title: 'Create React App Template', + description: 'Create a new CRA website project', + steps: [ + { + title: 'Please enter the following information', + schema: { + required: ['requiredParameter1'], + type: 'object', + properties: { + requiredParameter1: { + description: 'Required parameter 1', + type: 'string', + }, + }, + }, + }, + { + title: 'Please enter the following information', + schema: { + type: 'object', + required: ['requiredParameter2'], + 'backstage:permissions': { + tags: ['parameters-tag'], + }, + properties: { + requiredParameter2: { + type: 'string', + description: 'Required parameter 2', + }, + }, + }, + }, + ], + }); + }); + + it('filters parameters that the user is not authorized to see', async () => { + jest + .spyOn(permissionApi, 'authorizeConditional') + .mockImplementationOnce(async () => [ + { + result: AuthorizeResult.DENY, + }, + { + result: AuthorizeResult.ALLOW, + }, + ]); + const response = await request(app) + .get( + '/v2/templates/default/Template/create-react-app-template/parameter-schema', + ) + .send(); + expect(response.status).toEqual(200); + expect(response.body).toEqual({ + title: 'Create React App Template', + description: 'Create a new CRA website project', + steps: [], + }); + }); + + it('filters parameters that the user is not authorized to see in case of conditional decision', async () => { + jest + .spyOn(permissionApi, 'authorizeConditional') + .mockImplementationOnce(async () => [ + { + conditions: { + resourceType: 'scaffolder-template', + rule: 'HAS_TAG', + params: { tag: 'parameters-tag' }, + }, + pluginId: 'scaffolder', + resourceType: 'scaffolder-template', + result: AuthorizeResult.CONDITIONAL, + }, + { + result: AuthorizeResult.ALLOW, + }, + ]); + const response = await request(app) + .get( + '/v2/templates/default/Template/create-react-app-template/parameter-schema', + ) + .send(); + expect(response.status).toEqual(200); + expect(response.body).toEqual({ + title: 'Create React App Template', + description: 'Create a new CRA website project', + steps: [ + { + title: 'Please enter the following information', + schema: { + type: 'object', + required: ['requiredParameter2'], + 'backstage:permissions': { + tags: ['parameters-tag'], + }, + properties: { + requiredParameter2: { + type: 'string', + description: 'Required parameter 2', + }, + }, + }, + }, + ], + }); + }); + }); + describe('POST /v2/tasks', () => { it('rejects template values which do not match the template schema definition', async () => { const response = await request(app) @@ -801,6 +999,150 @@ data: {"id":1,"taskId":"a-random-id","type":"completion","createdAt":"","body":{ expect(response.status).toEqual(400); }); + it('filters steps that the user is not authorized to see', async () => { + jest + .spyOn(permissionApi, 'authorizeConditional') + .mockImplementation(async () => [ + { + result: AuthorizeResult.ALLOW, + }, + { + result: AuthorizeResult.DENY, + }, + ]); + + const broker = + taskBroker.dispatch as jest.Mocked['dispatch']; + const mockTemplate = getMockTemplate(); + + await request(app) + .post('/v2/tasks') + .send({ + templateRef: stringifyEntityRef({ + kind: 'template', + name: 'create-react-app-template', + }), + values: { + requiredParameter1: 'required-value-1', + requiredParameter2: 'required-value-2', + }, + }); + expect(broker).toHaveBeenCalledWith( + expect.objectContaining({ + createdBy: 'user:default/guest', + secrets: { + backstageToken: 'token', + }, + + spec: { + apiVersion: mockTemplate.apiVersion, + steps: [], + output: mockTemplate.spec.output ?? {}, + parameters: { + requiredParameter1: 'required-value-1', + requiredParameter2: 'required-value-2', + }, + user: { + entity: mockUser, + ref: 'user:default/guest', + }, + templateInfo: { + entityRef: stringifyEntityRef({ + kind: 'Template', + namespace: 'Default', + name: mockTemplate.metadata?.name, + }), + baseUrl: 'https://dev.azure.com', + entity: { + metadata: mockTemplate.metadata, + }, + }, + }, + }), + ); + }); + + it('filters steps that the user is not authorized to see in case of conditional decision', async () => { + jest + .spyOn(permissionApi, 'authorizeConditional') + .mockImplementation(async () => [ + { + result: AuthorizeResult.ALLOW, + }, + { + conditions: { + resourceType: 'scaffolder-template', + rule: 'HAS_TAG', + params: { tag: 'steps-tag' }, + }, + pluginId: 'scaffolder', + resourceType: 'scaffolder-template', + result: AuthorizeResult.CONDITIONAL, + }, + ]); + + const broker = + taskBroker.dispatch as jest.Mocked['dispatch']; + const mockTemplate = getMockTemplate(); + await request(app) + .post('/v2/tasks') + .send({ + templateRef: stringifyEntityRef({ + kind: 'template', + name: 'create-react-app-template', + }), + values: { + requiredParameter1: 'required-value-1', + requiredParameter2: 'required-value-2', + }, + }); + expect(broker).toHaveBeenCalledWith( + expect.objectContaining({ + createdBy: 'user:default/guest', + secrets: { + backstageToken: 'token', + }, + + spec: { + apiVersion: mockTemplate.apiVersion, + steps: [ + { + id: 'step-two', + name: 'Second log', + action: 'debug:log', + input: { + message: 'world', + }, + 'backstage:permissions': { + tags: ['steps-tag'], + }, + }, + ], + output: mockTemplate.spec.output ?? {}, + parameters: { + requiredParameter1: 'required-value-1', + requiredParameter2: 'required-value-2', + }, + user: { + entity: mockUser, + ref: 'user:default/guest', + }, + templateInfo: { + entityRef: stringifyEntityRef({ + kind: 'Template', + namespace: 'Default', + name: mockTemplate.metadata?.name, + }), + baseUrl: 'https://dev.azure.com', + entity: { + metadata: mockTemplate.metadata, + }, + }, + }, + }), + ); + }); + it('return the template id', async () => { const broker = taskBroker.dispatch as jest.Mocked['dispatch']; @@ -816,7 +1158,8 @@ data: {"id":1,"taskId":"a-random-id","type":"completion","createdAt":"","body":{ name: 'create-react-app-template', }), values: { - required: 'required-value', + requiredParameter1: 'required-value-1', + requiredParameter2: 'required-value-2', }, }); @@ -827,6 +1170,7 @@ data: {"id":1,"taskId":"a-random-id","type":"completion","createdAt":"","body":{ it('should call the broker with a correct spec', async () => { const broker = taskBroker.dispatch as jest.Mocked['dispatch']; + const mockTemplate = getMockTemplate(); await request(app) .post('/v2/tasks') @@ -836,7 +1180,8 @@ data: {"id":1,"taskId":"a-random-id","type":"completion","createdAt":"","body":{ name: 'create-react-app-template', }), values: { - required: 'required-value', + requiredParameter1: 'required-value-1', + requiredParameter2: 'required-value-2', }, }); expect(broker).toHaveBeenCalledWith( @@ -855,7 +1200,8 @@ data: {"id":1,"taskId":"a-random-id","type":"completion","createdAt":"","body":{ })), output: mockTemplate.spec.output ?? {}, parameters: { - required: 'required-value', + requiredParameter1: 'required-value-1', + requiredParameter2: 'required-value-2', }, user: { entity: mockUser, @@ -898,7 +1244,8 @@ data: {"id":1,"taskId":"a-random-id","type":"completion","createdAt":"","body":{ name: 'create-react-app-template', }), values: { - required: 'required-value', + requiredParameter1: 'required-value-1', + requiredParameter2: 'required-value-2', }, }); expect(response.status).not.toEqual(201); @@ -930,7 +1277,8 @@ data: {"id":1,"taskId":"a-random-id","type":"completion","createdAt":"","body":{ name: 'create-react-app-template', }), values: { - required: 'required-value', + requiredParameter1: 'required-value-1', + requiredParameter2: 'required-value-2', }, }); @@ -953,7 +1301,8 @@ data: {"id":1,"taskId":"a-random-id","type":"completion","createdAt":"","body":{ name: 'create-react-app-template', }), values: { - required: 'required-value', + requiredParameter1: 'required-value-1', + requiredParameter2: 'required-value-2', }, }); @@ -973,7 +1322,8 @@ data: {"id":1,"taskId":"a-random-id","type":"completion","createdAt":"","body":{ name: 'create-react-app-template', }), values: { - required: 'required-value', + requiredParameter1: 'required-value-1', + requiredParameter2: 'required-value-2', }, }); diff --git a/plugins/scaffolder-backend/src/service/router.ts b/plugins/scaffolder-backend/src/service/router.ts index dfccc4dc43..1f2d390f9f 100644 --- a/plugins/scaffolder-backend/src/service/router.ts +++ b/plugins/scaffolder-backend/src/service/router.ts @@ -18,6 +18,7 @@ import { PluginDatabaseManager, UrlReader } from '@backstage/backend-common'; import { PluginTaskScheduler } from '@backstage/backend-tasks'; import { CatalogApi } from '@backstage/catalog-client'; import { + CompoundEntityRef, Entity, parseEntityRef, stringifyEntityRef, @@ -31,7 +32,15 @@ import { TaskSpec, TemplateEntityV1beta3, templateEntityV1beta3Validator, + TemplateParametersV1beta3, + TemplateEntityStepV1beta3, } from '@backstage/plugin-scaffolder-common'; +import { + RESOURCE_TYPE_SCAFFOLDER_TEMPLATE, + scaffolderPermissions, + templateParameterReadPermission, + templateStepReadPermission, +} from '@backstage/plugin-scaffolder-common/alpha'; import express from 'express'; import Router from 'express-promise-router'; import { validate } from 'jsonschema'; @@ -53,6 +62,29 @@ import { IdentityApiGetIdentityRequest, } from '@backstage/plugin-auth-node'; import { TemplateAction } from '@backstage/plugin-scaffolder-node'; +import { + PermissionEvaluator, + PermissionRuleParams, +} from '@backstage/plugin-permission-common'; +import { + createConditionAuthorizer, + createPermissionIntegrationRouter, + PermissionRule, +} from '@backstage/plugin-permission-node'; +import { scaffolderTemplateRules } from './rules'; + +/** + * + * @public + */ +export type TemplatePermissionRuleInput< + TParams extends PermissionRuleParams = PermissionRuleParams, +> = PermissionRule< + TemplateEntityStepV1beta3 | TemplateParametersV1beta3, + {}, + typeof RESOURCE_TYPE_SCAFFOLDER_TEMPLATE, + TParams +>; /** * RouterOptions @@ -80,6 +112,8 @@ export interface RouterOptions { taskBroker?: TaskBroker; additionalTemplateFilters?: Record; additionalTemplateGlobals?: Record; + permissionApi?: PermissionEvaluator; + permissionRules?: TemplatePermissionRuleInput[]; identity?: IdentityApi; } @@ -174,6 +208,8 @@ export async function createRouter( scheduler, additionalTemplateFilters, additionalTemplateGlobals, + permissionApi, + permissionRules, } = options; const logger = parentLogger.child({ plugin: 'scaffolder' }); @@ -249,41 +285,46 @@ export async function createRouter( additionalTemplateGlobals, }); + const templateRules: TemplatePermissionRuleInput[] = Object.values( + scaffolderTemplateRules, + ); + + if (permissionRules) { + templateRules.push(...permissionRules); + } + + const isAuthorized = createConditionAuthorizer(Object.values(templateRules)); + + const permissionIntegrationRouter = createPermissionIntegrationRouter({ + resourceType: RESOURCE_TYPE_SCAFFOLDER_TEMPLATE, + permissions: scaffolderPermissions, + rules: templateRules, + }); + + router.use(permissionIntegrationRouter); + router .get( '/v2/templates/:namespace/:kind/:name/parameter-schema', async (req, res) => { - const { namespace, kind, name } = req.params; - const userIdentity = await identity.getIdentity({ request: req, }); const token = userIdentity?.token; - const template = await findTemplate({ - catalogApi: catalogClient, - entityRef: { kind, namespace, name }, - token, + const template = await authorizeTemplate(req.params, token); + + const parameters = [template.spec.parameters ?? []].flat(); + res.json({ + title: template.metadata.title ?? template.metadata.name, + description: template.metadata.description, + 'ui:options': template.metadata['ui:options'], + steps: parameters.map(schema => ({ + title: schema.title ?? 'Please enter the following information', + description: schema.description, + schema, + })), }); - if (isSupportedTemplate(template)) { - const parameters = [template.spec.parameters ?? []].flat(); - res.json({ - title: template.metadata.title ?? template.metadata.name, - description: template.metadata.description, - 'ui:options': template.metadata['ui:options'], - steps: parameters.map(schema => ({ - title: schema.title ?? 'Please enter the following information', - description: schema.description, - schema, - })), - }); - } else { - throw new InputError( - `Unsupported apiVersion field in schema entity, ${ - (template as Entity).apiVersion - }`, - ); - } }, ) .get('/v2/actions', async (_req, res) => { @@ -321,22 +362,14 @@ export async function createRouter( const values = req.body.values; - const template = await findTemplate({ - catalogApi: catalogClient, - entityRef: { kind, namespace, name }, + const template = await authorizeTemplate( + { kind, namespace, name }, token, - }); - - if (!isSupportedTemplate(template)) { - throw new InputError( - `Unsupported apiVersion field in schema entity, ${ - (template as Entity).apiVersion - }`, - ); - } + ); for (const parameters of [template.spec.parameters ?? []].flat()) { const result = validate(values, parameters); + if (!result.valid) { res.status(400).json({ errors: result.errors }); return; @@ -414,6 +447,11 @@ export async function createRouter( delete task.secrets; res.status(200).json(task); }) + .post('/v2/tasks/:taskId/cancel', async (req, res) => { + const { taskId } = req.params; + await taskBroker.cancel?.(taskId); + res.status(200).json({ status: 'cancelled' }); + }) .get('/v2/tasks/:taskId/eventstream', async (req, res) => { const { taskId } = req.params; const after = @@ -562,5 +600,56 @@ export async function createRouter( app.set('logger', logger); app.use('/', router); + async function authorizeTemplate( + entityRef: CompoundEntityRef, + token: string | undefined, + ) { + const template = await findTemplate({ + catalogApi: catalogClient, + entityRef, + token, + }); + + if (!isSupportedTemplate(template)) { + throw new InputError( + `Unsupported apiVersion field in schema entity, ${ + (template as Entity).apiVersion + }`, + ); + } + + if (!permissionApi) { + return template; + } + + const [parameterDecision, stepDecision] = + await permissionApi.authorizeConditional( + [ + { permission: templateParameterReadPermission }, + { permission: templateStepReadPermission }, + ], + { token }, + ); + + // Authorize parameters + if (Array.isArray(template.spec.parameters)) { + template.spec.parameters = template.spec.parameters.filter(step => + isAuthorized(parameterDecision, step), + ); + } else if ( + template.spec.parameters && + !isAuthorized(parameterDecision, template.spec.parameters) + ) { + template.spec.parameters = undefined; + } + + // Authorize steps + template.spec.steps = template.spec.steps.filter(step => + isAuthorized(stepDecision, step), + ); + + return template; + } + return app; } diff --git a/plugins/scaffolder-backend/src/service/rules.test.ts b/plugins/scaffolder-backend/src/service/rules.test.ts new file mode 100644 index 0000000000..7d8e0eb445 --- /dev/null +++ b/plugins/scaffolder-backend/src/service/rules.test.ts @@ -0,0 +1,81 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { hasTag } from './rules'; + +describe('hasTag', () => { + describe('apply', () => { + it('returns false when the tag is not present', () => { + expect( + hasTag.apply( + { + 'backstage:permissions': { + tags: ['foo', 'bar'], + }, + }, + { + tag: 'baz', + }, + ), + ).toEqual(false); + }); + + it('returns false when backstage:permissions is missing', () => { + expect( + hasTag.apply( + {}, + { + tag: 'baz', + }, + ), + ).toEqual(false); + }); + + it('returns false when tags is an empty array', () => { + expect( + hasTag.apply( + { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + 'backstage:permissions': { + tags: [], + }, + }, + }, + { + tag: 'baz', + }, + ), + ).toEqual(false); + }); + + it('returns true when the tag is present', () => { + expect( + hasTag.apply( + { + 'backstage:permissions': { + tags: ['foo', 'bar'], + }, + }, + { + tag: 'bar', + }, + ), + ).toEqual(true); + }); + }); +}); diff --git a/plugins/scaffolder-backend/src/service/rules.ts b/plugins/scaffolder-backend/src/service/rules.ts new file mode 100644 index 0000000000..d94f7dd4f4 --- /dev/null +++ b/plugins/scaffolder-backend/src/service/rules.ts @@ -0,0 +1,45 @@ +/* + * 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 { makeCreatePermissionRule } from '@backstage/plugin-permission-node'; +import { + TemplateEntityStepV1beta3, + TemplateParametersV1beta3, +} from '@backstage/plugin-scaffolder-common'; +import { RESOURCE_TYPE_SCAFFOLDER_TEMPLATE } from '@backstage/plugin-scaffolder-common/alpha'; + +import { z } from 'zod'; + +export const createScaffolderPermissionRule = makeCreatePermissionRule< + TemplateEntityStepV1beta3 | TemplateParametersV1beta3, + {}, + typeof RESOURCE_TYPE_SCAFFOLDER_TEMPLATE +>(); + +export const hasTag = createScaffolderPermissionRule({ + name: 'HAS_TAG', + resourceType: RESOURCE_TYPE_SCAFFOLDER_TEMPLATE, + description: `Match parameters or steps with the given tag`, + paramsSchema: z.object({ + tag: z.string().describe('Name of the tag to match on'), + }), + apply: (resource, { tag }) => { + return resource['backstage:permissions']?.tags?.includes(tag) ?? false; + }, + toQuery: () => ({}), +}); + +export const scaffolderTemplateRules = { hasTag }; diff --git a/plugins/scaffolder-common/CHANGELOG.md b/plugins/scaffolder-common/CHANGELOG.md index 4f76c33e36..83e32d4d30 100644 --- a/plugins/scaffolder-common/CHANGELOG.md +++ b/plugins/scaffolder-common/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-scaffolder-common +## 1.2.7-next.0 + +### Patch Changes + +- 48da4c46e45: Export `typeguard` for `isTemplateEntityV1beta3` +- Updated dependencies + - @backstage/catalog-model@1.2.1 + - @backstage/types@1.0.2 + ## 1.2.6 ### Patch Changes diff --git a/plugins/scaffolder-common/alpha-api-report.md b/plugins/scaffolder-common/alpha-api-report.md new file mode 100644 index 0000000000..e89999ad85 --- /dev/null +++ b/plugins/scaffolder-common/alpha-api-report.md @@ -0,0 +1,21 @@ +## API Report File for "@backstage/plugin-scaffolder-common" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { ResourcePermission } from '@backstage/plugin-permission-common'; + +// @alpha +export const RESOURCE_TYPE_SCAFFOLDER_TEMPLATE = 'scaffolder-template'; + +// @alpha +export const scaffolderPermissions: ResourcePermission<'scaffolder-template'>[]; + +// @alpha +export const templateParameterReadPermission: ResourcePermission<'scaffolder-template'>; + +// @alpha +export const templateStepReadPermission: ResourcePermission<'scaffolder-template'>; + +// (No @packageDocumentation comment for this package) +``` diff --git a/plugins/scaffolder-common/api-report.md b/plugins/scaffolder-common/api-report.md index 8864c0d76d..7c40780b57 100644 --- a/plugins/scaffolder-common/api-report.md +++ b/plugins/scaffolder-common/api-report.md @@ -10,6 +10,11 @@ import type { JsonValue } from '@backstage/types'; import { KindValidator } from '@backstage/catalog-model'; import type { UserEntity } from '@backstage/catalog-model'; +// @public +export const isTemplateEntityV1beta3: ( + entity: Entity, +) => entity is TemplateEntityV1beta3; + // @public export type TaskSpec = TaskSpecV1beta3; @@ -37,20 +42,30 @@ export interface TaskStep { name: string; } +// @public +export interface TemplateEntityStepV1beta3 extends JsonObject { + // (undocumented) + 'backstage:permissions'?: TemplatePermissionsV1beta3; + // (undocumented) + action: string; + // (undocumented) + id?: string; + // (undocumented) + if?: string | boolean; + // (undocumented) + input?: JsonObject; + // (undocumented) + name?: string; +} + // @public export interface TemplateEntityV1beta3 extends Entity { apiVersion: 'scaffolder.backstage.io/v1beta3'; kind: 'Template'; spec: { type: string; - parameters?: JsonObject | JsonObject[]; - steps: Array<{ - id?: string; - name?: string; - action: string; - input?: JsonObject; - if?: string | boolean; - }>; + parameters?: TemplateParametersV1beta3 | TemplateParametersV1beta3[]; + steps: Array; output?: { [name: string]: string; }; @@ -69,4 +84,16 @@ export type TemplateInfo = { metadata: EntityMeta; }; }; + +// @public +export interface TemplateParametersV1beta3 extends JsonObject { + // (undocumented) + 'backstage:permissions'?: TemplatePermissionsV1beta3; +} + +// @public +export interface TemplatePermissionsV1beta3 extends JsonObject { + // (undocumented) + tags?: string[]; +} ``` diff --git a/plugins/scaffolder-common/package.json b/plugins/scaffolder-common/package.json index c08763d98b..41c1b28fc1 100644 --- a/plugins/scaffolder-common/package.json +++ b/plugins/scaffolder-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-common", "description": "Common functionalities for the scaffolder, to be shared between scaffolder and scaffolder-backend plugin", - "version": "1.2.6", + "version": "1.2.7-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -11,6 +11,21 @@ "module": "dist/index.esm.js", "types": "dist/index.d.ts" }, + "exports": { + ".": "./src/index.ts", + "./alpha": "./src/alpha.ts", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "alpha": [ + "src/alpha.ts" + ], + "package.json": [ + "package.json" + ] + } + }, "backstage": { "role": "common-library" }, @@ -39,6 +54,7 @@ }, "dependencies": { "@backstage/catalog-model": "workspace:^", + "@backstage/plugin-permission-common": "workspace:^", "@backstage/types": "workspace:^" }, "devDependencies": { diff --git a/plugins/scaffolder-common/src/Template.v1beta3.schema.json b/plugins/scaffolder-common/src/Template.v1beta3.schema.json index e45bfb788d..beb0ca5e31 100644 --- a/plugins/scaffolder-common/src/Template.v1beta3.schema.json +++ b/plugins/scaffolder-common/src/Template.v1beta3.schema.json @@ -16,6 +16,9 @@ "owner": "artist-relations-team", "parameters": { "required": ["name", "description", "repoUrl"], + "backstage:permissions": { + "tags": ["one", "two"] + }, "properties": { "name": { "title": "Name", @@ -41,6 +44,9 @@ "action": "fetch:plain", "parameters": { "url": "./template" + }, + "backstage:permissions": { + "tags": ["one", "two"] } }, { @@ -92,14 +98,42 @@ "oneOf": [ { "type": "object", - "description": "The JSONSchema describing the inputs for the template." + "description": "The JSONSchema describing the inputs for the template.", + "properties": { + "backstage:permissions": { + "type": "object", + "description": "Object used for authorizing the parameter", + "properties": { + "tags": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } }, { "type": "array", "description": "A list of separate forms to collect parameters.", "items": { "type": "object", - "description": "The JSONSchema describing the inputs for the template." + "description": "The JSONSchema describing the inputs for the template.", + "properties": { + "backstage:permissions": { + "type": "object", + "description": "Object used for authorizing the parameter", + "properties": { + "tags": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } } } ] @@ -131,6 +165,18 @@ "if": { "type": ["string", "boolean"], "description": "A templated condition that skips the step when evaluated to false. If the condition is true or not defined, the step is executed. The condition is true, if the input is not `false`, `undefined`, `null`, `\"\"`, `0`, or `[]`." + }, + "backstage:permissions": { + "type": "object", + "description": "Object used for authorizing the step", + "properties": { + "tags": { + "type": "array", + "items": { + "type": "string" + } + } + } } } } diff --git a/plugins/scaffolder-common/src/TemplateEntityV1beta3.test.ts b/plugins/scaffolder-common/src/TemplateEntityV1beta3.test.ts index ab5900ab32..432292548e 100644 --- a/plugins/scaffolder-common/src/TemplateEntityV1beta3.test.ts +++ b/plugins/scaffolder-common/src/TemplateEntityV1beta3.test.ts @@ -15,7 +15,10 @@ */ import { entityKindSchemaValidator } from '@backstage/catalog-model'; -import type { TemplateEntityV1beta3 } from './TemplateEntityV1beta3'; +import type { + TemplateEntityV1beta3, + TemplateParametersV1beta3, +} from './TemplateEntityV1beta3'; import schema from './Template.v1beta3.schema.json'; const validator = entityKindSchemaValidator(schema); @@ -35,6 +38,7 @@ describe('templateEntityV1beta3Validator', () => { owner: 'team-b', parameters: { required: ['owner'], + 'backstage:permissions': { tags: ['one', 'two'] }, properties: { owner: { type: 'string', @@ -52,6 +56,9 @@ describe('templateEntityV1beta3Validator', () => { url: './template', }, if: '${{ parameters.owner }}', + 'backstage:permissions': { + tags: ['one', 'two'], + }, }, ], output: { @@ -154,4 +161,24 @@ describe('templateEntityV1beta3Validator', () => { (entity as any).spec.steps[0].if = 5; expect(() => validator(entity)).toThrow(/if/); }); + + it('rejects parameters with wrong backstage:permissions', async () => { + (entity.spec.parameters as TemplateParametersV1beta3)[ + 'backstage:permissions' + ]!.tags = true as unknown as []; + expect(() => validator(entity)).toThrow(/must be array/); + + (entity.spec.parameters as TemplateParametersV1beta3)[ + 'backstage:permissions' + ] = true as {}; + expect(() => validator(entity)).toThrow(/must be object/); + }); + + it('rejects steps with wrong backstage:permissions', async () => { + entity.spec.steps[0]['backstage:permissions']!.tags = true as unknown as []; + expect(() => validator(entity)).toThrow(/must be array/); + + entity.spec.steps[0]['backstage:permissions'] = true as {}; + expect(() => validator(entity)).toThrow(/must be object/); + }); }); diff --git a/plugins/scaffolder-common/src/TemplateEntityV1beta3.ts b/plugins/scaffolder-common/src/TemplateEntityV1beta3.ts index 8ded484ee2..ebabb5cad4 100644 --- a/plugins/scaffolder-common/src/TemplateEntityV1beta3.ts +++ b/plugins/scaffolder-common/src/TemplateEntityV1beta3.ts @@ -50,18 +50,12 @@ export interface TemplateEntityV1beta3 extends Entity { * to collect user input and validate it against that schema. This can then be used in the `steps` part below to template * variables passed from the user into each action in the template. */ - parameters?: JsonObject | JsonObject[]; + parameters?: TemplateParametersV1beta3 | TemplateParametersV1beta3[]; /** * A list of steps to be executed in sequence which are defined by the template. These steps are a list of the underlying * javascript action and some optional input parameters that may or may not have been collected from the end user. */ - steps: Array<{ - id?: string; - name?: string; - action: string; - input?: JsonObject; - if?: string | boolean; - }>; + steps: Array; /** * The output is an object where template authors can pull out information from template actions and return them in a known standard way. */ @@ -73,6 +67,38 @@ export interface TemplateEntityV1beta3 extends Entity { }; } +/** + * Step that is part of a Template Entity. + * + * @public + */ +export interface TemplateEntityStepV1beta3 extends JsonObject { + id?: string; + name?: string; + action: string; + input?: JsonObject; + if?: string | boolean; + 'backstage:permissions'?: TemplatePermissionsV1beta3; +} + +/** + * Parameter that is part of a Template Entity. + * + * @public + */ +export interface TemplateParametersV1beta3 extends JsonObject { + 'backstage:permissions'?: TemplatePermissionsV1beta3; +} + +/** + * Access control properties for parts of a template. + * + * @public + */ +export interface TemplatePermissionsV1beta3 extends JsonObject { + tags?: string[]; +} + const validator = entityKindSchemaValidator(schema); /** @@ -86,3 +112,13 @@ export const templateEntityV1beta3Validator: KindValidator = { return validator(data) === data; }, }; + +/** + * Typeguard for filtering entities and ensuring v1beta3 entities + * @public + */ +export const isTemplateEntityV1beta3 = ( + entity: Entity, +): entity is TemplateEntityV1beta3 => + entity.apiVersion === 'scaffolder.backstage.io/v1beta3' && + entity.kind === 'Template'; diff --git a/plugins/scaffolder-common/src/alpha.ts b/plugins/scaffolder-common/src/alpha.ts new file mode 100644 index 0000000000..9a8c021d15 --- /dev/null +++ b/plugins/scaffolder-common/src/alpha.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export * from './permissions'; diff --git a/plugins/scaffolder-common/src/index.ts b/plugins/scaffolder-common/src/index.ts index 521e678ab6..fd34fe6f41 100644 --- a/plugins/scaffolder-common/src/index.ts +++ b/plugins/scaffolder-common/src/index.ts @@ -21,5 +21,14 @@ */ export * from './TaskSpec'; -export { templateEntityV1beta3Validator } from './TemplateEntityV1beta3'; -export type { TemplateEntityV1beta3 } from './TemplateEntityV1beta3'; + +export { + templateEntityV1beta3Validator, + isTemplateEntityV1beta3, +} from './TemplateEntityV1beta3'; +export type { + TemplateEntityV1beta3, + TemplateEntityStepV1beta3, + TemplateParametersV1beta3, + TemplatePermissionsV1beta3, +} from './TemplateEntityV1beta3'; diff --git a/plugins/scaffolder-common/src/permissions.ts b/plugins/scaffolder-common/src/permissions.ts new file mode 100644 index 0000000000..858430eaf3 --- /dev/null +++ b/plugins/scaffolder-common/src/permissions.ts @@ -0,0 +1,69 @@ +/* + * 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 { createPermission } from '@backstage/plugin-permission-common'; + +/** + * Permission resource type which corresponds to a scaffolder templates. + * + * @alpha + */ +export const RESOURCE_TYPE_SCAFFOLDER_TEMPLATE = 'scaffolder-template'; + +/** + * This permission is used to authorize actions that involve reading + * one or more parameters from a template. + * + * If this permission is not authorized, it will appear that the + * parameter does not exist in the template — both in the frontend + * and in API responses. + * + * @alpha + */ +export const templateParameterReadPermission = createPermission({ + name: 'scaffolder.template.parameter.read', + attributes: { + action: 'read', + }, + resourceType: RESOURCE_TYPE_SCAFFOLDER_TEMPLATE, +}); + +/** + * This permission is used to authorize actions that involve reading + * one or more steps from a template. + * + * If this permission is not authorized, it will appear that the + * step does not exist in the template — both in the frontend + * and in API responses. Steps will also not be executed. + * + * @alpha + */ +export const templateStepReadPermission = createPermission({ + name: 'scaffolder.template.step.read', + attributes: { + action: 'read', + }, + resourceType: RESOURCE_TYPE_SCAFFOLDER_TEMPLATE, +}); + +/** + * List of all the scaffolder permissions + * @alpha + */ +export const scaffolderPermissions = [ + templateParameterReadPermission, + templateStepReadPermission, +]; diff --git a/plugins/scaffolder-node/CHANGELOG.md b/plugins/scaffolder-node/CHANGELOG.md index 663d7b1c39..aa73af9a1f 100644 --- a/plugins/scaffolder-node/CHANGELOG.md +++ b/plugins/scaffolder-node/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-scaffolder-node +## 0.1.2-next.0 + +### Patch Changes + +- e27ddc36dad: Added a possibility to cancel the running task (executing of a scaffolder template) +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.2.7-next.0 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/catalog-model@1.2.1 + - @backstage/types@1.0.2 + ## 0.1.1 ### Patch Changes diff --git a/plugins/scaffolder-node/api-report.md b/plugins/scaffolder-node/api-report.md index 89b7171ef9..d5b9b73767 100644 --- a/plugins/scaffolder-node/api-report.md +++ b/plugins/scaffolder-node/api-report.md @@ -30,6 +30,7 @@ export type ActionContext = { entity?: UserEntity; ref?: string; }; + signal?: AbortSignal; }; // @public diff --git a/plugins/scaffolder-node/package.json b/plugins/scaffolder-node/package.json index d349e41ec4..624fb4bdd2 100644 --- a/plugins/scaffolder-node/package.json +++ b/plugins/scaffolder-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-node", "description": "The plugin-scaffolder-node module for @backstage/plugin-scaffolder-backend", - "version": "0.1.1", + "version": "0.1.2-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder-node/src/actions/types.ts b/plugins/scaffolder-node/src/actions/types.ts index cce149adbe..8827aaf98c 100644 --- a/plugins/scaffolder-node/src/actions/types.ts +++ b/plugins/scaffolder-node/src/actions/types.ts @@ -60,6 +60,11 @@ export type ActionContext = { */ ref?: string; }; + + /** + * Implement the signal to make your custom step abortable https://developer.mozilla.org/en-US/docs/Web/API/AbortController/signal + */ + signal?: AbortSignal; }; /** @public */ diff --git a/plugins/scaffolder-react/CHANGELOG.md b/plugins/scaffolder-react/CHANGELOG.md index 744d687349..5993000724 100644 --- a/plugins/scaffolder-react/CHANGELOG.md +++ b/plugins/scaffolder-react/CHANGELOG.md @@ -1,5 +1,32 @@ # @backstage/plugin-scaffolder-react +## 1.3.0-next.0 + +### Minor Changes + +- 259d3407b9b: Move `CategoryPicker` from `scaffolder` into `scaffolder-react` + Move `ContextMenu` into `scaffolder-react` and rename it to `ScaffolderPageContextMenu` +- 2cfd03d7376: To offer better customization options, `ScaffolderPageContextMenu` takes callbacks as props instead of booleans +- 48da4c46e45: `scaffolder/next`: Export the `TemplateGroupFilter` and `TemplateGroups` and make an extensible component + +### Patch Changes + +- e27ddc36dad: Added a possibility to cancel the running task (executing of a scaffolder template) +- 7a6b16cc506: `scaffolder/next`: Bump `@rjsf/*` deps to 5.3.1 +- f84fc7fd040: Updated dependency `@rjsf/validator-ajv8` to `5.3.0`. +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.2.7-next.0 + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + - @backstage/types@1.0.2 + - @backstage/version-bridge@1.0.3 + ## 1.2.0 ### Minor Changes diff --git a/plugins/scaffolder-react/alpha-api-report.md b/plugins/scaffolder-react/alpha-api-report.md index 35029cb796..319e3963f0 100644 --- a/plugins/scaffolder-react/alpha-api-report.md +++ b/plugins/scaffolder-react/alpha-api-report.md @@ -132,6 +132,18 @@ export type ReviewStateProps = { formState: JsonObject; }; +// @alpha (undocumented) +export function ScaffolderPageContextMenu( + props: ScaffolderPageContextMenuProps, +): JSX.Element | null; + +// @alpha (undocumented) +export type ScaffolderPageContextMenuProps = { + onEditorClicked?: () => void; + onActionsClicked?: () => void; + onTasksClicked?: () => void; +}; + // @alpha export const Stepper: (stepperProps: StepperProps) => JSX.Element; @@ -190,9 +202,18 @@ export interface TemplateCardProps { template: TemplateEntityV1beta3; } +// @alpha +export const TemplateCategoryPicker: () => JSX.Element | null; + // @alpha export const TemplateGroup: (props: TemplateGroupProps) => JSX.Element; +// @alpha (undocumented) +export type TemplateGroupFilter = { + title?: React_2.ReactNode; + filter: (entity: TemplateEntityV1beta3) => boolean; +}; + // @alpha export interface TemplateGroupProps { // (undocumented) @@ -214,6 +235,29 @@ export interface TemplateGroupProps { title: React_2.ReactNode; } +// @alpha (undocumented) +export const TemplateGroups: (props: TemplateGroupsProps) => JSX.Element | null; + +// @alpha (undocumented) +export interface TemplateGroupsProps { + // (undocumented) + additionalLinksForEntity?: (template: TemplateEntityV1beta3) => { + icon: IconComponent; + text: string; + url: string; + }[]; + // (undocumented) + groups: TemplateGroupFilter[]; + // (undocumented) + onTemplateSelected?: (template: TemplateEntityV1beta3) => void; + // (undocumented) + TemplateCardComponent?: React_2.ComponentType<{ + template: TemplateEntityV1beta3; + }>; + // (undocumented) + templateFilter?: (entity: TemplateEntityV1beta3) => boolean; +} + // @alpha export const useFormDataFromQuery: ( initialState?: Record, diff --git a/plugins/scaffolder-react/api-report.md b/plugins/scaffolder-react/api-report.md index 0fbc8d0eed..da8309d5ec 100644 --- a/plugins/scaffolder-react/api-report.md +++ b/plugins/scaffolder-react/api-report.md @@ -113,7 +113,7 @@ export type ListActionsResponse = Array; // @public export type LogEvent = { - type: 'log' | 'completion'; + type: 'log' | 'completion' | 'cancelled'; body: { message: string; stepId?: string; @@ -126,6 +126,7 @@ export type LogEvent = { // @public export interface ScaffolderApi { + cancelTask(taskId: string): Promise; // (undocumented) dryRun?(options: ScaffolderDryRunOptions): Promise; // (undocumented) @@ -266,10 +267,11 @@ export type ScaffolderTaskOutput = { // @public export type ScaffolderTaskStatus = + | 'cancelled' + | 'completed' + | 'failed' | 'open' | 'processing' - | 'failed' - | 'completed' | 'skipped'; // @public @@ -287,6 +289,7 @@ export const SecretsContextProvider: ( // @public export type TaskStream = { + cancelled: boolean; loading: boolean; error?: Error; stepLogs: { diff --git a/plugins/scaffolder-react/package.json b/plugins/scaffolder-react/package.json index 012baa6aa5..0cae342b8c 100644 --- a/plugins/scaffolder-react/package.json +++ b/plugins/scaffolder-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-react", "description": "A frontend library that helps other Backstage plugins interact with the Scaffolder", - "version": "1.2.0", + "version": "1.3.0-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -57,14 +57,14 @@ "@backstage/version-bridge": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "@react-hookz/web": "^20.0.0", "@rjsf/core": "^3.2.1", - "@rjsf/core-v5": "npm:@rjsf/core@5.1.0", + "@rjsf/core-v5": "npm:@rjsf/core@5.3.1", "@rjsf/material-ui": "^3.2.1", - "@rjsf/material-ui-v5": "npm:@rjsf/material-ui@5.1.0", - "@rjsf/utils": "5.1.0", - "@rjsf/validator-ajv8": "5.1.0", + "@rjsf/material-ui-v5": "npm:@rjsf/material-ui@5.3.1", + "@rjsf/utils": "5.3.1", + "@rjsf/validator-ajv8": "5.3.1", "@types/json-schema": "^7.0.9", "classnames": "^2.2.6", "humanize-duration": "^3.25.1", diff --git a/plugins/scaffolder-react/src/api/types.ts b/plugins/scaffolder-react/src/api/types.ts index 0a517e7bff..b39555c14f 100644 --- a/plugins/scaffolder-react/src/api/types.ts +++ b/plugins/scaffolder-react/src/api/types.ts @@ -24,10 +24,11 @@ import { TemplateParameterSchema } from '../types'; * @public */ export type ScaffolderTaskStatus = + | 'cancelled' + | 'completed' + | 'failed' | 'open' | 'processing' - | 'failed' - | 'completed' | 'skipped'; /** @@ -96,7 +97,7 @@ export type ScaffolderTaskOutput = { * @public */ export type LogEvent = { - type: 'log' | 'completion'; + type: 'log' | 'completion' | 'cancelled'; body: { message: string; stepId?: string; @@ -196,6 +197,13 @@ export interface ScaffolderApi { getTask(taskId: string): Promise; + /** + * Sends a signal to a task broker to cancel the running task by taskId. + * + * @param taskId - the id of the task + */ + cancelTask(taskId: string): Promise; + listTasks?(options: { filterByOwnership: 'owned' | 'all'; }): Promise<{ tasks: ScaffolderTask[] }>; diff --git a/plugins/scaffolder-react/src/hooks/useEventStream.ts b/plugins/scaffolder-react/src/hooks/useEventStream.ts index d8c9cf4c1f..ec49911471 100644 --- a/plugins/scaffolder-react/src/hooks/useEventStream.ts +++ b/plugins/scaffolder-react/src/hooks/useEventStream.ts @@ -44,6 +44,7 @@ export type ScaffolderStep = { * @public */ export type TaskStream = { + cancelled: boolean; loading: boolean; error?: Error; stepLogs: { [stepId in string]: string[] }; @@ -66,6 +67,7 @@ type ReducerLogEntry = { type ReducerAction = | { type: 'INIT'; data: ScaffolderTask } + | { type: 'CANCELLED' } | { type: 'LOGS'; data: ReducerLogEntry[] } | { type: 'COMPLETED'; data: ReducerLogEntry } | { type: 'ERROR'; data: Error }; @@ -111,7 +113,7 @@ function reducer(draft: TaskStream, action: ReducerAction) { } if ( - ['cancelled', 'failed', 'completed'].includes(currentStep.status) + ['cancelled', 'completed', 'failed'].includes(currentStep.status) ) { currentStep.endedAt = entry.createdAt; } @@ -131,6 +133,11 @@ function reducer(draft: TaskStream, action: ReducerAction) { return; } + case 'CANCELLED': { + draft.cancelled = true; + return; + } + case 'ERROR': { draft.error = action.data; draft.loading = false; @@ -151,6 +158,7 @@ function reducer(draft: TaskStream, action: ReducerAction) { export const useTaskEventStream = (taskId: string): TaskStream => { const scaffolderApi = useApi(scaffolderApiRef); const [state, dispatch] = useImmerReducer(reducer, { + cancelled: false, loading: true, completed: false, stepLogs: {} as { [stepId in string]: string[] }, @@ -196,6 +204,9 @@ export const useTaskEventStream = (taskId: string): TaskStream => { switch (event.type) { case 'log': return collectedLogEvents.push(event); + case 'cancelled': + dispatch({ type: 'CANCELLED' }); + return undefined; case 'completion': emitLogs(); dispatch({ type: 'COMPLETED', data: event }); diff --git a/plugins/scaffolder/src/next/TemplateListPage/ContextMenu.tsx b/plugins/scaffolder-react/src/next/components/ScaffolderPageContextMenu/ScaffolderPageContextMenu.tsx similarity index 74% rename from plugins/scaffolder/src/next/TemplateListPage/ContextMenu.tsx rename to plugins/scaffolder-react/src/next/components/ScaffolderPageContextMenu/ScaffolderPageContextMenu.tsx index d78b8a62c4..fc3c0249a0 100644 --- a/plugins/scaffolder/src/next/TemplateListPage/ContextMenu.tsx +++ b/plugins/scaffolder-react/src/next/components/ScaffolderPageContextMenu/ScaffolderPageContextMenu.tsx @@ -14,7 +14,6 @@ * limitations under the License. */ -import { useRouteRef } from '@backstage/core-plugin-api'; import { BackstageTheme } from '@backstage/theme'; import IconButton from '@material-ui/core/IconButton'; import ListItemIcon from '@material-ui/core/ListItemIcon'; @@ -28,12 +27,6 @@ import Edit from '@material-ui/icons/Edit'; import List from '@material-ui/icons/List'; import MoreVert from '@material-ui/icons/MoreVert'; import React, { useState } from 'react'; -import { useNavigate } from 'react-router-dom'; -import { - nextActionsRouteRef, - nextEditRouteRef, - nextScaffolderListTaskRouteRef, -} from '../routes'; const useStyles = makeStyles((theme: BackstageTheme) => ({ button: { @@ -41,26 +34,26 @@ const useStyles = makeStyles((theme: BackstageTheme) => ({ }, })); +/** + * @alpha + */ export type ScaffolderPageContextMenuProps = { - editor?: boolean; - actions?: boolean; - tasks?: boolean; + onEditorClicked?: () => void; + onActionsClicked?: () => void; + onTasksClicked?: () => void; }; -export function ContextMenu(props: ScaffolderPageContextMenuProps) { +/** + * @alpha + */ +export function ScaffolderPageContextMenu( + props: ScaffolderPageContextMenuProps, +) { + const { onEditorClicked, onActionsClicked, onTasksClicked } = props; const classes = useStyles(); const [anchorEl, setAnchorEl] = useState(); - const editLink = useRouteRef(nextEditRouteRef); - const actionsLink = useRouteRef(nextActionsRouteRef); - const tasksLink = useRouteRef(nextScaffolderListTaskRouteRef); - const navigate = useNavigate(); - - const showEditor = props.editor !== false; - const showActions = props.actions !== false; - const showTasks = props.tasks !== false; - - if (!showEditor && !showActions) { + if (!onEditorClicked && !onActionsClicked) { return null; } @@ -93,24 +86,24 @@ export function ContextMenu(props: ScaffolderPageContextMenuProps) { transformOrigin={{ vertical: 'top', horizontal: 'right' }} > - {showEditor && ( - navigate(editLink())}> + {onEditorClicked && ( + )} - {showActions && ( - navigate(actionsLink())}> + {onActionsClicked && ( + )} - {showTasks && ( - navigate(tasksLink())}> + {onTasksClicked && ( + diff --git a/plugins/scaffolder-react/src/next/components/ScaffolderPageContextMenu/index.ts b/plugins/scaffolder-react/src/next/components/ScaffolderPageContextMenu/index.ts new file mode 100644 index 0000000000..ae6774a1e6 --- /dev/null +++ b/plugins/scaffolder-react/src/next/components/ScaffolderPageContextMenu/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 { + ScaffolderPageContextMenu, + type ScaffolderPageContextMenuProps, +} from './ScaffolderPageContextMenu'; diff --git a/plugins/scaffolder-react/src/next/components/TemplateCard/TemplateCard.tsx b/plugins/scaffolder-react/src/next/components/TemplateCard/TemplateCard.tsx index af44085151..2a0a34823d 100644 --- a/plugins/scaffolder-react/src/next/components/TemplateCard/TemplateCard.tsx +++ b/plugins/scaffolder-react/src/next/components/TemplateCard/TemplateCard.tsx @@ -142,20 +142,22 @@ export const TemplateCard = (props: TemplateCardProps) => { - {props.additionalLinks?.map(({ icon, text, url }) => ( - + {props.additionalLinks?.map(({ icon, text, url }, index) => ( + ))} - {template.metadata.links?.map(({ url, icon, title }) => ( - - - - ))} + {template.metadata.links?.map( + ({ url, icon, title }, index) => ( + + + + ), + )} diff --git a/plugins/scaffolder/src/next/TemplateListPage/CategoryPicker.test.tsx b/plugins/scaffolder-react/src/next/components/TemplateCategoryPicker/TemplateCategoryPicker.test.tsx similarity index 93% rename from plugins/scaffolder/src/next/TemplateListPage/CategoryPicker.test.tsx rename to plugins/scaffolder-react/src/next/components/TemplateCategoryPicker/TemplateCategoryPicker.test.tsx index f02ca51354..ce6e342809 100644 --- a/plugins/scaffolder/src/next/TemplateListPage/CategoryPicker.test.tsx +++ b/plugins/scaffolder-react/src/next/components/TemplateCategoryPicker/TemplateCategoryPicker.test.tsx @@ -16,7 +16,7 @@ import React from 'react'; import { useEntityTypeFilter } from '@backstage/plugin-catalog-react'; -import { CategoryPicker } from './CategoryPicker'; +import { TemplateCategoryPicker } from './TemplateCategoryPicker'; import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; import { alertApiRef } from '@backstage/core-plugin-api'; import { fireEvent } from '@testing-library/react'; @@ -25,7 +25,7 @@ jest.mock('@backstage/plugin-catalog-react', () => ({ useEntityTypeFilter: jest.fn(), })); -describe('CategoryPicker', () => { +describe('TemplateCategoryPicker', () => { const mockAlertApi = { post: jest.fn() }; beforeEach(() => { @@ -39,7 +39,7 @@ describe('CategoryPicker', () => { await renderInTestApp( - + , ); @@ -56,7 +56,7 @@ describe('CategoryPicker', () => { const { findByTestId } = await renderInTestApp( - + , ); @@ -70,7 +70,7 @@ describe('CategoryPicker', () => { const { queryByText } = await renderInTestApp( - + , ); @@ -86,7 +86,7 @@ describe('CategoryPicker', () => { const { getByRole } = await renderInTestApp( - + , ); @@ -108,7 +108,7 @@ describe('CategoryPicker', () => { const { getByRole } = await renderInTestApp( - + , ); @@ -139,7 +139,7 @@ describe('CategoryPicker', () => { const { getByRole } = await renderInTestApp( - + , ); diff --git a/plugins/scaffolder/src/next/TemplateListPage/CategoryPicker.tsx b/plugins/scaffolder-react/src/next/components/TemplateCategoryPicker/TemplateCategoryPicker.tsx similarity index 97% rename from plugins/scaffolder/src/next/TemplateListPage/CategoryPicker.tsx rename to plugins/scaffolder-react/src/next/components/TemplateCategoryPicker/TemplateCategoryPicker.tsx index 483751f2e2..028ce3a701 100644 --- a/plugins/scaffolder/src/next/TemplateListPage/CategoryPicker.tsx +++ b/plugins/scaffolder-react/src/next/components/TemplateCategoryPicker/TemplateCategoryPicker.tsx @@ -37,8 +37,9 @@ const checkedIcon = ; /** * The Category Picker that is rendered on the left side for picking * categories and filtering the template list. + * @alpha */ -export const CategoryPicker = () => { +export const TemplateCategoryPicker = () => { const alertApi = useApi(alertApiRef); const { error, loading, availableTypes, selectedTypes, setSelectedTypes } = useEntityTypeFilter(); diff --git a/plugins/scaffolder-react/src/next/components/TemplateCategoryPicker/index.ts b/plugins/scaffolder-react/src/next/components/TemplateCategoryPicker/index.ts new file mode 100644 index 0000000000..cf41f3f7f9 --- /dev/null +++ b/plugins/scaffolder-react/src/next/components/TemplateCategoryPicker/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { TemplateCategoryPicker } from './TemplateCategoryPicker'; diff --git a/plugins/scaffolder/src/next/TemplateListPage/TemplateGroups.test.tsx b/plugins/scaffolder-react/src/next/components/TemplateGroups/TemplateGroups.test.tsx similarity index 83% rename from plugins/scaffolder/src/next/TemplateListPage/TemplateGroups.test.tsx rename to plugins/scaffolder-react/src/next/components/TemplateGroups/TemplateGroups.test.tsx index 6fe2d6beb9..c03af41f99 100644 --- a/plugins/scaffolder/src/next/TemplateListPage/TemplateGroups.test.tsx +++ b/plugins/scaffolder-react/src/next/components/TemplateGroups/TemplateGroups.test.tsx @@ -28,7 +28,6 @@ import { TemplateGroups } from './TemplateGroups'; import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; import { errorApiRef } from '@backstage/core-plugin-api'; import { TemplateGroup } from '@backstage/plugin-scaffolder-react/alpha'; -import { nextRouteRef } from '../routes'; describe('TemplateGroups', () => { beforeEach(() => jest.clearAllMocks()); @@ -40,11 +39,6 @@ describe('TemplateGroups', () => { , - { - mountedRoutes: { - '/next': nextRouteRef, - }, - }, ); expect(await findByTestId('progress')).toBeInTheDocument(); @@ -62,11 +56,6 @@ describe('TemplateGroups', () => { , - { - mountedRoutes: { - '/next': nextRouteRef, - }, - }, ); expect(errorApi.post).toHaveBeenCalledWith(mockError); @@ -83,11 +72,6 @@ describe('TemplateGroups', () => { , - { - mountedRoutes: { - '/next': nextRouteRef, - }, - }, ); expect(await findByText(/No templates found/)).toBeInTheDocument(); @@ -104,11 +88,6 @@ describe('TemplateGroups', () => { , - { - mountedRoutes: { - '/next': nextRouteRef, - }, - }, ); expect(await findByText(/No templates found/)).toBeInTheDocument(); @@ -144,11 +123,6 @@ describe('TemplateGroups', () => { true }]} /> , - { - mountedRoutes: { - '/next': nextRouteRef, - }, - }, ); expect(TemplateGroup).toHaveBeenCalledWith( @@ -193,11 +167,6 @@ describe('TemplateGroups', () => { groups={[{ title: 'all', filter: e => e.metadata.name === 't1' }]} /> , - { - mountedRoutes: { - '/next': nextRouteRef, - }, - }, ); expect(TemplateGroup).toHaveBeenCalledWith( @@ -207,4 +176,47 @@ describe('TemplateGroups', () => { {}, ); }); + + it('should filter out templates based on filter condition', async () => { + const mockEntities = [ + { + apiVersion: 'scaffolder.backstage.io/v1beta3', + kind: 'Template', + metadata: { + name: 't1', + }, + spec: {}, + }, + { + apiVersion: 'scaffolder.backstage.io/v1beta3', + kind: 'Template', + metadata: { + name: 't2', + }, + spec: {}, + }, + ]; + + (useEntityList as jest.Mock).mockReturnValue({ + entities: mockEntities, + loading: false, + error: null, + }); + + await renderInTestApp( + + true }]} + templateFilter={e => e.metadata.name === 't1'} + /> + , + ); + + expect(TemplateGroup).toHaveBeenCalledWith( + expect.objectContaining({ + templates: [expect.objectContaining({ template: mockEntities[1] })], + }), + {}, + ); + }); }); diff --git a/plugins/scaffolder/src/next/TemplateListPage/TemplateGroups.tsx b/plugins/scaffolder-react/src/next/components/TemplateGroups/TemplateGroups.tsx similarity index 60% rename from plugins/scaffolder/src/next/TemplateListPage/TemplateGroups.tsx rename to plugins/scaffolder-react/src/next/components/TemplateGroups/TemplateGroups.tsx index 590ef802bd..50be7a4bdf 100644 --- a/plugins/scaffolder/src/next/TemplateListPage/TemplateGroups.tsx +++ b/plugins/scaffolder-react/src/next/components/TemplateGroups/TemplateGroups.tsx @@ -15,55 +15,54 @@ */ import React, { useCallback } from 'react'; -import { - Entity, - parseEntityRef, - stringifyEntityRef, -} from '@backstage/catalog-model'; import { useEntityList } from '@backstage/plugin-catalog-react'; -import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; -import { Progress, Link, DocsIcon } from '@backstage/core-components'; -import { Typography } from '@material-ui/core'; import { - errorApiRef, - useApi, - useApp, - useRouteRef, -} from '@backstage/core-plugin-api'; + isTemplateEntityV1beta3, + TemplateEntityV1beta3, +} from '@backstage/plugin-scaffolder-common'; +import { Progress, Link } from '@backstage/core-components'; +import { Typography } from '@material-ui/core'; +import { errorApiRef, IconComponent, useApi } from '@backstage/core-plugin-api'; import { TemplateGroup } from '@backstage/plugin-scaffolder-react/alpha'; -import { viewTechDocRouteRef } from '../../routes'; -import { nextSelectedTemplateRouteRef } from '../routes'; -import { useNavigate } from 'react-router-dom'; /** * @alpha */ export type TemplateGroupFilter = { title?: React.ReactNode; - filter: (entity: Entity) => boolean; + filter: (entity: TemplateEntityV1beta3) => boolean; }; +/** + * @alpha + */ export interface TemplateGroupsProps { groups: TemplateGroupFilter[]; + templateFilter?: (entity: TemplateEntityV1beta3) => boolean; TemplateCardComponent?: React.ComponentType<{ template: TemplateEntityV1beta3; }>; + onTemplateSelected?: (template: TemplateEntityV1beta3) => void; + additionalLinksForEntity?: (template: TemplateEntityV1beta3) => { + icon: IconComponent; + text: string; + url: string; + }[]; } +/** + * @alpha + */ export const TemplateGroups = (props: TemplateGroupsProps) => { const { loading, error, entities } = useEntityList(); - const { groups, TemplateCardComponent } = props; + const { groups, templateFilter, TemplateCardComponent, onTemplateSelected } = + props; const errorApi = useApi(errorApiRef); - const app = useApp(); - const viewTechDocsLink = useRouteRef(viewTechDocRouteRef); - const templateRoute = useRouteRef(nextSelectedTemplateRouteRef); - const navigate = useNavigate(); const onSelected = useCallback( (template: TemplateEntityV1beta3) => { - const { namespace, name } = parseEntityRef(stringifyEntityRef(template)); - navigate(templateRoute({ namespace, templateName: name })); + onTemplateSelected?.(template); }, - [navigate, templateRoute], + [onTemplateSelected], ); if (loading) { @@ -91,22 +90,12 @@ export const TemplateGroups = (props: TemplateGroupsProps) => { <> {groups.map(({ title, filter }, index) => { const templates = entities - .filter((e): e is TemplateEntityV1beta3 => filter(e)) + .filter(isTemplateEntityV1beta3) + .filter(e => (templateFilter ? !templateFilter(e) : true)) + .filter(filter) .map(template => { - const { kind, namespace, name } = parseEntityRef( - stringifyEntityRef(template), - ); const additionalLinks = - template.metadata.annotations?.['backstage.io/techdocs-ref'] && - viewTechDocsLink - ? [ - { - icon: app.getSystemIcon('docs') ?? DocsIcon, - text: 'View TechDocs', - url: viewTechDocsLink({ kind, namespace, name }), - }, - ] - : []; + props.additionalLinksForEntity?.(template) ?? []; return { template, diff --git a/plugins/scaffolder-react/src/next/components/TemplateGroups/index.ts b/plugins/scaffolder-react/src/next/components/TemplateGroups/index.ts new file mode 100644 index 0000000000..765883916c --- /dev/null +++ b/plugins/scaffolder-react/src/next/components/TemplateGroups/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export * from './TemplateGroups'; diff --git a/plugins/scaffolder-react/src/next/components/Workflow/Workflow.test.tsx b/plugins/scaffolder-react/src/next/components/Workflow/Workflow.test.tsx index 03604881d2..81c5a697e0 100644 --- a/plugins/scaffolder-react/src/next/components/Workflow/Workflow.test.tsx +++ b/plugins/scaffolder-react/src/next/components/Workflow/Workflow.test.tsx @@ -24,10 +24,10 @@ import { act, fireEvent } from '@testing-library/react'; import React from 'react'; import { Workflow } from './Workflow'; import { analyticsApiRef } from '@backstage/core-plugin-api'; -import { ScaffolderApi } from '../../../api/types'; -import { scaffolderApiRef } from '../../../api/ref'; +import { ScaffolderApi, scaffolderApiRef } from '../../../api'; const scaffolderApiMock: jest.Mocked = { + cancelTask: jest.fn(), scaffold: jest.fn(), getTemplateParameterSchema: jest.fn(), getIntegrationsList: jest.fn(), diff --git a/plugins/scaffolder-react/src/next/components/index.ts b/plugins/scaffolder-react/src/next/components/index.ts index 083d88927e..5bfa5ccdc8 100644 --- a/plugins/scaffolder-react/src/next/components/index.ts +++ b/plugins/scaffolder-react/src/next/components/index.ts @@ -17,8 +17,11 @@ export * from './Stepper'; export * from './TemplateCard'; export * from './ReviewState'; export * from './TemplateGroup'; +export * from './TemplateGroups'; export * from './Workflow'; export * from './TemplateOutputs'; export * from './Form'; export * from './TaskSteps'; export * from './TaskLogStream'; +export * from './TemplateCategoryPicker'; +export * from './ScaffolderPageContextMenu'; diff --git a/plugins/scaffolder/CHANGELOG.md b/plugins/scaffolder/CHANGELOG.md index f304d7b621..22741c6a14 100644 --- a/plugins/scaffolder/CHANGELOG.md +++ b/plugins/scaffolder/CHANGELOG.md @@ -1,5 +1,49 @@ # @backstage/plugin-scaffolder +## 1.13.0-next.0 + +### Minor Changes + +- cdab34fd9a2: scaffolder/next: removing the `routeRefs` and exporting the originals on `scaffolderPlugin.routes.x` instead +- e5ad1bd61ec: Allow `TemplateListPage` and `TemplateWizardPage` to be passed in as props +- 92cf86a4b5d: Added a `templateFilter` prop to the `` component to allow for filtering of templates through a function. +- 259d3407b9b: Move `CategoryPicker` from `scaffolder` into `scaffolder-react` + Move `ContextMenu` into `scaffolder-react` and rename it to `ScaffolderPageContextMenu` + +### Patch Changes + +- e27ddc36dad: Added a possibility to cancel the running task (executing of a scaffolder template) +- 57c1b4752fa: Allow use of `{ exists: true }` value inside filters to filter entities that has that key. + + this example will filter all entities that has the annotation `someAnnotation` set to any value. + + ```yaml + ui:options: + catalogFilter: + kind: Group + metadata.annotations.someAnnotation: { exists: true } + ``` + +- 7a6b16cc506: `scaffolder/next`: Bump `@rjsf/*` deps to 5.3.1 +- f84fc7fd040: Updated dependency `@rjsf/validator-ajv8` to `5.3.0`. +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.3.0-next.0 + - @backstage/plugin-scaffolder-common@1.2.7-next.0 + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/integration-react@1.1.12-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/plugin-permission-react@0.4.11 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + - @backstage/types@1.0.2 + - @backstage/plugin-catalog-common@1.0.12 + ## 1.12.0 ### Minor Changes diff --git a/plugins/scaffolder/alpha-api-report.md b/plugins/scaffolder/alpha-api-report.md index bf37acafc3..6ceacdc008 100644 --- a/plugins/scaffolder/alpha-api-report.md +++ b/plugins/scaffolder/alpha-api-report.md @@ -5,16 +5,15 @@ ```ts /// -import { Entity } from '@backstage/catalog-model'; import { FormProps as FormProps_2 } from '@backstage/plugin-scaffolder-react/alpha'; import type { FormProps as FormProps_3 } from '@rjsf/core-v5'; -import { PathParams } from '@backstage/core-plugin-api'; +import { LayoutOptions } from '@backstage/plugin-scaffolder-react'; +import { NextFieldExtensionOptions } from '@backstage/plugin-scaffolder-react/alpha'; import { PropsWithChildren } from 'react'; import { default as React_2 } from 'react'; -import { RouteRef } from '@backstage/core-plugin-api'; import { ScaffolderTaskOutput } from '@backstage/plugin-scaffolder-react'; -import { SubRouteRef } from '@backstage/core-plugin-api'; import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; +import { TemplateGroupFilter } from '@backstage/plugin-scaffolder-react/alpha'; // @alpha @deprecated export type FormProps = Pick< @@ -22,9 +21,6 @@ export type FormProps = Pick< 'transformErrors' | 'noHtml5Validate' >; -// @alpha (undocumented) -export const nextRouteRef: RouteRef; - // @alpha export type NextRouterProps = { components?: { @@ -35,8 +31,11 @@ export type NextRouterProps = { TemplateOutputsComponent?: React_2.ComponentType<{ output?: ScaffolderTaskOutput; }>; + TemplateListPageComponent?: React_2.ComponentType; + TemplateWizardPageComponent?: React_2.ComponentType; }; groups?: TemplateGroupFilter[]; + templateFilter?: (entity: TemplateEntityV1beta3) => boolean; FormProps?: FormProps_2; contextMenu?: { editor?: boolean; @@ -51,19 +50,24 @@ export const NextScaffolderPage: ( ) => JSX.Element; // @alpha (undocumented) -export const nextScaffolderTaskRouteRef: SubRouteRef< - PathParams<'/tasks/:taskId'> ->; +export type TemplateListPageProps = { + TemplateCardComponent?: React_2.ComponentType<{ + template: TemplateEntityV1beta3; + }>; + groups?: TemplateGroupFilter[]; + templateFilter?: (entity: TemplateEntityV1beta3) => boolean; + contextMenu?: { + editor?: boolean; + actions?: boolean; + tasks?: boolean; + }; +}; // @alpha (undocumented) -export const nextSelectedTemplateRouteRef: SubRouteRef< - PathParams<'/templates/:namespace/:templateName'> ->; - -// @alpha (undocumented) -export type TemplateGroupFilter = { - title?: React_2.ReactNode; - filter: (entity: Entity) => boolean; +export type TemplateWizardPageProps = { + customFieldExtensions: NextFieldExtensionOptions[]; + layouts?: LayoutOptions[]; + FormProps?: FormProps_2; }; // (No @packageDocumentation comment for this package) diff --git a/plugins/scaffolder/api-report.md b/plugins/scaffolder/api-report.md index 6b8d6d345f..8f37f7cf50 100644 --- a/plugins/scaffolder/api-report.md +++ b/plugins/scaffolder/api-report.md @@ -80,8 +80,22 @@ export const EntityPickerFieldExtension: FieldExtensionComponent_2< allowedKinds?: string[] | undefined; allowArbitraryValues?: boolean | undefined; catalogFilter?: - | Record - | Record[] + | Record< + string, + | string + | string[] + | { + exists?: boolean | undefined; + } + > + | Record< + string, + | string + | string[] + | { + exists?: boolean | undefined; + } + >[] | undefined; } >; @@ -95,8 +109,22 @@ export const EntityPickerFieldSchema: FieldSchema< allowedKinds?: string[] | undefined; allowArbitraryValues?: boolean | undefined; catalogFilter?: - | Record - | Record[] + | Record< + string, + | string + | string[] + | { + exists?: boolean | undefined; + } + > + | Record< + string, + | string + | string[] + | { + exists?: boolean | undefined; + } + >[] | undefined; } >; @@ -212,8 +240,22 @@ export const OwnerPickerFieldExtension: FieldExtensionComponent_2< allowedKinds?: string[] | undefined; allowArbitraryValues?: boolean | undefined; catalogFilter?: - | Record - | Record[] + | Record< + string, + | string + | string[] + | { + exists?: boolean | undefined; + } + > + | Record< + string, + | string + | string[] + | { + exists?: boolean | undefined; + } + >[] | undefined; } >; @@ -226,8 +268,22 @@ export const OwnerPickerFieldSchema: FieldSchema< allowedKinds?: string[] | undefined; allowArbitraryValues?: boolean | undefined; catalogFilter?: - | Record - | Record[] + | Record< + string, + | string + | string[] + | { + exists?: boolean | undefined; + } + > + | Record< + string, + | string + | string[] + | { + exists?: boolean | undefined; + } + >[] | undefined; } >; @@ -332,6 +388,7 @@ export type RouterProps = { title?: React_2.ReactNode; filter: (entity: Entity) => boolean; }>; + templateFilter?: (entity: TemplateEntityV1beta3) => boolean; defaultPreviewTemplate?: string; headerOptions?: { pageTitleOverride?: string; @@ -360,6 +417,8 @@ export class ScaffolderClient implements ScaffolderApi_2 { useLongPollingLogs?: boolean; }); // (undocumented) + cancelTask(taskId: string): Promise; + // (undocumented) dryRun( options: ScaffolderDryRunOptions_2, ): Promise; @@ -423,6 +482,9 @@ export const scaffolderPlugin: BackstagePlugin< PathParams<'/templates/:namespace/:templateName'> >; ongoingTask: SubRouteRef>; + actions: SubRouteRef; + listTasks: SubRouteRef; + edit: SubRouteRef; }, { registerComponent: ExternalRouteRef; diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index dc75dd1d01..357b727c95 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.12.0", + "version": "1.13.0-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -65,12 +65,12 @@ "@codemirror/view": "^6.0.0", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "@react-hookz/web": "^20.0.0", "@rjsf/core": "^3.2.1", "@rjsf/material-ui": "^3.2.1", - "@rjsf/utils": "5.1.0", - "@rjsf/validator-ajv8": "5.1.0", + "@rjsf/utils": "5.3.1", + "@rjsf/validator-ajv8": "5.3.1", "@uiw/react-codemirror": "^4.9.3", "classnames": "^2.2.6", "git-url-parse": "^13.0.0", diff --git a/plugins/scaffolder/src/alpha.ts b/plugins/scaffolder/src/alpha.ts index a460b0d7cc..d2bd762190 100644 --- a/plugins/scaffolder/src/alpha.ts +++ b/plugins/scaffolder/src/alpha.ts @@ -16,10 +16,8 @@ export { NextScaffolderPage } from './plugin'; export { - nextRouteRef, - nextScaffolderTaskRouteRef, - nextSelectedTemplateRouteRef, - type TemplateGroupFilter, type NextRouterProps, type FormProps, + type TemplateListPageProps, + type TemplateWizardPageProps, } from './next'; diff --git a/plugins/scaffolder/src/api.ts b/plugins/scaffolder/src/api.ts index 15bd1925b3..7a3f6c14bb 100644 --- a/plugins/scaffolder/src/api.ts +++ b/plugins/scaffolder/src/api.ts @@ -229,24 +229,22 @@ export class ScaffolderClient implements ScaffolderApi { const url = `${baseUrl}/v2/tasks/${encodeURIComponent( taskId, )}/eventstream`; + + const processEvent = (event: any) => { + if (event.data) { + try { + subscriber.next(JSON.parse(event.data)); + } catch (ex) { + subscriber.error(ex); + } + } + }; + const eventSource = new EventSource(url, { withCredentials: true }); - eventSource.addEventListener('log', (event: any) => { - if (event.data) { - try { - subscriber.next(JSON.parse(event.data)); - } catch (ex) { - subscriber.error(ex); - } - } - }); + eventSource.addEventListener('log', processEvent); + eventSource.addEventListener('cancelled', processEvent); eventSource.addEventListener('completion', (event: any) => { - if (event.data) { - try { - subscriber.next(JSON.parse(event.data)); - } catch (ex) { - subscriber.error(ex); - } - } + processEvent(event); eventSource.close(); subscriber.complete(); }); @@ -310,4 +308,19 @@ export class ScaffolderClient implements ScaffolderApi { return await response.json(); } + + async cancelTask(taskId: string): Promise { + const baseUrl = await this.discoveryApi.getBaseUrl('scaffolder'); + const url = `${baseUrl}/v2/tasks/${encodeURIComponent(taskId)}/cancel`; + + const response = await this.fetchApi.fetch(url, { + method: 'POST', + }); + + if (!response.ok) { + throw await ResponseError.fromResponse(response); + } + + return await response.json(); + } } diff --git a/plugins/scaffolder/src/components/ActionsPage/ActionsPage.test.tsx b/plugins/scaffolder/src/components/ActionsPage/ActionsPage.test.tsx index 552d0cea6a..90f6f9b393 100644 --- a/plugins/scaffolder/src/components/ActionsPage/ActionsPage.test.tsx +++ b/plugins/scaffolder/src/components/ActionsPage/ActionsPage.test.tsx @@ -25,6 +25,7 @@ import { rootRouteRef } from '../../routes'; const scaffolderApiMock: jest.Mocked = { scaffold: jest.fn(), + cancelTask: jest.fn(), getTemplateParameterSchema: jest.fn(), getIntegrationsList: jest.fn(), getTask: jest.fn(), diff --git a/plugins/scaffolder/src/components/Router.tsx b/plugins/scaffolder/src/components/Router.tsx index ccc2bd283b..05d5cc9f0a 100644 --- a/plugins/scaffolder/src/components/Router.tsx +++ b/plugins/scaffolder/src/components/Router.tsx @@ -58,6 +58,7 @@ export type RouterProps = { title?: React.ReactNode; filter: (entity: Entity) => boolean; }>; + templateFilter?: (entity: TemplateEntityV1beta3) => boolean; defaultPreviewTemplate?: string; headerOptions?: { pageTitleOverride?: string; @@ -81,7 +82,12 @@ export type RouterProps = { * @public */ export const Router = (props: RouterProps) => { - const { groups, components = {}, defaultPreviewTemplate } = props; + const { + groups, + templateFilter, + components = {}, + defaultPreviewTemplate, + } = props; const { ReviewStepComponent, TemplateCardComponent, TaskPageComponent } = components; @@ -126,6 +132,7 @@ export const Router = (props: RouterProps) => { element={ boolean; + filter: (entity: TemplateEntityV1beta3) => boolean; }>; + templateFilter?: (entity: TemplateEntityV1beta3) => boolean; contextMenu?: { editor?: boolean; actions?: boolean; @@ -64,13 +64,14 @@ export type ScaffolderPageProps = { export const ScaffolderPageContents = ({ TemplateCardComponent, groups, + templateFilter, contextMenu, headerOptions, }: ScaffolderPageProps) => { const registerComponentLink = useRouteRef(registerComponentRouteRef); const otherTemplatesGroup = { title: groups ? 'Other Templates' : 'Templates', - filter: (entity: Entity) => { + filter: (entity: TemplateEntityV1beta3) => { const filtered = (groups ?? []).map(group => group.filter(entity)); return !filtered.some(result => result === true); }, @@ -123,11 +124,13 @@ export const ScaffolderPageContents = ({ key={index} TemplateCardComponent={TemplateCardComponent} group={group} + templateFilter={templateFilter} /> ))} @@ -140,6 +143,7 @@ export const ScaffolderPageContents = ({ export const ScaffolderPage = ({ TemplateCardComponent, groups, + templateFilter, contextMenu, headerOptions, }: ScaffolderPageProps) => ( @@ -147,6 +151,7 @@ export const ScaffolderPage = ({ diff --git a/plugins/scaffolder/src/components/TaskPage/TaskPage.tsx b/plugins/scaffolder/src/components/TaskPage/TaskPage.tsx index f78d48e686..78cdc5d935 100644 --- a/plugins/scaffolder/src/components/TaskPage/TaskPage.tsx +++ b/plugins/scaffolder/src/components/TaskPage/TaskPage.tsx @@ -19,11 +19,15 @@ import { Content, ErrorPage, Header, - Page, LogViewer, + Page, Progress, } from '@backstage/core-components'; -import { useRouteRef, useRouteRefParams } from '@backstage/core-plugin-api'; +import { + useApi, + useRouteRef, + useRouteRefParams, +} from '@backstage/core-plugin-api'; import { BackstageTheme } from '@backstage/theme'; import { Button, @@ -59,6 +63,7 @@ import { scaffolderTaskRouteRef, selectedTemplateRouteRef, } from '../../routes'; +import { scaffolderApiRef } from '@backstage/plugin-scaffolder-react'; // typings are wrong for this library, so fallback to not parsing types. const humanizeDuration = require('humanize-duration'); @@ -188,9 +193,10 @@ export const TaskStatusStepper = memo( nonLinear > {steps.map((step, index) => { + const isCancelled = step.status === 'cancelled'; + const isActive = step.status === 'processing'; const isCompleted = step.status === 'completed'; const isFailed = step.status === 'failed'; - const isActive = step.status === 'processing'; const isSkipped = step.status === 'skipped'; return ( @@ -199,7 +205,7 @@ export const TaskStatusStepper = memo( { const { loadingText } = props; - const classes = useStyles(); const navigate = useNavigate(); const rootPath = useRouteRef(rootRouteRef); + const scaffolderApi = useApi(scaffolderApiRef); const templateRoute = useRouteRef(selectedTemplateRouteRef); const [userSelectedStepId, setUserSelectedStepId] = useState< string | undefined >(undefined); + const [clickedToCancel, setClickedToCancel] = useState(false); const [lastActiveStepId, setLastActiveStepId] = useState( undefined, ); const { taskId } = useRouteRefParams(scaffolderTaskRouteRef); const taskStream = useTaskEventStream(taskId); const completed = taskStream.completed; + const taskCancelled = taskStream.cancelled; const steps = useMemo( () => taskStream.task?.spec.steps.map(step => ({ @@ -295,9 +302,7 @@ export const TaskPage = (props: TaskPageProps) => { }, [taskStream.stepLogs, currentStepId, loadingText]); const taskNotFound = - taskStream.completed === true && - taskStream.loading === false && - !taskStream.task; + taskStream.completed && !taskStream.loading && !taskStream.task; const { output } = taskStream; @@ -320,6 +325,11 @@ export const TaskPage = (props: TaskPageProps) => { ); }; + const handleCancel = async () => { + setClickedToCancel(true); + await scaffolderApi.cancelTask(taskId); + }; + return (
{ > Start Over + diff --git a/plugins/scaffolder/src/components/TemplateList/TemplateList.test.tsx b/plugins/scaffolder/src/components/TemplateList/TemplateList.test.tsx new file mode 100644 index 0000000000..2ea417ad68 --- /dev/null +++ b/plugins/scaffolder/src/components/TemplateList/TemplateList.test.tsx @@ -0,0 +1,83 @@ +/* + * 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 { screen } from '@testing-library/react'; +import React from 'react'; +import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; +import { TemplateList } from './TemplateList'; +import { rootRouteRef } from '../../routes'; +import { + ScmIntegrationsApi, + scmIntegrationsApiRef, +} from '@backstage/integration-react'; +import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; + +jest.mock('@backstage/plugin-catalog-react', () => ({ + useEntityList: jest.fn().mockReturnValue({ + loading: false, + entities: [ + { + apiVersion: 'scaffolder.backstage.io/v1beta3', + kind: 'Template', + metadata: { + name: 't1', + }, + spec: {}, + }, + { + apiVersion: 'scaffolder.backstage.io/v1beta3', + kind: 'Template', + metadata: { + name: 't2', + }, + spec: {}, + }, + ], + }), + getEntityRelations: jest.fn().mockImplementation(() => []), + getEntitySourceLocation: jest.fn().mockImplementation(() => ({})), +})); + +describe('TemplateList', () => { + const mockIntegrationsApi: Partial = { + byHost: () => ({ type: 'github' }), + }; + + it('should filter out templates based on provided filter condition', async () => { + const TemplateCardComponent = ({ + template, + }: { + template: TemplateEntityV1beta3; + }) => ( +
{template.metadata.name}
+ ); + + await renderInTestApp( + +
+ e.metadata.name === 't1'} + TemplateCardComponent={TemplateCardComponent} + /> +
+
, + { mountedRoutes: { '/': rootRouteRef } }, + ); + + expect(() => screen.getByTestId('t1')).toThrow(); + expect(screen.getByTestId('t2')).toBeDefined(); + }); +}); diff --git a/plugins/scaffolder/src/components/TemplateList/TemplateList.tsx b/plugins/scaffolder/src/components/TemplateList/TemplateList.tsx index 90d1c8cceb..9a88050d74 100644 --- a/plugins/scaffolder/src/components/TemplateList/TemplateList.tsx +++ b/plugins/scaffolder/src/components/TemplateList/TemplateList.tsx @@ -16,7 +16,10 @@ import React, { ComponentType } from 'react'; import { Entity, stringifyEntityRef } from '@backstage/catalog-model'; -import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; +import { + isTemplateEntityV1beta3, + TemplateEntityV1beta3, +} from '@backstage/plugin-scaffolder-common'; import { Content, ContentHeader, @@ -38,8 +41,9 @@ export type TemplateListProps = { | undefined; group?: { title?: React.ReactNode; - filter: (entity: Entity) => boolean; + filter: (entity: TemplateEntityV1beta3) => boolean; }; + templateFilter?: (entity: TemplateEntityV1beta3) => boolean; }; /** @@ -48,12 +52,14 @@ export type TemplateListProps = { export const TemplateList = ({ TemplateCardComponent, group, + templateFilter, }: TemplateListProps) => { const { loading, error, entities } = useEntityList(); const Card = TemplateCardComponent || TemplateCard; - const maybeFilteredEntities = group - ? entities.filter(e => group.filter(e)) - : entities; + const templateEntities = entities.filter(isTemplateEntityV1beta3); + const maybeFilteredEntities = ( + group ? templateEntities.filter(group.filter) : templateEntities + ).filter(e => (templateFilter ? !templateFilter(e) : true)); const titleComponent: React.ReactNode = (() => { if (group && group.title) { diff --git a/plugins/scaffolder/src/components/TemplatePage/TemplatePage.test.tsx b/plugins/scaffolder/src/components/TemplatePage/TemplatePage.test.tsx index b4358146fd..344929fa43 100644 --- a/plugins/scaffolder/src/components/TemplatePage/TemplatePage.test.tsx +++ b/plugins/scaffolder/src/components/TemplatePage/TemplatePage.test.tsx @@ -47,6 +47,7 @@ jest.mock('react-router-dom', () => { }); const scaffolderApiMock: jest.Mocked = { + cancelTask: jest.fn(), scaffold: jest.fn(), getTemplateParameterSchema: jest.fn(), getIntegrationsList: jest.fn(), @@ -338,10 +339,7 @@ describe('TemplatePage', () => { it('should display a section or property based on a feature flag', async () => { featureFlagsApiMock.isActive.mockImplementation(flag => { - if (flag === 'experimental-feature') { - return true; - } - return false; + return flag === 'experimental-feature'; }); scaffolderApiMock.getTemplateParameterSchema.mockResolvedValue( schemaMockValue, diff --git a/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.test.tsx b/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.test.tsx index 3cc45e6412..937ff7d07a 100644 --- a/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.test.tsx +++ b/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.test.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { EntityFilterQuery } from '@backstage/catalog-client'; +import { CATALOG_FILTER_EXISTS } from '@backstage/catalog-client'; import { Entity } from '@backstage/catalog-model'; import { CatalogApi, catalogApiRef } from '@backstage/plugin-catalog-react'; import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; @@ -22,6 +22,7 @@ import { FieldProps } from '@rjsf/core'; import { fireEvent } from '@testing-library/react'; import React from 'react'; import { EntityPicker } from './EntityPicker'; +import { EntityPickerProps } from './schema'; const makeEntity = (kind: string, namespace: string, name: string): Entity => ({ apiVersion: 'backstage.io/v1beta1', @@ -34,15 +35,7 @@ describe('', () => { const onChange = jest.fn(); const schema = {}; const required = false; - let uiSchema: { - 'ui:options': { - allowedKinds?: string[]; - defaultKind?: string; - allowArbitraryValues?: boolean; - defaultNamespace?: string | false; - catalogFilter?: EntityFilterQuery; - }; - }; + let uiSchema: EntityPickerProps['uiSchema']; const rawErrors: string[] = []; const formData = undefined; @@ -192,6 +185,59 @@ describe('', () => { ], }); }); + it('allow single top level filter', async () => { + uiSchema = { + 'ui:options': { + catalogFilter: { + kind: ['Group'], + 'metadata.name': 'test-entity', + }, + }, + }; + + catalogApi.getEntities.mockResolvedValue({ items: entities }); + + await renderInTestApp( + + + , + ); + + expect(catalogApi.getEntities).toHaveBeenCalledWith({ + filter: { + kind: ['Group'], + 'metadata.name': 'test-entity', + }, + }); + }); + + it('search for entitities containing an specific key', async () => { + const uiSchemaWithBoolean = { + 'ui:options': { + catalogFilter: [ + { + kind: ['User'], + 'metadata.annotation.some/anotation': { exists: true }, + }, + ], + }, + }; + + await renderInTestApp( + + + , + ); + + expect(catalogApi.getEntities).toHaveBeenCalledWith({ + filter: [ + { + kind: ['User'], + 'metadata.annotation.some/anotation': CATALOG_FILTER_EXISTS, + }, + ], + }); + }); }); describe('catalogFilter should take precedence over allowedKinds', () => { diff --git a/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.tsx b/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.tsx index 48d6453ab9..aeb4a52f77 100644 --- a/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.tsx +++ b/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.tsx @@ -13,7 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { type EntityFilterQuery } from '@backstage/catalog-client'; +import { + type EntityFilterQuery, + CATALOG_FILTER_EXISTS, +} from '@backstage/catalog-client'; import { Entity, parseEntityRef, @@ -31,7 +34,12 @@ import Autocomplete, { } from '@material-ui/lab/Autocomplete'; import React, { useCallback, useEffect } from 'react'; import useAsync from 'react-use/lib/useAsync'; -import { EntityPickerProps } from './schema'; +import { + EntityPickerFilterQueryValue, + EntityPickerProps, + EntityPickerUiOptions, + EntityPickerFilterQuery, +} from './schema'; export { EntityPickerSchema } from './schema'; @@ -51,12 +59,7 @@ export const EntityPicker = (props: EntityPickerProps) => { formData, idSchema, } = props; - const allowedKinds = uiSchema['ui:options']?.allowedKinds; - - const catalogFilter: EntityFilterQuery | undefined = - uiSchema['ui:options']?.catalogFilter || - (allowedKinds && { kind: allowedKinds }); - + const catalogFilter = buildCatalogFilter(uiSchema); const defaultKind = uiSchema['ui:options']?.defaultKind; const defaultNamespace = uiSchema['ui:options']?.defaultNamespace || undefined; @@ -167,3 +170,71 @@ export const EntityPicker = (props: EntityPickerProps) => { ); }; + +/** + * Converts a especial `{exists: true}` value to the `CATALOG_FILTER_EXISTS` symbol. + * + * @param value - The value to convert. + * @returns The converted value. + */ +function convertOpsValues( + value: Exclude>, +): string | symbol { + if (typeof value === 'object' && value.exists) { + return CATALOG_FILTER_EXISTS; + } + return value?.toString(); +} + +/** + * Converts schema filters to entity filter query, replacing `{exists:true}` values + * with the constant `CATALOG_FILTER_EXISTS`. + * + * @param schemaFilters - An object containing schema filters with keys as filter names + * and values as filter values. + * @returns An object with the same keys as the input object, but with `{exists:true}` values + * transformed to `CATALOG_FILTER_EXISTS` symbol. + */ +function convertSchemaFiltersToQuery( + schemaFilters: EntityPickerFilterQuery, +): Exclude> { + const query: EntityFilterQuery = {}; + + for (const [key, value] of Object.entries(schemaFilters)) { + if (Array.isArray(value)) { + query[key] = value; + } else { + query[key] = convertOpsValues(value); + } + } + + return query; +} + +/** + * Builds an `EntityFilterQuery` based on the `uiSchema` passed in. + * If `catalogFilter` is specified in the `uiSchema`, it is converted to a `EntityFilterQuery`. + * If `allowedKinds` is specified in the `uiSchema` will support the legacy `allowedKinds` option. + * + * @param uiSchema The `uiSchema` of an `EntityPicker` component. + * @returns An `EntityFilterQuery` based on the `uiSchema`, or `undefined` if `catalogFilter` is not specified in the `uiSchema`. + */ +function buildCatalogFilter( + uiSchema: EntityPickerProps['uiSchema'], +): EntityFilterQuery | undefined { + const allowedKinds = uiSchema['ui:options']?.allowedKinds; + + const catalogFilter: EntityPickerUiOptions['catalogFilter'] | undefined = + uiSchema['ui:options']?.catalogFilter || + (allowedKinds && { kind: allowedKinds }); + + if (!catalogFilter) { + return undefined; + } + + if (Array.isArray(catalogFilter)) { + return catalogFilter.map(convertSchemaFiltersToQuery); + } + + return convertSchemaFiltersToQuery(catalogFilter); +} diff --git a/plugins/scaffolder/src/components/fields/EntityPicker/schema.ts b/plugins/scaffolder/src/components/fields/EntityPicker/schema.ts index f83dfbf817..eb1bba364b 100644 --- a/plugins/scaffolder/src/components/fields/EntityPicker/schema.ts +++ b/plugins/scaffolder/src/components/fields/EntityPicker/schema.ts @@ -20,7 +20,10 @@ import { makeFieldSchemaFromZod } from '../utils'; * @public */ export const entityQueryFilterExpressionSchema = z.record( - z.string().or(z.array(z.string())), + z + .string() + .or(z.object({ exists: z.boolean().optional() })) + .or(z.array(z.string())), ); /** @@ -74,3 +77,10 @@ export type EntityPickerUiOptions = export type EntityPickerProps = typeof EntityPickerFieldSchema.type; export const EntityPickerSchema = EntityPickerFieldSchema.schema; + +export type EntityPickerFilterQuery = z.TypeOf< + typeof entityQueryFilterExpressionSchema +>; + +export type EntityPickerFilterQueryValue = + EntityPickerFilterQuery[keyof EntityPickerFilterQuery]; diff --git a/plugins/scaffolder/src/next/OngoingTask/ContextMenu.tsx b/plugins/scaffolder/src/next/OngoingTask/ContextMenu.tsx index d4c771a9f8..985dd98903 100644 --- a/plugins/scaffolder/src/next/OngoingTask/ContextMenu.tsx +++ b/plugins/scaffolder/src/next/OngoingTask/ContextMenu.tsx @@ -23,15 +23,21 @@ import { MenuList, Popover, } from '@material-ui/core'; +import { useAsync } from '@react-hookz/web'; +import Cancel from '@material-ui/icons/Cancel'; import Retry from '@material-ui/icons/Repeat'; import Toc from '@material-ui/icons/Toc'; import MoreVert from '@material-ui/icons/MoreVert'; import React, { useState } from 'react'; +import { useApi } from '@backstage/core-plugin-api'; +import { scaffolderApiRef } from '@backstage/plugin-scaffolder-react'; type ContextMenuProps = { + cancelEnabled?: boolean; logsVisible?: boolean; - onToggleLogs?: (state: boolean) => void; onStartOver?: () => void; + onToggleLogs?: (state: boolean) => void; + taskId?: string; }; const useStyles = makeStyles((theme: BackstageTheme) => ({ @@ -41,10 +47,18 @@ const useStyles = makeStyles((theme: BackstageTheme) => ({ })); export const ContextMenu = (props: ContextMenuProps) => { - const { logsVisible, onToggleLogs, onStartOver } = props; + const { cancelEnabled, logsVisible, onStartOver, onToggleLogs, taskId } = + props; const classes = useStyles(); + const scaffolderApi = useApi(scaffolderApiRef); const [anchorEl, setAnchorEl] = useState(); + const [{ status: cancelStatus }, { execute: cancel }] = useAsync(async () => { + if (taskId) { + await scaffolderApi.cancelTask(taskId); + } + }); + return ( <> { + + + + + + diff --git a/plugins/scaffolder/src/next/OngoingTask/OngoingTask.test.tsx b/plugins/scaffolder/src/next/OngoingTask/OngoingTask.test.tsx new file mode 100644 index 0000000000..c31322a9eb --- /dev/null +++ b/plugins/scaffolder/src/next/OngoingTask/OngoingTask.test.tsx @@ -0,0 +1,84 @@ +/* + * 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 { OngoingTask } from './OngoingTask'; +import React from 'react'; +import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; +import { scaffolderApiRef } from '@backstage/plugin-scaffolder-react'; +import { act, fireEvent, waitFor } from '@testing-library/react'; +import { rootRouteRef } from '../../routes'; + +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ taskId: 'my-task' }), +})); + +jest.mock('@backstage/plugin-scaffolder-react', () => ({ + ...jest.requireActual('@backstage/plugin-scaffolder-react'), + useTaskEventStream: () => ({ + cancelled: false, + loading: true, + stepLogs: {}, + completed: false, + steps: {}, + task: { + spec: { + steps: [], + templateInfo: { entity: { metadata: { name: 'my-template' } } }, + }, + }, + }), +})); + +describe('OngoingTask', () => { + const mockScaffolderApi = { + cancelTask: jest.fn(), + getTask: jest.fn().mockImplementation(async () => {}), + }; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should trigger cancel api on "Cancel" click in context menu', async () => { + const cancelOptionLabel = 'Cancel'; + const rendered = await renderInTestApp( + + + , + { mountedRoutes: { '/': rootRouteRef } }, + ); + const { getByText, getByTestId } = rendered; + + await act(async () => { + fireEvent.click(getByTestId('menu-button')); + }); + expect(getByTestId('cancel-task')).not.toHaveClass('Mui-disabled'); + + await act(async () => { + fireEvent.click(getByText(cancelOptionLabel)); + }); + + expect(mockScaffolderApi.cancelTask).toHaveBeenCalled(); + await act(async () => { + fireEvent.click(getByTestId('menu-button')); + }); + + await waitFor(() => { + expect(getByTestId('cancel-task')).toHaveClass('Mui-disabled'); + }); + }); +}); diff --git a/plugins/scaffolder/src/next/OngoingTask/OngoingTask.tsx b/plugins/scaffolder/src/next/OngoingTask/OngoingTask.tsx index fc1c1a7413..f8026cf073 100644 --- a/plugins/scaffolder/src/next/OngoingTask/OngoingTask.tsx +++ b/plugins/scaffolder/src/next/OngoingTask/OngoingTask.tsx @@ -13,15 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import React, { useEffect, useMemo, useState, useCallback } from 'react'; -import { Page, Header, Content, ErrorPanel } from '@backstage/core-components'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import { Content, ErrorPanel, Header, Page } from '@backstage/core-components'; import { useNavigate, useParams } from 'react-router-dom'; import { Box, makeStyles, Paper } from '@material-ui/core'; import { ScaffolderTaskOutput, useTaskEventStream, } from '@backstage/plugin-scaffolder-react'; -import { nextSelectedTemplateRouteRef } from '../routes'; +import { selectedTemplateRouteRef } from '../../routes'; import { useRouteRef } from '@backstage/core-plugin-api'; import qs from 'qs'; import { ContextMenu } from './ContextMenu'; @@ -45,7 +45,7 @@ export const OngoingTask = (props: { }) => { // todo(blam): check that task Id actually exists, and that it's valid. otherwise redirect to something more useful. const { taskId } = useParams(); - const templateRouteRef = useRouteRef(nextSelectedTemplateRouteRef); + const templateRouteRef = useRouteRef(selectedTemplateRouteRef); const navigate = useNavigate(); const taskStream = useTaskEventStream(taskId!); const classes = useStyles(); @@ -105,6 +105,8 @@ export const OngoingTask = (props: { const templateName = taskStream.task?.spec.templateInfo?.entity?.metadata.name; + const cancelEnabled = !(taskStream.cancelled || taskStream.completed); + return (
diff --git a/plugins/scaffolder/src/next/Router/Router.test.tsx b/plugins/scaffolder/src/next/Router/Router.test.tsx index 9565572a2f..3d52dd0dd0 100644 --- a/plugins/scaffolder/src/next/Router/Router.test.tsx +++ b/plugins/scaffolder/src/next/Router/Router.test.tsx @@ -47,6 +47,21 @@ describe('Router', () => { expect(TemplateListPage).toHaveBeenCalled(); }); + + it('should render user-provided TemplateListPage', async () => { + const { getByText } = await renderInTestApp( + <>foobar, + }} + />, + { + routeEntries: ['/'], + }, + ); + expect(getByText('foobar')).toBeInTheDocument(); + expect(TemplateListPage).not.toHaveBeenCalled(); + }); }); describe('/templates/:templateName', () => { @@ -58,6 +73,21 @@ describe('Router', () => { expect(TemplateWizardPage).toHaveBeenCalled(); }); + it('should render user-provided TemplateWizardPage', async () => { + const { getByText } = await renderInTestApp( + <>foobar, + }} + />, + { + routeEntries: ['/templates/default/foo'], + }, + ); + expect(getByText('foobar')).toBeInTheDocument(); + expect(TemplateWizardPage).not.toHaveBeenCalled(); + }); + it('should pass through the FormProps property', async () => { const transformErrorsMock = jest.fn(); diff --git a/plugins/scaffolder/src/next/Router/Router.tsx b/plugins/scaffolder/src/next/Router/Router.tsx index 5e199cae9b..9c50d0d979 100644 --- a/plugins/scaffolder/src/next/Router/Router.tsx +++ b/plugins/scaffolder/src/next/Router/Router.tsx @@ -15,11 +15,15 @@ */ import React, { PropsWithChildren } from 'react'; import { Routes, Route, useOutlet } from 'react-router-dom'; -import { TemplateListPage } from '../TemplateListPage'; -import { TemplateWizardPage } from '../TemplateWizardPage'; +import { TemplateListPage, TemplateListPageProps } from '../TemplateListPage'; +import { + TemplateWizardPage, + TemplateWizardPageProps, +} from '../TemplateWizardPage'; import { NextFieldExtensionOptions, FormProps, + TemplateGroupFilter, } from '@backstage/plugin-scaffolder-react/alpha'; import { ScaffolderTaskOutput, @@ -29,16 +33,15 @@ import { } from '@backstage/plugin-scaffolder-react'; import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; -import { TemplateGroupFilter } from '../TemplateListPage/TemplateGroups'; import { DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS } from '../../extensions/default'; import { - nextActionsRouteRef, - nextEditRouteRef, - nextScaffolderListTaskRouteRef, - nextScaffolderTaskRouteRef, - nextSelectedTemplateRouteRef, -} from '../routes'; + actionsRouteRef, + editRouteRef, + scaffolderListTaskRouteRef, + scaffolderTaskRouteRef, + selectedTemplateRouteRef, +} from '../../routes'; import { ErrorPage } from '@backstage/core-components'; import { OngoingTask } from '../OngoingTask'; import { ActionsPage } from '../../components/ActionsPage'; @@ -59,8 +62,11 @@ export type NextRouterProps = { TemplateOutputsComponent?: React.ComponentType<{ output?: ScaffolderTaskOutput; }>; + TemplateListPageComponent?: React.ComponentType; + TemplateWizardPageComponent?: React.ComponentType; }; groups?: TemplateGroupFilter[]; + templateFilter?: (entity: TemplateEntityV1beta3) => boolean; // todo(blam): rename this to formProps FormProps?: FormProps; contextMenu?: { @@ -84,6 +90,8 @@ export const Router = (props: PropsWithChildren) => { TemplateCardComponent, TemplateOutputsComponent, TaskPageComponent = OngoingTask, + TemplateListPageComponent = TemplateListPage, + TemplateWizardPageComponent = TemplateWizardPage, } = {}, } = props; const outlet = useOutlet() || props.children; @@ -107,18 +115,19 @@ export const Router = (props: PropsWithChildren) => { } /> - ) => { } /> ) => { } /> ) => { } /> - } /> + } /> } /> { @@ -63,7 +63,7 @@ describe('TemplateListPage', () => { > , - { mountedRoutes: { '/': nextRouteRef } }, + { mountedRoutes: { '/': rootRouteRef } }, ); expect(getByPlaceholderText('Search')).toBeInTheDocument(); @@ -85,7 +85,7 @@ describe('TemplateListPage', () => { > , - { mountedRoutes: { '/': nextRouteRef } }, + { mountedRoutes: { '/': rootRouteRef } }, ); expect(getByRole('menuitem', { name: /All/ })).toBeInTheDocument(); @@ -108,7 +108,7 @@ describe('TemplateListPage', () => { > , - { mountedRoutes: { '/': nextRouteRef } }, + { mountedRoutes: { '/': rootRouteRef } }, ); expect(getByText('Categories')).toBeInTheDocument(); @@ -135,4 +135,54 @@ describe('TemplateListPage', () => { expect(getByText('Tags')).toBeInTheDocument(); }); + + describe('scaffolder page context menu', () => { + it('should render if context menu props are not set to false', async () => { + const { queryByTestId } = await renderInTestApp( + + + , + { mountedRoutes: { '/': rootRouteRef } }, + ); + expect(queryByTestId('menu-button')).toBeInTheDocument(); + }); + + it('should not render if context menu props are set to false', async () => { + const { queryByTestId } = await renderInTestApp( + + + , + { mountedRoutes: { '/': rootRouteRef } }, + ); + expect(queryByTestId('menu-button')).not.toBeInTheDocument(); + }); + }); }); diff --git a/plugins/scaffolder/src/next/TemplateListPage/TemplateListPage.tsx b/plugins/scaffolder/src/next/TemplateListPage/TemplateListPage.tsx index bddc15a61b..863d3009e1 100644 --- a/plugins/scaffolder/src/next/TemplateListPage/TemplateListPage.tsx +++ b/plugins/scaffolder/src/next/TemplateListPage/TemplateListPage.tsx @@ -14,12 +14,15 @@ * limitations under the License. */ -import React from 'react'; +import React, { useCallback } from 'react'; +import { useNavigate } from 'react-router-dom'; import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; +import { useApp, useRouteRef } from '@backstage/core-plugin-api'; import { Content, ContentHeader, + DocsIcon, Header, Page, SupportButton, @@ -32,18 +35,33 @@ import { CatalogFilterLayout, UserListPicker, } from '@backstage/plugin-catalog-react'; -import { CategoryPicker } from './CategoryPicker'; -import { RegisterExistingButton } from './RegisterExistingButton'; -import { useRouteRef } from '@backstage/core-plugin-api'; -import { TemplateGroupFilter, TemplateGroups } from './TemplateGroups'; -import { registerComponentRouteRef } from '../../routes'; -import { ContextMenu } from './ContextMenu'; +import { + ScaffolderPageContextMenu, + TemplateCategoryPicker, + TemplateGroupFilter, + TemplateGroups, +} from '@backstage/plugin-scaffolder-react/alpha'; +import { RegisterExistingButton } from './RegisterExistingButton'; +import { + actionsRouteRef, + editRouteRef, + registerComponentRouteRef, + scaffolderListTaskRouteRef, + selectedTemplateRouteRef, + viewTechDocRouteRef, +} from '../../routes'; +import { parseEntityRef, stringifyEntityRef } from '@backstage/catalog-model'; + +/** + * @alpha + */ export type TemplateListPageProps = { TemplateCardComponent?: React.ComponentType<{ template: TemplateEntityV1beta3; }>; groups?: TemplateGroupFilter[]; + templateFilter?: (entity: TemplateEntityV1beta3) => boolean; contextMenu?: { editor?: boolean; actions?: boolean; @@ -66,14 +84,71 @@ const createGroupsWithOther = ( }, ]; +/** + * @alpha + */ export const TemplateListPage = (props: TemplateListPageProps) => { const registerComponentLink = useRouteRef(registerComponentRouteRef); - const { TemplateCardComponent, groups: givenGroups = [] } = props; + const { + TemplateCardComponent, + groups: givenGroups = [], + templateFilter, + } = props; + const navigate = useNavigate(); + const editorLink = useRouteRef(editRouteRef); + const actionsLink = useRouteRef(actionsRouteRef); + const tasksLink = useRouteRef(scaffolderListTaskRouteRef); + const viewTechDocsLink = useRouteRef(viewTechDocRouteRef); + const templateRoute = useRouteRef(selectedTemplateRouteRef); + const app = useApp(); const groups = givenGroups.length ? createGroupsWithOther(givenGroups) : [defaultGroup]; + const scaffolderPageContextMenuProps = { + onEditorClicked: + props?.contextMenu?.editor !== false + ? () => navigate(editorLink()) + : undefined, + onActionsClicked: + props?.contextMenu?.actions !== false + ? () => navigate(actionsLink()) + : undefined, + onTasksClicked: + props?.contextMenu?.tasks !== false + ? () => navigate(tasksLink()) + : undefined, + }; + + const additionalLinksForEntity = useCallback( + (template: TemplateEntityV1beta3) => { + const { kind, namespace, name } = parseEntityRef( + stringifyEntityRef(template), + ); + return template.metadata.annotations?.['backstage.io/techdocs-ref'] && + viewTechDocsLink + ? [ + { + icon: app.getSystemIcon('docs') ?? DocsIcon, + text: 'View TechDocs', + url: viewTechDocsLink({ kind, namespace, name }), + }, + ] + : []; + }, + [app, viewTechDocsLink], + ); + + const onTemplateSelected = useCallback( + (template: TemplateEntityV1beta3) => { + const { namespace, name } = parseEntityRef(stringifyEntityRef(template)); + + navigate(templateRoute({ namespace, templateName: name })); + }, + [navigate, templateRoute], + ); + return ( @@ -82,7 +157,7 @@ export const TemplateListPage = (props: TemplateListPageProps) => { title="Create a new component" subtitle="Create new software components using standard templates in your organization" > - +
@@ -105,13 +180,16 @@ export const TemplateListPage = (props: TemplateListPageProps) => { initialFilter="all" availableFilters={['all', 'starred']} /> - + diff --git a/plugins/scaffolder/src/next/TemplateListPage/index.ts b/plugins/scaffolder/src/next/TemplateListPage/index.ts index 0436cfeeeb..c404a9352a 100644 --- a/plugins/scaffolder/src/next/TemplateListPage/index.ts +++ b/plugins/scaffolder/src/next/TemplateListPage/index.ts @@ -14,4 +14,4 @@ * limitations under the License. */ export { TemplateListPage } from './TemplateListPage'; -export type { TemplateGroupFilter } from './TemplateGroups'; +export type { TemplateListPageProps } from './TemplateListPage'; diff --git a/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.test.tsx b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.test.tsx index c4f9c75ceb..26a9dd946c 100644 --- a/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.test.tsx +++ b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.test.tsx @@ -29,7 +29,6 @@ import { } from '@backstage/plugin-scaffolder-react'; import { TemplateWizardPage } from './TemplateWizardPage'; import { rootRouteRef } from '../../routes'; -import { nextRouteRef } from '../routes'; jest.mock('react-router-dom', () => { return { @@ -41,6 +40,7 @@ jest.mock('react-router-dom', () => { }); const scaffolderApiMock: jest.Mocked = { + cancelTask: jest.fn(), scaffold: jest.fn(), getTemplateParameterSchema: jest.fn(), getIntegrationsList: jest.fn(), @@ -83,8 +83,7 @@ describe('TemplateWizardPage', () => { , { mountedRoutes: { - '/create': nextRouteRef, - '/create-legacy': rootRouteRef, + '/create': rootRouteRef, }, }, ); diff --git a/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx index 4825715fcb..a7133ae8c7 100644 --- a/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx +++ b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx @@ -34,12 +34,16 @@ import { } from '@backstage/plugin-scaffolder-react/alpha'; import { JsonValue } from '@backstage/types'; import { Header, Page } from '@backstage/core-components'; -import { - nextRouteRef, - nextScaffolderTaskRouteRef, - nextSelectedTemplateRouteRef, -} from '../routes'; +import { + rootRouteRef, + scaffolderTaskRouteRef, + selectedTemplateRouteRef, +} from '../../routes'; + +/** + * @alpha + */ export type TemplateWizardPageProps = { customFieldExtensions: NextFieldExtensionOptions[]; layouts?: LayoutOptions[]; @@ -47,13 +51,13 @@ export type TemplateWizardPageProps = { }; export const TemplateWizardPage = (props: TemplateWizardPageProps) => { - const rootRef = useRouteRef(nextRouteRef); - const taskRoute = useRouteRef(nextScaffolderTaskRouteRef); + const rootRef = useRouteRef(rootRouteRef); + const taskRoute = useRouteRef(scaffolderTaskRouteRef); const { secrets } = useTemplateSecrets(); const scaffolderApi = useApi(scaffolderApiRef); const navigate = useNavigate(); const { templateName, namespace } = useRouteRefParams( - nextSelectedTemplateRouteRef, + selectedTemplateRouteRef, ); const templateRef = stringifyEntityRef({ diff --git a/plugins/scaffolder/src/next/TemplateWizardPage/index.ts b/plugins/scaffolder/src/next/TemplateWizardPage/index.ts index 146a7a9afc..991b754ec9 100644 --- a/plugins/scaffolder/src/next/TemplateWizardPage/index.ts +++ b/plugins/scaffolder/src/next/TemplateWizardPage/index.ts @@ -14,3 +14,4 @@ * limitations under the License. */ export { TemplateWizardPage } from './TemplateWizardPage'; +export type { TemplateWizardPageProps } from './TemplateWizardPage'; diff --git a/plugins/scaffolder/src/next/index.ts b/plugins/scaffolder/src/next/index.ts index 1ca9096459..6cef3eaa03 100644 --- a/plugins/scaffolder/src/next/index.ts +++ b/plugins/scaffolder/src/next/index.ts @@ -17,4 +17,3 @@ export * from './Router'; export * from './TemplateListPage'; export * from './TemplateWizardPage'; export * from './types'; -export * from './routes'; diff --git a/plugins/scaffolder/src/next/routes.ts b/plugins/scaffolder/src/next/routes.ts deleted file mode 100644 index 12fad4210a..0000000000 --- a/plugins/scaffolder/src/next/routes.ts +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2022 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { createRouteRef, createSubRouteRef } from '@backstage/core-plugin-api'; - -/** @alpha */ -export const nextRouteRef = createRouteRef({ - id: 'scaffolder/next', -}); - -/** @alpha */ -export const nextSelectedTemplateRouteRef = createSubRouteRef({ - id: 'scaffolder/next/selected-template', - parent: nextRouteRef, - path: '/templates/:namespace/:templateName', -}); - -/** @alpha */ -export const nextScaffolderTaskRouteRef = createSubRouteRef({ - id: 'scaffolder/next/task', - parent: nextRouteRef, - path: '/tasks/:taskId', -}); - -/** @alpha */ -export const nextScaffolderListTaskRouteRef = createSubRouteRef({ - id: 'scaffolder/next/list-tasks', - parent: nextRouteRef, - path: '/tasks', -}); - -/** @alpha */ -export const nextActionsRouteRef = createSubRouteRef({ - id: 'scaffolder/next/actions', - parent: nextRouteRef, - path: '/actions', -}); - -/** @alpha */ -export const nextEditRouteRef = createSubRouteRef({ - id: 'scaffolder/next/edit', - parent: nextRouteRef, - path: '/edit', -}); diff --git a/plugins/scaffolder/src/plugin.tsx b/plugins/scaffolder/src/plugin.tsx index f6801c6371..dfe87a3780 100644 --- a/plugins/scaffolder/src/plugin.tsx +++ b/plugins/scaffolder/src/plugin.tsx @@ -60,8 +60,10 @@ import { viewTechDocRouteRef, selectedTemplateRouteRef, scaffolderTaskRouteRef, + scaffolderListTaskRouteRef, + actionsRouteRef, + editRouteRef, } from './routes'; -import { nextRouteRef } from './next'; /** * The main plugin export for the scaffolder. @@ -91,6 +93,9 @@ export const scaffolderPlugin = createPlugin({ root: rootRouteRef, selectedTemplate: selectedTemplateRouteRef, ongoingTask: scaffolderTaskRouteRef, + actions: actionsRouteRef, + listTasks: scaffolderListTaskRouteRef, + edit: editRouteRef, }, externalRoutes: { registerComponent: registerComponentRouteRef, @@ -199,6 +204,6 @@ export const NextScaffolderPage = scaffolderPlugin.provide( createRoutableExtension({ name: 'NextScaffolderPage', component: () => import('./next/Router').then(m => m.Router), - mountPoint: nextRouteRef, + mountPoint: rootRouteRef, }), ); diff --git a/plugins/search-backend-module-catalog/.eslintrc.js b/plugins/search-backend-module-catalog/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/search-backend-module-catalog/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/search-backend-module-catalog/README.md b/plugins/search-backend-module-catalog/README.md new file mode 100644 index 0000000000..b5960e2789 --- /dev/null +++ b/plugins/search-backend-module-catalog/README.md @@ -0,0 +1,41 @@ +# search-backend-module-catalog + +> DISCLAIMER: The new backend system is in alpha, and so are the search backend module support for the new backend system. We don't recommend you to migrate your backend installations to the new system yet. But if you want to experiment, you can find getting started guides below. + +This package exports catalog backend modules responsible for extending search. + +## Example + +### Use default schedule + +```tsx +// packages/backend-next/src/index.ts +import { createBackend } from '@backstage/backend-defaults'; +import { searchPlugin } from '@backstage/plugin-search-backend/alpha'; +import { searchModuleCatalogCollator } from '@backstage/plugin-search-backend-module-catalog/alpha'; + +const backend = createBackend(); +backend.add(searchPlugin()); +backend.add(searchModuleCatalogCollator()); +backend.start(); +``` + +### Use custom schedule + +```tsx +// packages/backend-next/src/index.ts +import { createBackend } from '@backstage/backend-defaults'; +import { searchPlugin } from '@backstage/plugin-search-backend/alpha'; +import { searchModuleCatalogCollator } from '@backstage/plugin-search-backend-module-catalog/alpha'; + +const schedule = { + frequency: { minutes: 10 }, + timeout: { minutes: 15 }, + initialDelay: { seconds: 3 }, +}; + +const backend = createBackend(); +backend.add(searchPlugin()); +backend.add(searchModuleCatalogCollator({ schedule })); +backend.start(); +``` diff --git a/plugins/search-backend-module-catalog/alpha-api-report.md b/plugins/search-backend-module-catalog/alpha-api-report.md new file mode 100644 index 0000000000..70fae9ef93 --- /dev/null +++ b/plugins/search-backend-module-catalog/alpha-api-report.md @@ -0,0 +1,24 @@ +## API Report File for "@backstage/plugin-search-backend-module-catalog" + +> 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 { DefaultCatalogCollatorFactoryOptions } from '@backstage/plugin-search-backend-module-catalog'; +import { TaskScheduleDefinition } from '@backstage/backend-tasks'; + +// @alpha +export const searchModuleCatalogCollator: ( + options?: SearchModuleCatalogCollatorOptions | undefined, +) => BackendFeature; + +// @alpha +export type SearchModuleCatalogCollatorOptions = Omit< + DefaultCatalogCollatorFactoryOptions, + 'discovery' | 'tokenManager' +> & { + schedule?: TaskScheduleDefinition; +}; + +// (No @packageDocumentation comment for this package) +``` diff --git a/plugins/search-backend-module-catalog/api-report.md b/plugins/search-backend-module-catalog/api-report.md new file mode 100644 index 0000000000..b773860fe8 --- /dev/null +++ b/plugins/search-backend-module-catalog/api-report.md @@ -0,0 +1,52 @@ +## API Report File for "@backstage/plugin-search-backend-module-catalog" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +/// + +import { CatalogApi } from '@backstage/catalog-client'; +import { CatalogEntityDocument } from '@backstage/plugin-catalog-common'; +import { Config } from '@backstage/config'; +import { DocumentCollatorFactory } from '@backstage/plugin-search-common'; +import { Entity } from '@backstage/catalog-model'; +import { GetEntitiesRequest } from '@backstage/catalog-client'; +import { Permission } from '@backstage/plugin-permission-common'; +import { PluginEndpointDiscovery } from '@backstage/backend-common'; +import { Readable } from 'stream'; +import { TokenManager } from '@backstage/backend-common'; + +// @public (undocumented) +export type CatalogCollatorEntityTransformer = ( + entity: Entity, +) => Omit; + +// @public (undocumented) +export const defaultCatalogCollatorEntityTransformer: CatalogCollatorEntityTransformer; + +// @public (undocumented) +export class DefaultCatalogCollatorFactory implements DocumentCollatorFactory { + // (undocumented) + static fromConfig( + _config: Config, + options: DefaultCatalogCollatorFactoryOptions, + ): DefaultCatalogCollatorFactory; + // (undocumented) + getCollator(): Promise; + // (undocumented) + readonly type = 'software-catalog'; + // (undocumented) + readonly visibilityPermission: Permission; +} + +// @public (undocumented) +export type DefaultCatalogCollatorFactoryOptions = { + discovery: PluginEndpointDiscovery; + tokenManager: TokenManager; + locationTemplate?: string; + filter?: GetEntitiesRequest['filter']; + batchSize?: number; + catalogClient?: CatalogApi; + entityTransformer?: CatalogCollatorEntityTransformer; +}; +``` diff --git a/plugins/search-backend-module-catalog/package.json b/plugins/search-backend-module-catalog/package.json new file mode 100644 index 0000000000..4c323ae7fd --- /dev/null +++ b/plugins/search-backend-module-catalog/package.json @@ -0,0 +1,59 @@ +{ + "name": "@backstage/plugin-search-backend-module-catalog", + "description": "A module for the search backend that exports catalog modules", + "version": "0.0.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public" + }, + "exports": { + ".": "./src/index.ts", + "./alpha": "./src/alpha.ts", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "alpha": [ + "src/alpha.ts" + ], + "package.json": [ + "package.json" + ] + } + }, + "backstage": { + "role": "backend-plugin-module" + }, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" + }, + "dependencies": { + "@backstage/backend-common": "workspace:^", + "@backstage/backend-plugin-api": "workspace:^", + "@backstage/backend-tasks": "workspace:^", + "@backstage/catalog-client": "workspace:^", + "@backstage/catalog-model": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/plugin-catalog-common": "workspace:^", + "@backstage/plugin-permission-common": "workspace:^", + "@backstage/plugin-search-backend-node": "workspace:^", + "@backstage/plugin-search-common": "workspace:^" + }, + "devDependencies": { + "@backstage/backend-common": "workspace:^", + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", + "msw": "^1.0.0" + }, + "files": [ + "dist" + ] +} diff --git a/plugins/search-backend-module-catalog/src/alpha.test.ts b/plugins/search-backend-module-catalog/src/alpha.test.ts new file mode 100644 index 0000000000..8a3082c6aa --- /dev/null +++ b/plugins/search-backend-module-catalog/src/alpha.test.ts @@ -0,0 +1,46 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { startTestBackend } from '@backstage/backend-test-utils'; +import { searchIndexRegistryExtensionPoint } from '@backstage/plugin-search-backend-node/alpha'; +import { searchModuleCatalogCollator } from './alpha'; + +describe('searchModuleCatalogCollator', () => { + const schedule = { + frequency: { minutes: 10 }, + timeout: { minutes: 15 }, + initialDelay: { seconds: 3 }, + }; + + it('should register the catalog collator to the search index registry extension point with factory and schedule', async () => { + const extensionPointMock = { + addCollator: jest.fn(), + }; + + await startTestBackend({ + extensionPoints: [ + [searchIndexRegistryExtensionPoint, extensionPointMock], + ], + features: [searchModuleCatalogCollator({ schedule })], + }); + + expect(extensionPointMock.addCollator).toHaveBeenCalledTimes(1); + expect(extensionPointMock.addCollator).toHaveBeenCalledWith({ + factory: expect.objectContaining({ type: 'software-catalog' }), + schedule: expect.objectContaining({ run: expect.any(Function) }), + }); + }); +}); diff --git a/plugins/search-backend-module-catalog/src/alpha.ts b/plugins/search-backend-module-catalog/src/alpha.ts new file mode 100644 index 0000000000..c633dc71b2 --- /dev/null +++ b/plugins/search-backend-module-catalog/src/alpha.ts @@ -0,0 +1,89 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @packageDocumentation + * A module for the search backend that exports Catalog modules. + */ + +import { + coreServices, + createBackendModule, +} from '@backstage/backend-plugin-api'; +import { TaskScheduleDefinition } from '@backstage/backend-tasks'; +import { searchIndexRegistryExtensionPoint } from '@backstage/plugin-search-backend-node/alpha'; + +import { + DefaultCatalogCollatorFactory, + DefaultCatalogCollatorFactoryOptions, +} from '@backstage/plugin-search-backend-module-catalog'; + +/** + * @alpha + * Options for {@link searchModuleCatalogCollator}. + */ +export type SearchModuleCatalogCollatorOptions = Omit< + DefaultCatalogCollatorFactoryOptions, + 'discovery' | 'tokenManager' +> & { + schedule?: TaskScheduleDefinition; +}; + +/** + * @alpha + * Search backend module for the Catalog index. + */ +export const searchModuleCatalogCollator = createBackendModule( + (options?: SearchModuleCatalogCollatorOptions) => ({ + moduleId: 'catalogCollator', + pluginId: 'search', + register(env) { + env.registerInit({ + deps: { + config: coreServices.config, + discovery: coreServices.discovery, + tokenManager: coreServices.tokenManager, + scheduler: coreServices.scheduler, + indexRegistry: searchIndexRegistryExtensionPoint, + }, + async init({ + config, + discovery, + tokenManager, + scheduler, + indexRegistry, + }) { + const defaultSchedule = { + frequency: { minutes: 10 }, + timeout: { minutes: 15 }, + initialDelay: { seconds: 3 }, + }; + + indexRegistry.addCollator({ + schedule: scheduler.createScheduledTaskRunner( + options?.schedule ?? defaultSchedule, + ), + factory: DefaultCatalogCollatorFactory.fromConfig(config, { + ...options, + discovery, + tokenManager, + }), + }); + }, + }); + }, + }), +); diff --git a/plugins/catalog-backend/src/search/CatalogCollatorEntityTransformer.ts b/plugins/search-backend-module-catalog/src/collators/CatalogCollatorEntityTransformer.ts similarity index 100% rename from plugins/catalog-backend/src/search/CatalogCollatorEntityTransformer.ts rename to plugins/search-backend-module-catalog/src/collators/CatalogCollatorEntityTransformer.ts diff --git a/plugins/catalog-backend/src/search/DefaultCatalogCollatorFactory.test.ts b/plugins/search-backend-module-catalog/src/collators/DefaultCatalogCollatorFactory.test.ts similarity index 100% rename from plugins/catalog-backend/src/search/DefaultCatalogCollatorFactory.test.ts rename to plugins/search-backend-module-catalog/src/collators/DefaultCatalogCollatorFactory.test.ts diff --git a/plugins/catalog-backend/src/search/DefaultCatalogCollatorFactory.ts b/plugins/search-backend-module-catalog/src/collators/DefaultCatalogCollatorFactory.ts similarity index 100% rename from plugins/catalog-backend/src/search/DefaultCatalogCollatorFactory.ts rename to plugins/search-backend-module-catalog/src/collators/DefaultCatalogCollatorFactory.ts diff --git a/plugins/catalog-backend/src/search/defaultCatalogCollatorEntityTransformer.test.ts b/plugins/search-backend-module-catalog/src/collators/defaultCatalogCollatorEntityTransformer.test.ts similarity index 100% rename from plugins/catalog-backend/src/search/defaultCatalogCollatorEntityTransformer.test.ts rename to plugins/search-backend-module-catalog/src/collators/defaultCatalogCollatorEntityTransformer.test.ts diff --git a/plugins/catalog-backend/src/search/defaultCatalogCollatorEntityTransformer.ts b/plugins/search-backend-module-catalog/src/collators/defaultCatalogCollatorEntityTransformer.ts similarity index 100% rename from plugins/catalog-backend/src/search/defaultCatalogCollatorEntityTransformer.ts rename to plugins/search-backend-module-catalog/src/collators/defaultCatalogCollatorEntityTransformer.ts diff --git a/plugins/search-backend-module-catalog/src/collators/index.ts b/plugins/search-backend-module-catalog/src/collators/index.ts new file mode 100644 index 0000000000..5876e71a02 --- /dev/null +++ b/plugins/search-backend-module-catalog/src/collators/index.ts @@ -0,0 +1,21 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { DefaultCatalogCollatorFactory } from './DefaultCatalogCollatorFactory'; +export type { DefaultCatalogCollatorFactoryOptions } from './DefaultCatalogCollatorFactory'; + +export { defaultCatalogCollatorEntityTransformer } from './defaultCatalogCollatorEntityTransformer'; +export type { CatalogCollatorEntityTransformer } from './CatalogCollatorEntityTransformer'; diff --git a/plugins/search-backend-module-catalog/src/index.ts b/plugins/search-backend-module-catalog/src/index.ts new file mode 100644 index 0000000000..7998562311 --- /dev/null +++ b/plugins/search-backend-module-catalog/src/index.ts @@ -0,0 +1,22 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @packageDocumentation + * A module for the search backend that exports Catalog modules. + */ + +export * from './collators'; diff --git a/plugins/search-backend-module-elasticsearch/CHANGELOG.md b/plugins/search-backend-module-elasticsearch/CHANGELOG.md index b72c36dec2..a7ef318ec1 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.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.0.7 + - @backstage/plugin-search-backend-node@1.1.5-next.0 + - @backstage/plugin-search-common@1.2.2 + ## 1.1.4 ### Patch Changes diff --git a/plugins/search-backend-module-elasticsearch/alpha-api-report.md b/plugins/search-backend-module-elasticsearch/alpha-api-report.md new file mode 100644 index 0000000000..91007c20de --- /dev/null +++ b/plugins/search-backend-module-elasticsearch/alpha-api-report.md @@ -0,0 +1,22 @@ +## API Report File for "@backstage/plugin-search-backend-module-elasticsearch" + +> 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 { ElasticSearchCustomIndexTemplate } from '@backstage/plugin-search-backend-module-elasticsearch'; +import { ElasticSearchQueryTranslator } from '@backstage/plugin-search-backend-module-elasticsearch'; + +// @alpha +export const searchModuleElasticsearchEngine: ( + options?: SearchModuleElasticsearchEngineOptions | undefined, +) => BackendFeature; + +// @alpha +export type SearchModuleElasticsearchEngineOptions = { + translator?: ElasticSearchQueryTranslator; + indexTemplate?: ElasticSearchCustomIndexTemplate; +}; + +// (No @packageDocumentation comment for this package) +``` diff --git a/plugins/search-backend-module-elasticsearch/package.json b/plugins/search-backend-module-elasticsearch/package.json index e854687360..285ab4e2fe 100644 --- a/plugins/search-backend-module-elasticsearch/package.json +++ b/plugins/search-backend-module-elasticsearch/package.json @@ -1,14 +1,27 @@ { "name": "@backstage/plugin-search-backend-module-elasticsearch", "description": "A module for the search backend that implements search using ElasticSearch", - "version": "1.1.4", + "version": "1.1.5-next.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" + "access": "public" + }, + "exports": { + ".": "./src/index.ts", + "./alpha": "./src/alpha.ts", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "alpha": [ + "src/alpha.ts" + ], + "package.json": [ + "package.json" + ] + } }, "backstage": { "role": "backend-plugin-module" @@ -23,6 +36,8 @@ "clean": "backstage-cli package clean" }, "dependencies": { + "@backstage/backend-common": "workspace:^", + "@backstage/backend-plugin-api": "workspace:^", "@backstage/config": "workspace:^", "@backstage/plugin-search-backend-node": "workspace:^", "@backstage/plugin-search-common": "workspace:^", diff --git a/plugins/search-backend-module-elasticsearch/src/alpha.ts b/plugins/search-backend-module-elasticsearch/src/alpha.ts new file mode 100644 index 0000000000..538124f004 --- /dev/null +++ b/plugins/search-backend-module-elasticsearch/src/alpha.ts @@ -0,0 +1,74 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { + coreServices, + createBackendModule, +} from '@backstage/backend-plugin-api'; +import { loggerToWinstonLogger } from '@backstage/backend-common'; +import { searchEngineRegistryExtensionPoint } from '@backstage/plugin-search-backend-node/alpha'; + +import { + ElasticSearchCustomIndexTemplate, + ElasticSearchQueryTranslator, + ElasticSearchSearchEngine, +} from '@backstage/plugin-search-backend-module-elasticsearch'; + +/** + * @alpha + * Options for {@link searchModuleElasticsearchEngine}. + */ +export type SearchModuleElasticsearchEngineOptions = { + translator?: ElasticSearchQueryTranslator; + indexTemplate?: ElasticSearchCustomIndexTemplate; +}; + +/** + * @alpha + * Search backend module for the Elasticsearch engine. + */ +export const searchModuleElasticsearchEngine = createBackendModule( + (options?: SearchModuleElasticsearchEngineOptions) => ({ + moduleId: 'elasticsearchEngine', + pluginId: 'search', + register(env) { + env.registerInit({ + deps: { + searchEngineRegistry: searchEngineRegistryExtensionPoint, + logger: coreServices.logger, + config: coreServices.config, + }, + async init({ searchEngineRegistry, logger, config }) { + const searchEngine = await ElasticSearchSearchEngine.fromConfig({ + logger: loggerToWinstonLogger(logger), + config: config, + }); + + // set custom translator if available + if (options?.translator) { + searchEngine.setTranslator(options.translator); + } + + // set custom index template if available + if (options?.indexTemplate) { + searchEngine.setIndexTemplate(options.indexTemplate); + } + + searchEngineRegistry.setSearchEngine(searchEngine); + }, + }); + }, + }), +); diff --git a/plugins/search-backend-module-explore/.eslintrc.js b/plugins/search-backend-module-explore/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/search-backend-module-explore/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/search-backend-module-explore/README.md b/plugins/search-backend-module-explore/README.md new file mode 100644 index 0000000000..a87f2d78f9 --- /dev/null +++ b/plugins/search-backend-module-explore/README.md @@ -0,0 +1,41 @@ +# search-backend-module-explore + +> DISCLAIMER: The new backend system is in alpha, and so are the search backend module support for the new backend system. We don't recommend you to migrate your backend installations to the new system yet. But if you want to experiment, you can find getting started guides below. + +This package exports explore backend modules responsible for extending search. + +## Example + +### Use default schedule + +```tsx +// packages/backend-next/src/index.ts +import { createBackend } from '@backstage/backend-defaults'; +import { searchPlugin } from '@backstage/plugin-search-backend/alpha'; +import { searchModuleExploreCollator } from '@backstage/plugin-search-backend-module-explore/alpha'; + +const backend = createBackend(); +backend.add(searchPlugin()); +backend.add(searchModuleExploreCollator()); +backend.start(); +``` + +### Use custom schedule + +```tsx +// packages/backend-next/src/index.ts +import { createBackend } from '@backstage/backend-defaults'; +import { searchPlugin } from '@backstage/plugin-search-backend/alpha'; +import { searchModuleExploreCollator } from '@backstage/plugin-search-backend-module-explore/alpha'; + +const schedule = { + frequency: { minutes: 10 }, + timeout: { minutes: 15 }, + initialDelay: { seconds: 3 }, +}; + +const backend = createBackend(); +backend.add(searchPlugin()); +backend.add(searchModuleExploreCollator({ schedule })); +backend.start(); +``` diff --git a/plugins/search-backend-module-explore/alpha-api-report.md b/plugins/search-backend-module-explore/alpha-api-report.md new file mode 100644 index 0000000000..cf32b59dd3 --- /dev/null +++ b/plugins/search-backend-module-explore/alpha-api-report.md @@ -0,0 +1,24 @@ +## API Report File for "@backstage/plugin-search-backend-module-explore" + +> 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 { TaskScheduleDefinition } from '@backstage/backend-tasks'; +import { ToolDocumentCollatorFactoryOptions } from '@backstage/plugin-search-backend-module-explore'; + +// @alpha +export const searchModuleExploreCollator: ( + options?: SearchModuleExploreCollatorOptions | undefined, +) => BackendFeature; + +// @alpha +export type SearchModuleExploreCollatorOptions = Omit< + ToolDocumentCollatorFactoryOptions, + 'logger' | 'discovery' +> & { + schedule?: TaskScheduleDefinition; +}; + +// (No @packageDocumentation comment for this package) +``` diff --git a/plugins/search-backend-module-explore/api-report.md b/plugins/search-backend-module-explore/api-report.md new file mode 100644 index 0000000000..80e8c0c06b --- /dev/null +++ b/plugins/search-backend-module-explore/api-report.md @@ -0,0 +1,39 @@ +## API Report File for "@backstage/plugin-search-backend-module-explore" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +/// + +import { Config } from '@backstage/config'; +import { DocumentCollatorFactory } from '@backstage/plugin-search-common'; +import { ExploreTool } from '@backstage/plugin-explore-common'; +import { IndexableDocument } from '@backstage/plugin-search-common'; +import { Logger } from 'winston'; +import { PluginEndpointDiscovery } from '@backstage/backend-common'; +import { Readable } from 'stream'; + +// @public +export interface ToolDocument extends IndexableDocument, ExploreTool {} + +// @public +export class ToolDocumentCollatorFactory implements DocumentCollatorFactory { + // (undocumented) + execute(): AsyncGenerator; + // (undocumented) + static fromConfig( + _config: Config, + options: ToolDocumentCollatorFactoryOptions, + ): ToolDocumentCollatorFactory; + // (undocumented) + getCollator(): Promise; + // (undocumented) + readonly type: string; +} + +// @public +export type ToolDocumentCollatorFactoryOptions = { + discovery: PluginEndpointDiscovery; + logger: Logger; +}; +``` diff --git a/plugins/search-backend-module-explore/package.json b/plugins/search-backend-module-explore/package.json new file mode 100644 index 0000000000..e4c71448ff --- /dev/null +++ b/plugins/search-backend-module-explore/package.json @@ -0,0 +1,56 @@ +{ + "name": "@backstage/plugin-search-backend-module-explore", + "description": "A module for the search backend that exports explore modules", + "version": "0.0.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public" + }, + "exports": { + ".": "./src/index.ts", + "./alpha": "./src/alpha.ts", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "alpha": [ + "src/alpha.ts" + ], + "package.json": [ + "package.json" + ] + } + }, + "backstage": { + "role": "backend-plugin-module" + }, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" + }, + "dependencies": { + "@backstage/backend-common": "workspace:^", + "@backstage/backend-plugin-api": "workspace:^", + "@backstage/backend-tasks": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/plugin-explore-common": "workspace:^", + "@backstage/plugin-search-backend-node": "workspace:^", + "@backstage/plugin-search-common": "workspace:^", + "node-fetch": "^2.6.7", + "winston": "^3.2.1" + }, + "devDependencies": { + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^" + }, + "files": [ + "dist" + ] +} diff --git a/plugins/search-backend-module-explore/src/alpha.test.ts b/plugins/search-backend-module-explore/src/alpha.test.ts new file mode 100644 index 0000000000..9b133f0fd5 --- /dev/null +++ b/plugins/search-backend-module-explore/src/alpha.test.ts @@ -0,0 +1,46 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { startTestBackend } from '@backstage/backend-test-utils'; +import { searchIndexRegistryExtensionPoint } from '@backstage/plugin-search-backend-node/alpha'; +import { searchModuleExploreCollator } from './alpha'; + +describe('searchModuleExploreCollator', () => { + const schedule = { + frequency: { minutes: 10 }, + timeout: { minutes: 15 }, + initialDelay: { seconds: 3 }, + }; + + it('should register the explore collator to the search index registry extension point with factory and schedule', async () => { + const extensionPointMock = { + addCollator: jest.fn(), + }; + + await startTestBackend({ + extensionPoints: [ + [searchIndexRegistryExtensionPoint, extensionPointMock], + ], + features: [searchModuleExploreCollator({ schedule })], + }); + + expect(extensionPointMock.addCollator).toHaveBeenCalledTimes(1); + expect(extensionPointMock.addCollator).toHaveBeenCalledWith({ + factory: expect.objectContaining({ type: 'tools' }), + schedule: expect.objectContaining({ run: expect.any(Function) }), + }); + }); +}); diff --git a/plugins/search-backend-module-explore/src/alpha.ts b/plugins/search-backend-module-explore/src/alpha.ts new file mode 100644 index 0000000000..f13c3c2406 --- /dev/null +++ b/plugins/search-backend-module-explore/src/alpha.ts @@ -0,0 +1,84 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @packageDocumentation + * A module for the search backend that exports Explore modules. + */ + +import { + coreServices, + createBackendModule, +} from '@backstage/backend-plugin-api'; +import { TaskScheduleDefinition } from '@backstage/backend-tasks'; +import { loggerToWinstonLogger } from '@backstage/backend-common'; +import { searchIndexRegistryExtensionPoint } from '@backstage/plugin-search-backend-node/alpha'; + +import { + ToolDocumentCollatorFactory, + ToolDocumentCollatorFactoryOptions, +} from '@backstage/plugin-search-backend-module-explore'; + +/** + * @alpha + * Options for {@link searchModuleExploreCollator}. + */ +export type SearchModuleExploreCollatorOptions = Omit< + ToolDocumentCollatorFactoryOptions, + 'logger' | 'discovery' +> & { + schedule?: TaskScheduleDefinition; +}; + +/** + * @alpha + * Search backend module for the Explore index. + */ +export const searchModuleExploreCollator = createBackendModule( + (options?: SearchModuleExploreCollatorOptions) => ({ + moduleId: 'exploreCollator', + pluginId: 'search', + register(env) { + env.registerInit({ + deps: { + config: coreServices.config, + logger: coreServices.logger, + discovery: coreServices.discovery, + scheduler: coreServices.scheduler, + indexRegistry: searchIndexRegistryExtensionPoint, + }, + async init({ config, logger, discovery, scheduler, indexRegistry }) { + const defaultSchedule = { + frequency: { minutes: 10 }, + timeout: { minutes: 15 }, + initialDelay: { seconds: 3 }, + }; + + indexRegistry.addCollator({ + schedule: scheduler.createScheduledTaskRunner( + options?.schedule ?? defaultSchedule, + ), + factory: ToolDocumentCollatorFactory.fromConfig(config, { + ...options, + discovery, + logger: loggerToWinstonLogger(logger), + }), + }); + }, + }); + }, + }), +); diff --git a/plugins/explore-backend/src/search/ToolDocumentCollatorFactory.ts b/plugins/search-backend-module-explore/src/collators/ToolDocumentCollatorFactory.ts similarity index 100% rename from plugins/explore-backend/src/search/ToolDocumentCollatorFactory.ts rename to plugins/search-backend-module-explore/src/collators/ToolDocumentCollatorFactory.ts diff --git a/plugins/explore-backend/src/search/index.ts b/plugins/search-backend-module-explore/src/collators/index.ts similarity index 99% rename from plugins/explore-backend/src/search/index.ts rename to plugins/search-backend-module-explore/src/collators/index.ts index 70e9414652..45f0c933e2 100644 --- a/plugins/explore-backend/src/search/index.ts +++ b/plugins/search-backend-module-explore/src/collators/index.ts @@ -15,6 +15,7 @@ */ export { ToolDocumentCollatorFactory } from './ToolDocumentCollatorFactory'; + export type { ToolDocument, ToolDocumentCollatorFactoryOptions, diff --git a/plugins/search-backend-module-explore/src/index.ts b/plugins/search-backend-module-explore/src/index.ts new file mode 100644 index 0000000000..ea94071984 --- /dev/null +++ b/plugins/search-backend-module-explore/src/index.ts @@ -0,0 +1,22 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @packageDocumentation + * A module for the search backend that exports Explore modules. + */ + +export * from './collators'; diff --git a/plugins/search-backend-module-pg/CHANGELOG.md b/plugins/search-backend-module-pg/CHANGELOG.md index 50a9fc9d91..8f3f01e83c 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.5.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/plugin-search-backend-node@1.1.5-next.0 + - @backstage/plugin-search-common@1.2.2 + ## 0.5.4 ### Patch Changes diff --git a/plugins/search-backend-module-pg/alpha-api-report.md b/plugins/search-backend-module-pg/alpha-api-report.md new file mode 100644 index 0000000000..eaee78e944 --- /dev/null +++ b/plugins/search-backend-module-pg/alpha-api-report.md @@ -0,0 +1,12 @@ +## API Report File for "@backstage/plugin-search-backend-module-pg" + +> 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'; + +// @alpha +export const searchModulePostgresEngine: () => BackendFeature; + +// (No @packageDocumentation comment for this package) +``` diff --git a/plugins/search-backend-module-pg/package.json b/plugins/search-backend-module-pg/package.json index b284557369..28432f2025 100644 --- a/plugins/search-backend-module-pg/package.json +++ b/plugins/search-backend-module-pg/package.json @@ -1,14 +1,27 @@ { "name": "@backstage/plugin-search-backend-module-pg", "description": "A module for the search backend that implements search using PostgreSQL", - "version": "0.5.4", + "version": "0.5.5-next.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" + "access": "public" + }, + "exports": { + ".": "./src/index.ts", + "./alpha": "./src/alpha.ts", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "alpha": [ + "src/alpha.ts" + ], + "package.json": [ + "package.json" + ] + } }, "backstage": { "role": "backend-plugin-module" @@ -24,6 +37,7 @@ }, "dependencies": { "@backstage/backend-common": "workspace:^", + "@backstage/backend-plugin-api": "workspace:^", "@backstage/config": "workspace:^", "@backstage/plugin-search-backend-node": "workspace:^", "@backstage/plugin-search-common": "workspace:^", diff --git a/plugins/search-backend-module-pg/src/alpha.ts b/plugins/search-backend-module-pg/src/alpha.ts new file mode 100644 index 0000000000..e3e0087957 --- /dev/null +++ b/plugins/search-backend-module-pg/src/alpha.ts @@ -0,0 +1,46 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { + coreServices, + createBackendModule, +} from '@backstage/backend-plugin-api'; +import { searchEngineRegistryExtensionPoint } from '@backstage/plugin-search-backend-node/alpha'; +import { PgSearchEngine } from './PgSearchEngine'; + +/** + * @alpha + * Search backend module for the Postgres engine. + */ +export const searchModulePostgresEngine = createBackendModule({ + moduleId: 'postgresEngine', + pluginId: 'search', + register(env) { + env.registerInit({ + deps: { + searchEngineRegistry: searchEngineRegistryExtensionPoint, + database: coreServices.database, + config: coreServices.config, + }, + async init({ searchEngineRegistry, database, config }) { + searchEngineRegistry.setSearchEngine( + await PgSearchEngine.fromConfig(config, { + database: database, + }), + ); + }, + }); + }, +}); diff --git a/plugins/search-backend-module-techdocs/.eslintrc.js b/plugins/search-backend-module-techdocs/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/search-backend-module-techdocs/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/search-backend-module-techdocs/README.md b/plugins/search-backend-module-techdocs/README.md new file mode 100644 index 0000000000..5de310466b --- /dev/null +++ b/plugins/search-backend-module-techdocs/README.md @@ -0,0 +1,41 @@ +# search-backend-module-techdocs + +> DISCLAIMER: The new backend system is in alpha, and so are the search backend module support for the new backend system. We don't recommend you to migrate your backend installations to the new system yet. But if you want to experiment, you can find getting started guides below. + +This package exports techdocs backend modules responsible for extending search. + +## Example + +### Use default schedule + +```tsx +// packages/backend-next/src/index.ts +import { createBackend } from '@backstage/backend-defaults'; +import { searchPlugin } from '@backstage/plugin-search-backend/alpha'; +import { searchModuleTechDocsCollator } from '@backstage/plugin-search-backend-module-techdocs/alpha'; + +const backend = createBackend(); +backend.add(searchPlugin()); +backend.add(searchModuleTechDocsCollator()); +backend.start(); +``` + +### Use custom schedule + +```tsx +// packages/backend-next/src/index.ts +import { createBackend } from '@backstage/backend-defaults'; +import { searchPlugin } from '@backstage/plugin-search-backend/alpha'; +import { searchModuleTechDocsCollator } from '@backstage/plugin-search-backend-module-techdocs/alpha'; + +const schedule = { + frequency: { minutes: 10 }, + timeout: { minutes: 15 }, + initialDelay: { seconds: 3 }, +}; + +const backend = createBackend(); +backend.add(searchPlugin()); +backend.add(searchModuleTechDocsCollator({ schedule })); +backend.start(); +``` diff --git a/plugins/search-backend-module-techdocs/alpha-api-report.md b/plugins/search-backend-module-techdocs/alpha-api-report.md new file mode 100644 index 0000000000..71ce09b744 --- /dev/null +++ b/plugins/search-backend-module-techdocs/alpha-api-report.md @@ -0,0 +1,24 @@ +## API Report File for "@backstage/plugin-search-backend-module-techdocs" + +> 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 { TaskScheduleDefinition } from '@backstage/backend-tasks'; +import { TechDocsCollatorFactoryOptions } from '@backstage/plugin-search-backend-module-techdocs'; + +// @alpha +export const searchModuleTechDocsCollator: ( + options?: SearchModuleTechDocsCollatorOptions | undefined, +) => BackendFeature; + +// @alpha +export type SearchModuleTechDocsCollatorOptions = Omit< + TechDocsCollatorFactoryOptions, + 'logger' | 'discovery' | 'tokenManager' +> & { + schedule?: TaskScheduleDefinition; +}; + +// (No @packageDocumentation comment for this package) +``` diff --git a/plugins/search-backend-module-techdocs/api-report.md b/plugins/search-backend-module-techdocs/api-report.md new file mode 100644 index 0000000000..9f72b1c487 --- /dev/null +++ b/plugins/search-backend-module-techdocs/api-report.md @@ -0,0 +1,42 @@ +## API Report File for "@backstage/plugin-search-backend-module-techdocs" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +/// + +import { CatalogApi } from '@backstage/catalog-client'; +import { Config } from '@backstage/config'; +import { DocumentCollatorFactory } from '@backstage/plugin-search-common'; +import { Logger } from 'winston'; +import { Permission } from '@backstage/plugin-permission-common'; +import { PluginEndpointDiscovery } from '@backstage/backend-common'; +import { Readable } from 'stream'; +import { TokenManager } from '@backstage/backend-common'; + +// @public +export class DefaultTechDocsCollatorFactory implements DocumentCollatorFactory { + // (undocumented) + static fromConfig( + config: Config, + options: TechDocsCollatorFactoryOptions, + ): DefaultTechDocsCollatorFactory; + // (undocumented) + getCollator(): Promise; + // (undocumented) + readonly type: string; + // (undocumented) + readonly visibilityPermission: Permission; +} + +// @public +export type TechDocsCollatorFactoryOptions = { + discovery: PluginEndpointDiscovery; + logger: Logger; + tokenManager: TokenManager; + locationTemplate?: string; + catalogClient?: CatalogApi; + parallelismLimit?: number; + legacyPathCasing?: boolean; +}; +``` diff --git a/plugins/search-backend-module-techdocs/package.json b/plugins/search-backend-module-techdocs/package.json new file mode 100644 index 0000000000..d08193be29 --- /dev/null +++ b/plugins/search-backend-module-techdocs/package.json @@ -0,0 +1,63 @@ +{ + "name": "@backstage/plugin-search-backend-module-techdocs", + "description": "A module for the search backend that exports techdocs modules", + "version": "0.0.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public" + }, + "exports": { + ".": "./src/index.ts", + "./alpha": "./src/alpha.ts", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "alpha": [ + "src/alpha.ts" + ], + "package.json": [ + "package.json" + ] + } + }, + "backstage": { + "role": "backend-plugin-module" + }, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "clean": "backstage-cli package clean" + }, + "dependencies": { + "@backstage/backend-common": "workspace:^", + "@backstage/backend-plugin-api": "workspace:^", + "@backstage/backend-tasks": "workspace:^", + "@backstage/catalog-client": "workspace:^", + "@backstage/catalog-model": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/plugin-catalog-common": "workspace:^", + "@backstage/plugin-permission-common": "workspace:^", + "@backstage/plugin-search-backend-node": "workspace:^", + "@backstage/plugin-search-common": "workspace:^", + "@backstage/plugin-techdocs-node": "workspace:^", + "lodash": "^4.17.21", + "node-fetch": "^2.6.7", + "p-limit": "^3.1.0", + "winston": "^3.2.1" + }, + "devDependencies": { + "@backstage/backend-test-utils": "workspace:^", + "@backstage/cli": "workspace:^", + "msw": "^1.0.0" + }, + "files": [ + "dist" + ] +} diff --git a/plugins/search-backend-module-techdocs/src/alpha.test.ts b/plugins/search-backend-module-techdocs/src/alpha.test.ts new file mode 100644 index 0000000000..011b00b12c --- /dev/null +++ b/plugins/search-backend-module-techdocs/src/alpha.test.ts @@ -0,0 +1,46 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { startTestBackend } from '@backstage/backend-test-utils'; +import { searchIndexRegistryExtensionPoint } from '@backstage/plugin-search-backend-node/alpha'; +import { searchModuleTechDocsCollator } from './alpha'; + +describe('searchModuleTechDocsCollator', () => { + const schedule = { + frequency: { minutes: 10 }, + timeout: { minutes: 15 }, + initialDelay: { seconds: 3 }, + }; + + it('should register the techdocs collator to the search index registry extension point with factory and schedule', async () => { + const extensionPointMock = { + addCollator: jest.fn(), + }; + + await startTestBackend({ + extensionPoints: [ + [searchIndexRegistryExtensionPoint, extensionPointMock], + ], + features: [searchModuleTechDocsCollator({ schedule })], + }); + + expect(extensionPointMock.addCollator).toHaveBeenCalledTimes(1); + expect(extensionPointMock.addCollator).toHaveBeenCalledWith({ + factory: expect.objectContaining({ type: 'techdocs' }), + schedule: expect.objectContaining({ run: expect.any(Function) }), + }); + }); +}); diff --git a/plugins/search-backend-module-techdocs/src/alpha.ts b/plugins/search-backend-module-techdocs/src/alpha.ts new file mode 100644 index 0000000000..1432cc88fb --- /dev/null +++ b/plugins/search-backend-module-techdocs/src/alpha.ts @@ -0,0 +1,93 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @packageDocumentation + * A module for the search backend that exports TechDocs modules. + */ + +import { + coreServices, + createBackendModule, +} from '@backstage/backend-plugin-api'; +import { TaskScheduleDefinition } from '@backstage/backend-tasks'; +import { loggerToWinstonLogger } from '@backstage/backend-common'; +import { searchIndexRegistryExtensionPoint } from '@backstage/plugin-search-backend-node/alpha'; + +import { + DefaultTechDocsCollatorFactory, + TechDocsCollatorFactoryOptions, +} from '@backstage/plugin-search-backend-module-techdocs'; + +/** + * @alpha + * Options for {@link searchModuleTechDocsCollator}. + */ +export type SearchModuleTechDocsCollatorOptions = Omit< + TechDocsCollatorFactoryOptions, + 'logger' | 'discovery' | 'tokenManager' +> & { + schedule?: TaskScheduleDefinition; +}; + +/** + * @alpha + * Search backend module for the TechDocs index. + */ +export const searchModuleTechDocsCollator = createBackendModule( + (options?: SearchModuleTechDocsCollatorOptions) => ({ + moduleId: 'techDocsCollator', + pluginId: 'search', + register(env) { + env.registerInit({ + deps: { + config: coreServices.config, + logger: coreServices.logger, + discovery: coreServices.discovery, + tokenManager: coreServices.tokenManager, + scheduler: coreServices.scheduler, + indexRegistry: searchIndexRegistryExtensionPoint, + }, + async init({ + config, + logger, + discovery, + tokenManager, + scheduler, + indexRegistry, + }) { + const defaultSchedule = { + frequency: { minutes: 10 }, + timeout: { minutes: 15 }, + initialDelay: { seconds: 3 }, + }; + + indexRegistry.addCollator({ + schedule: scheduler.createScheduledTaskRunner( + options?.schedule ?? defaultSchedule, + ), + factory: DefaultTechDocsCollatorFactory.fromConfig(config, { + ...options, + discovery, + tokenManager, + logger: loggerToWinstonLogger(logger), + }), + }); + }, + }); + }, + }), +); diff --git a/plugins/techdocs-backend/src/search/DefaultTechDocsCollatorFactory.test.ts b/plugins/search-backend-module-techdocs/src/collators/DefaultTechDocsCollatorFactory.test.ts similarity index 100% rename from plugins/techdocs-backend/src/search/DefaultTechDocsCollatorFactory.test.ts rename to plugins/search-backend-module-techdocs/src/collators/DefaultTechDocsCollatorFactory.test.ts diff --git a/plugins/techdocs-backend/src/search/DefaultTechDocsCollatorFactory.ts b/plugins/search-backend-module-techdocs/src/collators/DefaultTechDocsCollatorFactory.ts similarity index 100% rename from plugins/techdocs-backend/src/search/DefaultTechDocsCollatorFactory.ts rename to plugins/search-backend-module-techdocs/src/collators/DefaultTechDocsCollatorFactory.ts diff --git a/plugins/search-backend-module-techdocs/src/collators/index.ts b/plugins/search-backend-module-techdocs/src/collators/index.ts new file mode 100644 index 0000000000..8c5fd122f1 --- /dev/null +++ b/plugins/search-backend-module-techdocs/src/collators/index.ts @@ -0,0 +1,19 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { DefaultTechDocsCollatorFactory } from './DefaultTechDocsCollatorFactory'; + +export type { TechDocsCollatorFactoryOptions } from './DefaultTechDocsCollatorFactory'; diff --git a/plugins/search-backend-module-techdocs/src/index.ts b/plugins/search-backend-module-techdocs/src/index.ts new file mode 100644 index 0000000000..c28175fd61 --- /dev/null +++ b/plugins/search-backend-module-techdocs/src/index.ts @@ -0,0 +1,22 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @packageDocumentation + * A module for the search backend that exports TechDocs modules. + */ + +export * from './collators'; diff --git a/plugins/search-backend-node/CHANGELOG.md b/plugins/search-backend-node/CHANGELOG.md index 69cc5ac718..ed51a90369 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.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/errors@1.1.5 + - @backstage/plugin-permission-common@0.7.4 + - @backstage/plugin-search-common@1.2.2 + ## 1.1.4 ### Patch Changes diff --git a/plugins/search-backend-node/alpha-api-report.md b/plugins/search-backend-node/alpha-api-report.md new file mode 100644 index 0000000000..74b7a4b4bc --- /dev/null +++ b/plugins/search-backend-node/alpha-api-report.md @@ -0,0 +1,50 @@ +## API Report File for "@backstage/plugin-search-backend-node" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { DocumentTypeInfo } from '@backstage/plugin-search-common'; +import { ExtensionPoint } from '@backstage/backend-plugin-api'; +import { RegisterCollatorParameters } from '@backstage/plugin-search-backend-node'; +import { RegisterDecoratorParameters } from '@backstage/plugin-search-backend-node'; +import { SearchEngine } from '@backstage/plugin-search-common'; +import { ServiceRef } from '@backstage/backend-plugin-api'; + +// @alpha +export interface SearchEngineRegistryExtensionPoint { + // (undocumented) + setSearchEngine(searchEngine: SearchEngine): void; +} + +// @alpha +export const searchEngineRegistryExtensionPoint: ExtensionPoint; + +// @alpha +export interface SearchIndexRegistryExtensionPoint { + // (undocumented) + addCollator(options: RegisterCollatorParameters): void; + // (undocumented) + addDecorator(options: RegisterDecoratorParameters): void; +} + +// @alpha +export const searchIndexRegistryExtensionPoint: ExtensionPoint; + +// @alpha +export interface SearchIndexService { + getDocumentTypes(): Record; + start(options: SearchIndexServiceStartOptions): Promise; +} + +// @alpha +export const searchIndexServiceRef: ServiceRef; + +// @alpha +export type SearchIndexServiceStartOptions = { + searchEngine: SearchEngine; + collators: RegisterCollatorParameters[]; + decorators: RegisterDecoratorParameters[]; +}; + +// (No @packageDocumentation comment for this package) +``` diff --git a/plugins/search-backend-node/package.json b/plugins/search-backend-node/package.json index 2abc0a8ef0..a49b6088ab 100644 --- a/plugins/search-backend-node/package.json +++ b/plugins/search-backend-node/package.json @@ -1,14 +1,27 @@ { "name": "@backstage/plugin-search-backend-node", "description": "A library for Backstage backend plugins that want to interact with the search backend plugin", - "version": "1.1.4", + "version": "1.1.5-next.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" + "access": "public" + }, + "exports": { + ".": "./src/index.ts", + "./alpha": "./src/alpha.ts", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "alpha": [ + "src/alpha.ts" + ], + "package.json": [ + "package.json" + ] + } }, "backstage": { "role": "node-library" @@ -24,6 +37,7 @@ }, "dependencies": { "@backstage/backend-common": "workspace:^", + "@backstage/backend-plugin-api": "workspace:^", "@backstage/backend-tasks": "workspace:^", "@backstage/config": "workspace:^", "@backstage/errors": "workspace:^", diff --git a/plugins/search-backend-node/src/alpha.ts b/plugins/search-backend-node/src/alpha.ts new file mode 100644 index 0000000000..943e11b580 --- /dev/null +++ b/plugins/search-backend-node/src/alpha.ts @@ -0,0 +1,159 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Logger } from 'winston'; + +import { + createServiceRef, + createServiceFactory, + coreServices, +} from '@backstage/backend-plugin-api'; +import { loggerToWinstonLogger } from '@backstage/backend-common'; +import { + DocumentTypeInfo, + SearchEngine, +} from '@backstage/plugin-search-common'; +import { createExtensionPoint } from '@backstage/backend-plugin-api'; + +import { + RegisterCollatorParameters, + RegisterDecoratorParameters, +} from '@backstage/plugin-search-backend-node'; + +import { IndexBuilder } from './IndexBuilder'; + +/** + * @alpha + * Options for build method on {@link SearchIndexService}. + */ +export type SearchIndexServiceStartOptions = { + searchEngine: SearchEngine; + collators: RegisterCollatorParameters[]; + decorators: RegisterDecoratorParameters[]; +}; + +/** + * @alpha + * Interface for implementation of index service. + */ +export interface SearchIndexService { + /** + * Starts indexing process + */ + start(options: SearchIndexServiceStartOptions): Promise; + /** + * Returns an index types list. + */ + getDocumentTypes(): Record; +} + +/** + * @alpha + * Interface for search index registry extension point. + */ +export interface SearchIndexRegistryExtensionPoint { + addCollator(options: RegisterCollatorParameters): void; + addDecorator(options: RegisterDecoratorParameters): void; +} + +/** + * @alpha + * Interface for search engine registry extension point. + */ +export interface SearchEngineRegistryExtensionPoint { + setSearchEngine(searchEngine: SearchEngine): void; +} + +type DefaultSearchIndexServiceOptions = { + logger: Logger; +}; + +/** + * @alpha + * Reponsible for register the indexing task and start the schedule. + */ +class DefaultSearchIndexService implements SearchIndexService { + private logger: Logger; + private indexBuilder: IndexBuilder | null = null; + + private constructor(options: DefaultSearchIndexServiceOptions) { + this.logger = options.logger; + } + + static fromConfig(options: DefaultSearchIndexServiceOptions) { + return new DefaultSearchIndexService(options); + } + + async start(options: SearchIndexServiceStartOptions): Promise { + this.indexBuilder = new IndexBuilder({ + logger: this.logger, + searchEngine: options.searchEngine, + }); + + options.collators.forEach(collator => + this.indexBuilder?.addCollator(collator), + ); + + options.decorators.forEach(decorator => + this.indexBuilder?.addDecorator(decorator), + ); + + const { scheduler } = await this.indexBuilder?.build(); + scheduler.start(); + } + + getDocumentTypes(): Record { + return this.indexBuilder?.getDocumentTypes() ?? {}; + } +} + +/** + * @alpha + * Service that builds a search index. + */ +export const searchIndexServiceRef = createServiceRef({ + id: 'search.index.service', + defaultFactory: async service => + createServiceFactory({ + service, + deps: { + logger: coreServices.logger, + }, + factory({ logger }) { + return DefaultSearchIndexService.fromConfig({ + logger: loggerToWinstonLogger(logger), + }); + }, + }), +}); + +/** + * @alpha + * Extension point for register a search engine. + */ +export const searchEngineRegistryExtensionPoint = + createExtensionPoint({ + id: 'search.engine.registry', + }); + +/** + * @alpha + * Extension point for registering collators and decorators + */ +export const searchIndexRegistryExtensionPoint = + createExtensionPoint({ + id: 'search.index.registry', + }); diff --git a/plugins/search-backend/CHANGELOG.md b/plugins/search-backend/CHANGELOG.md index 72d9e53c08..d6985a70f1 100644 --- a/plugins/search-backend/CHANGELOG.md +++ b/plugins/search-backend/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-search-backend +## 1.2.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/errors@1.1.5 + - @backstage/types@1.0.2 + - @backstage/plugin-auth-node@0.2.13-next.0 + - @backstage/plugin-permission-common@0.7.4 + - @backstage/plugin-permission-node@0.7.7-next.0 + - @backstage/plugin-search-backend-node@1.1.5-next.0 + - @backstage/plugin-search-common@1.2.2 + ## 1.2.4 ### Patch Changes diff --git a/plugins/search-backend/alpha-api-report.md b/plugins/search-backend/alpha-api-report.md new file mode 100644 index 0000000000..6ee94a0e29 --- /dev/null +++ b/plugins/search-backend/alpha-api-report.md @@ -0,0 +1,12 @@ +## API Report File for "@backstage/plugin-search-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'; + +// @alpha +export const searchPlugin: () => BackendFeature; + +// (No @packageDocumentation comment for this package) +``` diff --git a/plugins/search-backend/package.json b/plugins/search-backend/package.json index 02d4d53a92..3091e0e8b4 100644 --- a/plugins/search-backend/package.json +++ b/plugins/search-backend/package.json @@ -1,14 +1,27 @@ { "name": "@backstage/plugin-search-backend", "description": "The Backstage backend plugin that provides your backstage app with search", - "version": "1.2.4", + "version": "1.2.5-next.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" + "access": "public" + }, + "exports": { + ".": "./src/index.ts", + "./alpha": "./src/alpha.ts", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "alpha": [ + "src/alpha.ts" + ], + "package.json": [ + "package.json" + ] + } }, "backstage": { "role": "backend-plugin" @@ -24,6 +37,7 @@ }, "dependencies": { "@backstage/backend-common": "workspace:^", + "@backstage/backend-plugin-api": "workspace:^", "@backstage/config": "workspace:^", "@backstage/errors": "workspace:^", "@backstage/plugin-auth-node": "workspace:^", @@ -43,6 +57,7 @@ "zod": "~3.18.0" }, "devDependencies": { + "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "@types/supertest": "^2.0.8", "supertest": "^6.1.3" diff --git a/plugins/search-backend/src/alpha.test.ts b/plugins/search-backend/src/alpha.test.ts new file mode 100644 index 0000000000..527f099236 --- /dev/null +++ b/plugins/search-backend/src/alpha.test.ts @@ -0,0 +1,31 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { startTestBackend } from '@backstage/backend-test-utils'; +import request from 'supertest'; +import { searchPlugin } from './alpha'; + +describe('searchPlugin', () => { + it('should serve search results on query endpoint', async () => { + const { server } = await startTestBackend({ + features: [searchPlugin()], + }); + + const response = await request(server).get('/api/search/query'); + expect(response.status).toBe(200); + expect(response.body).toEqual({ numberOfResults: 0, results: [] }); + }); +}); diff --git a/plugins/search-backend/src/alpha.ts b/plugins/search-backend/src/alpha.ts new file mode 100644 index 0000000000..0c14852875 --- /dev/null +++ b/plugins/search-backend/src/alpha.ts @@ -0,0 +1,130 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + coreServices, + createBackendPlugin, +} from '@backstage/backend-plugin-api'; +import { loggerToWinstonLogger } from '@backstage/backend-common'; +import { + RegisterCollatorParameters, + RegisterDecoratorParameters, + LunrSearchEngine, +} from '@backstage/plugin-search-backend-node'; +import { + searchIndexServiceRef, + searchIndexRegistryExtensionPoint, + SearchIndexRegistryExtensionPoint, + SearchEngineRegistryExtensionPoint, + searchEngineRegistryExtensionPoint, +} from '@backstage/plugin-search-backend-node/alpha'; + +import { createRouter } from './service/router'; +import { SearchEngine } from '@backstage/plugin-search-common'; + +class SearchIndexRegistry implements SearchIndexRegistryExtensionPoint { + private collators: RegisterCollatorParameters[] = []; + private decorators: RegisterDecoratorParameters[] = []; + + public addCollator(options: RegisterCollatorParameters): void { + this.collators.push(options); + } + + public addDecorator(options: RegisterDecoratorParameters): void { + this.decorators.push(options); + } + + public getCollators(): RegisterCollatorParameters[] { + return this.collators; + } + + public getDecorators(): RegisterDecoratorParameters[] { + return this.decorators; + } +} + +class SearchEngineRegistry implements SearchEngineRegistryExtensionPoint { + private searchEngine: SearchEngine | null = null; + + public setSearchEngine(searchEngine: SearchEngine): void { + if (this.searchEngine) { + throw new Error('Multiple Search engines is not supported at this time'); + } + this.searchEngine = searchEngine; + } + + public getSearchEngine(): SearchEngine | null { + return this.searchEngine; + } +} + +/** + * The Search plugin is responsible for starting search indexing processes and return search results. + * @alpha + */ +export const searchPlugin = createBackendPlugin({ + pluginId: 'search', + register(env) { + const searchIndexRegistry = new SearchIndexRegistry(); + env.registerExtensionPoint( + searchIndexRegistryExtensionPoint, + searchIndexRegistry, + ); + + const searchEngineRegistry = new SearchEngineRegistry(); + env.registerExtensionPoint( + searchEngineRegistryExtensionPoint, + searchEngineRegistry, + ); + + env.registerInit({ + deps: { + logger: coreServices.logger, + config: coreServices.config, + permissions: coreServices.permissions, + http: coreServices.httpRouter, + searchIndexService: searchIndexServiceRef, + }, + async init({ config, logger, permissions, http, searchIndexService }) { + let searchEngine = searchEngineRegistry.getSearchEngine(); + if (!searchEngine) { + searchEngine = new LunrSearchEngine({ + logger: loggerToWinstonLogger(logger), + }); + } + + const collators = searchIndexRegistry.getCollators(); + const decorators = searchIndexRegistry.getDecorators(); + + await searchIndexService.start({ + searchEngine, + collators, + decorators, + }); + + const router = await createRouter({ + config, + permissions, + logger: loggerToWinstonLogger(logger), + engine: searchEngine, + types: searchIndexService.getDocumentTypes(), + }); + + http.use(router); + }, + }); + }, +}); diff --git a/plugins/search-react/CHANGELOG.md b/plugins/search-react/CHANGELOG.md index cf6138956c..22bf885caf 100644 --- a/plugins/search-react/CHANGELOG.md +++ b/plugins/search-react/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-search-react +## 1.5.2-next.0 + +### Patch Changes + +- b2e182cdfa4: Fixes a UI bug in search result item which rendered the item text with incorrect font size and color +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/theme@0.2.18 + - @backstage/types@1.0.2 + - @backstage/version-bridge@1.0.3 + - @backstage/plugin-search-common@1.2.2 + ## 1.5.1 ### Patch Changes diff --git a/plugins/search-react/package.json b/plugins/search-react/package.json index f14a62ccea..0a8864392b 100644 --- a/plugins/search-react/package.json +++ b/plugins/search-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-react", - "version": "1.5.1", + "version": "1.5.2-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -39,7 +39,7 @@ "@backstage/version-bridge": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "lodash": "^4.17.21", "qs": "^6.9.4", "react-use": "^17.3.2" diff --git a/plugins/search-react/src/components/DefaultResultListItem/DefaultResultListItem.tsx b/plugins/search-react/src/components/DefaultResultListItem/DefaultResultListItem.tsx index cf89b6a9cd..0d2c59e173 100644 --- a/plugins/search-react/src/components/DefaultResultListItem/DefaultResultListItem.tsx +++ b/plugins/search-react/src/components/DefaultResultListItem/DefaultResultListItem.tsx @@ -81,6 +81,8 @@ export const DefaultResultListItemComponent = ({ WebkitLineClamp: lineClamp, overflow: 'hidden', }} + color="textSecondary" + variant="body2" > {highlight?.fields.text ? ( ( ); ``` +To allow external links to be added as shortcut, you can add `allowExternalLinks` property to the `` component. + The plugin exports a `shortcutApiRef` but the plugin includes a default implementation of the `ShortcutApi` that uses `localStorage` to store each user's shortcuts. To overwrite the default implementation add it to the App's `apis.ts`: diff --git a/plugins/shortcuts/api-report.md b/plugins/shortcuts/api-report.md index 19c0035a55..0dd42f5344 100644 --- a/plugins/shortcuts/api-report.md +++ b/plugins/shortcuts/api-report.md @@ -58,6 +58,8 @@ export const shortcutsPlugin: BackstagePlugin<{}, {}, {}>; // @public export interface ShortcutsProps { + // (undocumented) + allowExternalLinks?: boolean; // (undocumented) icon?: IconComponent; } diff --git a/plugins/shortcuts/package.json b/plugins/shortcuts/package.json index 1901198b80..d84cf27223 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.8", + "version": "0.3.9-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -29,7 +29,7 @@ "@backstage/types": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "react-hook-form": "^7.12.2", "react-use": "^17.2.4", "uuid": "^8.3.2", diff --git a/plugins/shortcuts/src/AddShortcut.tsx b/plugins/shortcuts/src/AddShortcut.tsx index e4b1ba84ce..1e14767531 100644 --- a/plugins/shortcuts/src/AddShortcut.tsx +++ b/plugins/shortcuts/src/AddShortcut.tsx @@ -45,9 +45,16 @@ type Props = { onClose: () => void; anchorEl?: Element; api: ShortcutApi; + + allowExternalLinks?: boolean; }; -export const AddShortcut = ({ onClose, anchorEl, api }: Props) => { +export const AddShortcut = ({ + onClose, + anchorEl, + api, + allowExternalLinks, +}: Props) => { const classes = useStyles(); const alertApi = useApi(alertApiRef); const { pathname } = useLocation(); @@ -114,6 +121,7 @@ export const AddShortcut = ({ onClose, anchorEl, api }: Props) => { onClose={handleClose} onSave={handleSave} formValues={formValues} + allowExternalLinks={allowExternalLinks} /> diff --git a/plugins/shortcuts/src/EditShortcut.tsx b/plugins/shortcuts/src/EditShortcut.tsx index 702275e90e..5336841633 100644 --- a/plugins/shortcuts/src/EditShortcut.tsx +++ b/plugins/shortcuts/src/EditShortcut.tsx @@ -46,9 +46,16 @@ type Props = { onClose: () => void; anchorEl?: Element; api: ShortcutApi; + allowExternalLinks?: boolean; }; -export const EditShortcut = ({ shortcut, onClose, anchorEl, api }: Props) => { +export const EditShortcut = ({ + shortcut, + onClose, + anchorEl, + api, + allowExternalLinks, +}: Props) => { const classes = useStyles(); const alertApi = useApi(alertApiRef); const open = Boolean(anchorEl); @@ -127,6 +134,7 @@ export const EditShortcut = ({ shortcut, onClose, anchorEl, api }: Props) => { formValues={{ url: shortcut.url, title: shortcut.title }} onClose={handleClose} onSave={handleSave} + allowExternalLinks={allowExternalLinks} /> diff --git a/plugins/shortcuts/src/ShortcutForm.test.tsx b/plugins/shortcuts/src/ShortcutForm.test.tsx index 2582148fc7..3a52356b5d 100644 --- a/plugins/shortcuts/src/ShortcutForm.test.tsx +++ b/plugins/shortcuts/src/ShortcutForm.test.tsx @@ -43,6 +43,50 @@ describe('ShortcutForm', () => { }); }); + it('allows external links', async () => { + await renderInTestApp(); + + const urlInput = screen.getByPlaceholderText('Enter a URL'); + const titleInput = screen.getByPlaceholderText('Enter a display name'); + fireEvent.change(urlInput, { + target: { value: 'https://www.backstage.io' }, + }); + fireEvent.change(titleInput, { target: { value: 'Backstage' } }); + + fireEvent.click(screen.getByText('Save')); + await waitFor(() => { + expect(props.onSave).toHaveBeenCalledWith( + expect.objectContaining({ + title: 'Backstage', + url: 'https://www.backstage.io', + }), + expect.anything(), + ); + }); + }); + + it('allows relative links when external links are enabled', async () => { + await renderInTestApp(); + + const urlInput = screen.getByPlaceholderText('Enter a URL'); + const titleInput = screen.getByPlaceholderText('Enter a display name'); + fireEvent.change(urlInput, { + target: { value: '/catalog' }, + }); + fireEvent.change(titleInput, { target: { value: 'Catalog' } }); + + fireEvent.click(screen.getByText('Save')); + await waitFor(() => { + expect(props.onSave).toHaveBeenCalledWith( + expect.objectContaining({ + title: 'Catalog', + url: '/catalog', + }), + expect.anything(), + ); + }); + }); + it('calls the save handler', async () => { await renderInTestApp( ; onClose: () => void; + allowExternalLinks?: boolean; }; -export const ShortcutForm = ({ formValues, onSave, onClose }: Props) => { +export const ShortcutForm = ({ + formValues, + onSave, + onClose, + allowExternalLinks, +}: Props) => { const classes = useStyles(); - const { handleSubmit, reset, @@ -70,10 +75,19 @@ export const ShortcutForm = ({ formValues, onSave, onClose }: Props) => { control={control} rules={{ required: true, - pattern: { - value: /^\//, - message: 'Must be a relative URL (starts with a /)', - }, + ...(allowExternalLinks + ? { + pattern: { + value: /^(https?:\/\/)|\//, + message: 'Must start with http(s):// or /', + }, + } + : { + pattern: { + value: /^\//, + message: 'Must be a relative URL (starts with a /)', + }, + }), }} render={({ field }) => ( type Props = { shortcut: Shortcut; api: ShortcutApi; + allowExternalLinks?: boolean; }; -export const ShortcutItem = ({ shortcut, api }: Props) => { +export const ShortcutItem = ({ shortcut, api, allowExternalLinks }: Props) => { const classes = useStyles(); const [anchorEl, setAnchorEl] = React.useState(); @@ -100,6 +101,7 @@ export const ShortcutItem = ({ shortcut, api }: Props) => { anchorEl={anchorEl} api={api} shortcut={shortcut} + allowExternalLinks={allowExternalLinks} /> ); diff --git a/plugins/shortcuts/src/Shortcuts.tsx b/plugins/shortcuts/src/Shortcuts.tsx index 28aa33e8f2..6b9ea4d79b 100644 --- a/plugins/shortcuts/src/Shortcuts.tsx +++ b/plugins/shortcuts/src/Shortcuts.tsx @@ -35,6 +35,7 @@ import { IconComponent, useApi } from '@backstage/core-plugin-api'; */ export interface ShortcutsProps { icon?: IconComponent; + allowExternalLinks?: boolean; } export const Shortcuts = (props: ShortcutsProps) => { @@ -62,6 +63,7 @@ export const Shortcuts = (props: ShortcutsProps) => { onClose={handleClose} anchorEl={anchorEl} api={shortcutApi} + allowExternalLinks={props.allowExternalLinks} /> {loading ? ( @@ -71,6 +73,7 @@ export const Shortcuts = (props: ShortcutsProps) => { key={shortcut.id} shortcut={shortcut} api={shortcutApi} + allowExternalLinks={props.allowExternalLinks} /> )) )} diff --git a/plugins/sonarqube-backend/CHANGELOG.md b/plugins/sonarqube-backend/CHANGELOG.md index 0f2ff1d996..1989ad3426 100644 --- a/plugins/sonarqube-backend/CHANGELOG.md +++ b/plugins/sonarqube-backend/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-sonarqube-backend +## 0.1.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/errors@1.1.5 + ## 0.1.8 ### Patch Changes diff --git a/plugins/sonarqube-backend/package.json b/plugins/sonarqube-backend/package.json index a3f3b42f43..b69b851115 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.8", + "version": "0.1.9-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/sonarqube/CHANGELOG.md b/plugins/sonarqube/CHANGELOG.md index 6eeea22725..810d2125c0 100644 --- a/plugins/sonarqube/CHANGELOG.md +++ b/plugins/sonarqube/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-sonarqube +## 0.6.6-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + - @backstage/plugin-sonarqube-react@0.1.4 + ## 0.6.5 ### Patch Changes diff --git a/plugins/sonarqube/package.json b/plugins/sonarqube/package.json index 5815032f6a..672888057a 100644 --- a/plugins/sonarqube/package.json +++ b/plugins/sonarqube/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-sonarqube", "description": "", - "version": "0.6.5", + "version": "0.6.6-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -43,7 +43,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "@material-ui/styles": "^4.10.0", "cross-fetch": "^3.1.5", "rc-progress": "3.4.1", diff --git a/plugins/splunk-on-call/CHANGELOG.md b/plugins/splunk-on-call/CHANGELOG.md index 011e513852..8295e1c7ce 100644 --- a/plugins/splunk-on-call/CHANGELOG.md +++ b/plugins/splunk-on-call/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-splunk-on-call +## 0.4.6-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/theme@0.2.18 + ## 0.4.5 ### Patch Changes diff --git a/plugins/splunk-on-call/package.json b/plugins/splunk-on-call/package.json index 98a6291791..fd7e6b524f 100644 --- a/plugins/splunk-on-call/package.json +++ b/plugins/splunk-on-call/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-splunk-on-call", "description": "A Backstage plugin that integrates towards Splunk On-Call", - "version": "0.4.5", + "version": "0.4.6-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -40,7 +40,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "classnames": "^2.2.6", "luxon": "^3.0.0", "react-use": "^17.2.4" diff --git a/plugins/stack-overflow-backend/CHANGELOG.md b/plugins/stack-overflow-backend/CHANGELOG.md index ba743be981..bc76962999 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.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/plugin-search-common@1.2.2 + ## 0.1.12 ### Patch Changes diff --git a/plugins/stack-overflow-backend/package.json b/plugins/stack-overflow-backend/package.json index 8d1203577d..a3fba58bbe 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.12", + "version": "0.1.13-next.0", "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 c8641592a6..8c8ae16170 100644 --- a/plugins/stack-overflow/CHANGELOG.md +++ b/plugins/stack-overflow/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-stack-overflow +## 0.1.13-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-search-react@1.5.2-next.0 + - @backstage/plugin-home@0.4.33-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/config@1.0.7 + - @backstage/theme@0.2.18 + - @backstage/plugin-search-common@1.2.2 + ## 0.1.12 ### Patch Changes diff --git a/plugins/stack-overflow/package.json b/plugins/stack-overflow/package.json index 952471fd50..94cc071af4 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.12", + "version": "0.1.13-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/stackstorm/CHANGELOG.md b/plugins/stackstorm/CHANGELOG.md index 3af84cd8a6..9899f2f05f 100644 --- a/plugins/stackstorm/CHANGELOG.md +++ b/plugins/stackstorm/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-stackstorm +## 0.1.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + ## 0.1.0 ### Minor Changes diff --git a/plugins/stackstorm/package.json b/plugins/stackstorm/package.json index 2819fc0e33..ff432f9199 100644 --- a/plugins/stackstorm/package.json +++ b/plugins/stackstorm/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-stackstorm", "description": "A Backstage plugin that integrates towards StackStorm", - "version": "0.1.0", + "version": "0.1.1-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -40,7 +40,6 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "^4.0.0-alpha.57", "react-use": "^17.2.4" }, "peerDependencies": { diff --git a/plugins/tech-insights-backend-module-jsonfc/CHANGELOG.md b/plugins/tech-insights-backend-module-jsonfc/CHANGELOG.md index 17334e90b7..cc49a78340 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.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/errors@1.1.5 + - @backstage/plugin-tech-insights-common@0.2.10 + - @backstage/plugin-tech-insights-node@0.4.2-next.0 + ## 0.1.27 ### Patch Changes diff --git a/plugins/tech-insights-backend-module-jsonfc/package.json b/plugins/tech-insights-backend-module-jsonfc/package.json index a6bc32a990..3e6b08c65b 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.27", + "version": "0.1.28-next.0", "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 8071740295..95497c3b88 100644 --- a/plugins/tech-insights-backend/CHANGELOG.md +++ b/plugins/tech-insights-backend/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-tech-insights-backend +## 0.5.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/types@1.0.2 + - @backstage/plugin-tech-insights-common@0.2.10 + - @backstage/plugin-tech-insights-node@0.4.2-next.0 + ## 0.5.9 ### Patch Changes diff --git a/plugins/tech-insights-backend/package.json b/plugins/tech-insights-backend/package.json index c1887906e9..f6bae36e6b 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.9", + "version": "0.5.10-next.0", "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 71eb372214..45583c194f 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.4.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/backend-tasks@0.5.1-next.0 + - @backstage/types@1.0.2 + - @backstage/plugin-tech-insights-common@0.2.10 + ## 0.4.1 ### Patch Changes diff --git a/plugins/tech-insights-node/package.json b/plugins/tech-insights-node/package.json index bfa4d893c0..d662258c3a 100644 --- a/plugins/tech-insights-node/package.json +++ b/plugins/tech-insights-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-tech-insights-node", - "version": "0.4.1", + "version": "0.4.2-next.0", "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 056b15cb8b..52d6ce6102 100644 --- a/plugins/tech-insights/CHANGELOG.md +++ b/plugins/tech-insights/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-tech-insights +## 0.3.9-next.0 + +### Patch Changes + +- f538b9c5b83: The `Check` type now optionally includes the `failureMetadata` and `successMetadata` as returned by the `runChecks` call. +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + - @backstage/types@1.0.2 + - @backstage/plugin-tech-insights-common@0.2.10 + ## 0.3.8 ### Patch Changes diff --git a/plugins/tech-insights/api-report.md b/plugins/tech-insights/api-report.md index 83509e1673..47aa8bbbea 100644 --- a/plugins/tech-insights/api-report.md +++ b/plugins/tech-insights/api-report.md @@ -27,6 +27,8 @@ export type Check = { name: string; description: string; factIds: string[]; + successMetadata?: Record; + failureMetadata?: Record; }; // @public diff --git a/plugins/tech-insights/package.json b/plugins/tech-insights/package.json index 1c912083fd..6bff5523dc 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.8", + "version": "0.3.9-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -37,7 +37,7 @@ "@backstage/types": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "qs": "^6.9.4", "react-use": "^17.2.4" }, diff --git a/plugins/tech-insights/src/api/types.ts b/plugins/tech-insights/src/api/types.ts index ac1f2e44ee..b08f63ecc2 100644 --- a/plugins/tech-insights/src/api/types.ts +++ b/plugins/tech-insights/src/api/types.ts @@ -22,11 +22,48 @@ import { JsonValue } from '@backstage/types'; * @public */ export type Check = { + /** + * Unique identifier of the check + * + * Used to identify which checks to use when running checks. + */ id: string; + + /** + * Type identifier for the check. + * Can be used to determine storage options, logical routing to correct FactChecker implementation + * or to help frontend render correct component types based on this + */ type: string; + + /** + * Human readable name of the check, may be displayed in the UI + */ name: string; + + /** + * Human readable description of the check, may be displayed in the UI + */ description: string; + + /** + * A collection of string referencing fact rows that a check will be run against. + * + * References the fact container, aka fact retriever itself which may or may not contain multiple individual facts and values + */ factIds: string[]; + + /** + * Metadata to be returned in case a check has been successfully evaluated + * Can contain links, description texts or other actionable items + */ + successMetadata?: Record; + + /** + * Metadata to be returned in case a check evaluation has ended in failure + * Can contain links, description texts or other actionable items + */ + failureMetadata?: Record; }; /** diff --git a/plugins/tech-radar/CHANGELOG.md b/plugins/tech-radar/CHANGELOG.md index 694e07eeac..0ce2e73a86 100644 --- a/plugins/tech-radar/CHANGELOG.md +++ b/plugins/tech-radar/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-tech-radar +## 0.6.3-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/theme@0.2.18 + ## 0.6.2 ### Patch Changes diff --git a/plugins/tech-radar/package.json b/plugins/tech-radar/package.json index f47e2a80c7..d02a4a0695 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.6.2", + "version": "0.6.3-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -37,7 +37,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "color": "^4.0.1", "d3-force": "^3.0.0", "prop-types": "^15.7.2", diff --git a/plugins/techdocs-addons-test-utils/CHANGELOG.md b/plugins/techdocs-addons-test-utils/CHANGELOG.md index 6aad4ffd2d..cd86a795f3 100644 --- a/plugins/techdocs-addons-test-utils/CHANGELOG.md +++ b/plugins/techdocs-addons-test-utils/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-techdocs-addons-test-utils +## 1.0.12-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/plugin-catalog@1.10.0-next.0 + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-app-api@1.7.0-next.0 + - @backstage/test-utils@1.3.0-next.0 + - @backstage/plugin-search-react@1.5.2-next.0 + - @backstage/plugin-techdocs@1.6.1-next.0 + - @backstage/plugin-techdocs-react@1.1.5-next.0 + - @backstage/integration-react@1.1.12-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/theme@0.2.18 + ## 1.0.11 ### Patch Changes diff --git a/plugins/techdocs-addons-test-utils/package.json b/plugins/techdocs-addons-test-utils/package.json index d8c6242adc..23917a52cb 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.11", + "version": "1.0.12-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -44,7 +44,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "@testing-library/react": "^12.1.3", "react-use": "^17.2.4", "testing-library__dom": "^7.29.4-beta.1" diff --git a/plugins/techdocs-backend/.gitignore b/plugins/techdocs-backend/.gitignore index 7b4d4ba2e6..b1befabea2 100644 --- a/plugins/techdocs-backend/.gitignore +++ b/plugins/techdocs-backend/.gitignore @@ -1 +1,4 @@ static + +# Folder generated by plantuml containing jdk font config +**/\?/ diff --git a/plugins/techdocs-backend/CHANGELOG.md b/plugins/techdocs-backend/CHANGELOG.md index e39e58589d..80eab46ee0 100644 --- a/plugins/techdocs-backend/CHANGELOG.md +++ b/plugins/techdocs-backend/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-techdocs-backend +## 1.6.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/backend-plugin-api@0.5.1-next.0 + - @backstage/catalog-client@1.4.0 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/plugin-catalog-common@1.0.12 + - @backstage/plugin-permission-common@0.7.4 + - @backstage/plugin-search-common@1.2.2 + - @backstage/plugin-techdocs-node@1.6.1-next.0 + ## 1.6.0 ### Minor Changes diff --git a/plugins/techdocs-backend/api-report.md b/plugins/techdocs-backend/api-report.md index 1f6aa1d66a..b8974e6d4f 100644 --- a/plugins/techdocs-backend/api-report.md +++ b/plugins/techdocs-backend/api-report.md @@ -3,12 +3,10 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts -/// - import { CatalogApi } from '@backstage/catalog-client'; import { CatalogClient } from '@backstage/catalog-client'; import { Config } from '@backstage/config'; -import { DocumentCollatorFactory } from '@backstage/plugin-search-common'; +import { DefaultTechDocsCollatorFactory as DefaultTechDocsCollatorFactory_2 } from '@backstage/plugin-search-backend-module-techdocs'; import { Entity } from '@backstage/catalog-model'; import express from 'express'; import { GeneratorBuilder } from '@backstage/plugin-techdocs-node'; @@ -19,7 +17,7 @@ import { PluginCacheManager } from '@backstage/backend-common'; import { PluginEndpointDiscovery } from '@backstage/backend-common'; import { PreparerBuilder } from '@backstage/plugin-techdocs-node'; import { PublisherBase } from '@backstage/plugin-techdocs-node'; -import { Readable } from 'stream'; +import type { TechDocsCollatorFactoryOptions as TechDocsCollatorFactoryOptions_2 } from '@backstage/plugin-search-backend-module-techdocs'; import { TechDocsDocument } from '@backstage/plugin-techdocs-node'; import { TokenManager } from '@backstage/backend-common'; import * as winston from 'winston'; @@ -47,20 +45,8 @@ export class DefaultTechDocsCollator { readonly visibilityPermission: Permission; } -// @public -export class DefaultTechDocsCollatorFactory implements DocumentCollatorFactory { - // (undocumented) - static fromConfig( - config: Config, - options: TechDocsCollatorFactoryOptions, - ): DefaultTechDocsCollatorFactory; - // (undocumented) - getCollator(): Promise; - // (undocumented) - readonly type: string; - // (undocumented) - readonly visibilityPermission: Permission; -} +// @public @deprecated (undocumented) +export const DefaultTechDocsCollatorFactory: typeof DefaultTechDocsCollatorFactory_2; // @public export interface DocsBuildStrategy { @@ -105,16 +91,8 @@ export type ShouldBuildParameters = { entity: Entity; }; -// @public -export type TechDocsCollatorFactoryOptions = { - discovery: PluginEndpointDiscovery; - logger: Logger; - tokenManager: TokenManager; - locationTemplate?: string; - catalogClient?: CatalogApi; - parallelismLimit?: number; - legacyPathCasing?: boolean; -}; +// @public @deprecated (undocumented) +export type TechDocsCollatorFactoryOptions = TechDocsCollatorFactoryOptions_2; // @public export type TechDocsCollatorOptions = { diff --git a/plugins/techdocs-backend/package.json b/plugins/techdocs-backend/package.json index 1d6ca8931e..74af0e1010 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.6.0", + "version": "1.6.1-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -57,6 +57,7 @@ "@backstage/integration": "workspace:^", "@backstage/plugin-catalog-common": "workspace:^", "@backstage/plugin-permission-common": "workspace:^", + "@backstage/plugin-search-backend-module-techdocs": "workspace:^", "@backstage/plugin-search-common": "workspace:^", "@backstage/plugin-techdocs-node": "workspace:^", "@types/express": "^4.17.6", diff --git a/plugins/techdocs-backend/src/search/index.ts b/plugins/techdocs-backend/src/search/index.ts index 68e3b4edc7..fc2b48375e 100644 --- a/plugins/techdocs-backend/src/search/index.ts +++ b/plugins/techdocs-backend/src/search/index.ts @@ -14,11 +14,23 @@ * limitations under the License. */ -export { DefaultTechDocsCollatorFactory } from './DefaultTechDocsCollatorFactory'; -export type { TechDocsCollatorFactoryOptions } from './DefaultTechDocsCollatorFactory'; - /** * todo(backstage/techdocs-core): stop exporting these in a future release. */ export { DefaultTechDocsCollator } from './DefaultTechDocsCollator'; export type { TechDocsCollatorOptions } from './DefaultTechDocsCollator'; + +import { DefaultTechDocsCollatorFactory as _DefaultTechDocsCollatorFactory } from '@backstage/plugin-search-backend-module-techdocs'; +import type { TechDocsCollatorFactoryOptions as _TechDocsCollatorFactoryOptions } from '@backstage/plugin-search-backend-module-techdocs'; + +/** + * @public + * @deprecated import from `@backstage/search-backend-module-techdocs` instead + */ +export type TechDocsCollatorFactoryOptions = _TechDocsCollatorFactoryOptions; + +/** + * @public + * @deprecated import from `@backstage/search-backend-module-techdocs` instead + */ +export const DefaultTechDocsCollatorFactory = _DefaultTechDocsCollatorFactory; diff --git a/plugins/techdocs-module-addons-contrib/CHANGELOG.md b/plugins/techdocs-module-addons-contrib/CHANGELOG.md index 005c38f64c..7d4e087301 100644 --- a/plugins/techdocs-module-addons-contrib/CHANGELOG.md +++ b/plugins/techdocs-module-addons-contrib/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-techdocs-module-addons-contrib +## 1.0.12-next.0 + +### Patch Changes + +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-techdocs-react@1.1.5-next.0 + - @backstage/integration-react@1.1.12-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/integration@1.4.3 + - @backstage/theme@0.2.18 + ## 1.0.11 ### Patch Changes diff --git a/plugins/techdocs-module-addons-contrib/package.json b/plugins/techdocs-module-addons-contrib/package.json index 12b30d3cc2..05989fed44 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.11", + "version": "1.0.12-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -41,7 +41,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "@react-hookz/web": "^20.0.0", "git-url-parse": "^13.0.0", "photoswipe": "^5.3.5", diff --git a/plugins/techdocs-node/CHANGELOG.md b/plugins/techdocs-node/CHANGELOG.md index f4221afc3a..041437bc89 100644 --- a/plugins/techdocs-node/CHANGELOG.md +++ b/plugins/techdocs-node/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-techdocs-node +## 1.6.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.18.4-next.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/integration-aws-node@0.1.2 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/plugin-search-common@1.2.2 + ## 1.6.0 ### Minor Changes diff --git a/plugins/techdocs-node/package.json b/plugins/techdocs-node/package.json index fe23c88367..1b0977fbdd 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.6.0", + "version": "1.6.1-next.0", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/plugins/techdocs-react/CHANGELOG.md b/plugins/techdocs-react/CHANGELOG.md index b0f163836a..434ab32835 100644 --- a/plugins/techdocs-react/CHANGELOG.md +++ b/plugins/techdocs-react/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-techdocs-react +## 1.1.5-next.0 + +### Patch Changes + +- 7e0c7b09a47: Fix a bug that caused the header to not render when generating a document for the first time +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/config@1.0.7 + - @backstage/catalog-model@1.2.1 + - @backstage/version-bridge@1.0.3 + ## 1.1.4 ### Patch Changes diff --git a/plugins/techdocs-react/package.json b/plugins/techdocs-react/package.json index c605838215..e77a153e65 100644 --- a/plugins/techdocs-react/package.json +++ b/plugins/techdocs-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-techdocs-react", "description": "Shared frontend utilities for TechDocs and Addons", - "version": "1.1.4", + "version": "1.1.5-next.0", "publishConfig": { "access": "public", "main": "dist/index.esm.js", @@ -39,7 +39,7 @@ "@backstage/core-plugin-api": "workspace:^", "@backstage/version-bridge": "workspace:^", "@material-ui/core": "^4.12.2", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "@material-ui/styles": "^4.11.0", "jss": "~10.10.0", "lodash": "^4.17.21", diff --git a/plugins/techdocs-react/src/context.tsx b/plugins/techdocs-react/src/context.tsx index 4f427e0031..608dbc59b3 100644 --- a/plugins/techdocs-react/src/context.tsx +++ b/plugins/techdocs-react/src/context.tsx @@ -21,8 +21,10 @@ import React, { useState, memo, ReactNode, + useEffect, } from 'react'; import useAsync, { AsyncState } from 'react-use/lib/useAsync'; +import useAsyncRetry from 'react-use/lib/useAsyncRetry'; import { CompoundEntityRef, @@ -117,14 +119,14 @@ export const TechDocsReaderPageProvider = memo( const techdocsApi = useApi(techdocsApiRef); const config = useApi(configApiRef); - const metadata = useAsync(async () => { - return techdocsApi.getTechDocsMetadata(entityRef); - }, [entityRef]); - const entityMetadata = useAsync(async () => { return techdocsApi.getEntityMetadata(entityRef); }, [entityRef]); + const metadata = useAsyncRetry(async () => { + return techdocsApi.getTechDocsMetadata(entityRef); + }, [entityRef]); + const [title, setTitle] = useState(defaultTechDocsReaderPageValue.title); const [subtitle, setSubtitle] = useState( defaultTechDocsReaderPageValue.subtitle, @@ -133,7 +135,19 @@ export const TechDocsReaderPageProvider = memo( defaultTechDocsReaderPageValue.shadowRoot, ); - const value = { + useEffect(() => { + if (shadowRoot && !metadata.value && !metadata.loading) { + metadata.retry(); + } + }, [ + metadata.value, + metadata.loading, + shadowRoot, + metadata.retry, + metadata, + ]); + + const value: TechDocsReaderPageValue = { metadata, entityRef: toLowercaseEntityRefMaybe(entityRef, config), entityMetadata, diff --git a/plugins/techdocs-react/src/hooks.ts b/plugins/techdocs-react/src/hooks.ts index e8cc7bddc8..2984a4b588 100644 --- a/plugins/techdocs-react/src/hooks.ts +++ b/plugins/techdocs-react/src/hooks.ts @@ -84,11 +84,13 @@ export const useShadowRootSelection = (waitMillis: number = 0) => { useEffect(() => { window.document.addEventListener('selectionchange', handleSelectionChange); - return () => + return () => { + handleSelectionChange.cancel(); window.document.removeEventListener( 'selectionchange', handleSelectionChange, ); + }; }, [handleSelectionChange]); return selection; diff --git a/plugins/techdocs/CHANGELOG.md b/plugins/techdocs/CHANGELOG.md index f66e0fa3a4..0b44055461 100644 --- a/plugins/techdocs/CHANGELOG.md +++ b/plugins/techdocs/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-techdocs +## 1.6.1-next.0 + +### Patch Changes + +- b2e182cdfa4: Fixes a UI bug in search result item which rendered the item text with incorrect font size and color +- 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs) +- Updated dependencies + - @backstage/core-components@0.12.6-next.0 + - @backstage/plugin-search-react@1.5.2-next.0 + - @backstage/plugin-techdocs-react@1.1.5-next.0 + - @backstage/plugin-catalog-react@1.4.1-next.0 + - @backstage/integration-react@1.1.12-next.0 + - @backstage/core-plugin-api@1.5.0 + - @backstage/config@1.0.7 + - @backstage/integration@1.4.3 + - @backstage/catalog-model@1.2.1 + - @backstage/errors@1.1.5 + - @backstage/theme@0.2.18 + - @backstage/plugin-search-common@1.2.2 + ## 1.6.0 ### Minor Changes diff --git a/plugins/techdocs/package.json b/plugins/techdocs/package.json index ae0a31ab4d..2fd4effcdc 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.6.0", + "version": "1.6.1-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -47,7 +47,7 @@ "@backstage/theme": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@material-ui/lab": "4.0.0-alpha.57", + "@material-ui/lab": "4.0.0-alpha.61", "@material-ui/styles": "^4.10.0", "dompurify": "^2.2.9", "event-source-polyfill": "1.0.25", diff --git a/plugins/techdocs/src/reader/components/TechDocsReaderPageSubheader/TechDocsReaderPageSubheader.tsx b/plugins/techdocs/src/reader/components/TechDocsReaderPageSubheader/TechDocsReaderPageSubheader.tsx index 0cef4d521f..f3612aa46e 100644 --- a/plugins/techdocs/src/reader/components/TechDocsReaderPageSubheader/TechDocsReaderPageSubheader.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsReaderPageSubheader/TechDocsReaderPageSubheader.tsx @@ -107,7 +107,7 @@ export const TechDocsReaderPageSubheader = (props: { onClose={handleClose} keepMounted > - {settingsAddons} +
{settingsAddons}
) : null} diff --git a/plugins/techdocs/src/search/components/TechDocsSearchResultListItem.tsx b/plugins/techdocs/src/search/components/TechDocsSearchResultListItem.tsx index 3c0d2314e2..eae4ee7ce9 100644 --- a/plugins/techdocs/src/search/components/TechDocsSearchResultListItem.tsx +++ b/plugins/techdocs/src/search/components/TechDocsSearchResultListItem.tsx @@ -132,6 +132,8 @@ export const TechDocsSearchResultListItem = ( WebkitLineClamp: lineClamp, overflow: 'hidden', }} + color="textSecondary" + variant="body2" > {highlight?.fields.text ? ( =1.0.0" peerDependenciesMeta: aws-crt: optional: true - checksum: b13d7e114610c15d0d4d6137e6b6e2ce2d9b696aec1f3ba60515228b9c59068260fb976a0af2d9166705e00c99408c603abf4ebc65384bcd76abfa9003a4afa4 + checksum: 20b370e1ebee13f70d7f2ee804c6069e5bcaa676591ba2aed09ef28fbd05ac8e201b0473dd0572e9e47c98bbc27f5b55d61ad469f330833576a7972c5c387be9 languageName: node linkType: hard -"@aws-sdk/util-utf8-browser@npm:3.188.0, @aws-sdk/util-utf8-browser@npm:^3.0.0": +"@aws-sdk/util-utf8-browser@npm:^3.0.0": version: 3.188.0 resolution: "@aws-sdk/util-utf8-browser@npm:3.188.0" dependencies: @@ -1592,33 +1663,33 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/util-utf8@npm:3.254.0": - version: 3.254.0 - resolution: "@aws-sdk/util-utf8@npm:3.254.0" +"@aws-sdk/util-utf8@npm:3.295.0": + version: 3.295.0 + resolution: "@aws-sdk/util-utf8@npm:3.295.0" dependencies: - "@aws-sdk/util-buffer-from": 3.208.0 - tslib: ^2.3.1 - checksum: e5dfe7565f2de32245a544d1d715d803025bc5522538c0206fa61377f747804d95fc2e5e25976144bb63a6857e360b4286d101e730ab5d39866c60383a47e7d5 + "@aws-sdk/util-buffer-from": 3.295.0 + tslib: ^2.5.0 + checksum: 098058651aa48bb2a6652ea6a1a0a1520e9964a91920e67eed023eacc0956b75475d25025e888ee193140aa800ed89faafa67653914b78c7ffb98e8f96f6d54c languageName: node linkType: hard -"@aws-sdk/util-waiter@npm:3.272.0": - version: 3.272.0 - resolution: "@aws-sdk/util-waiter@npm:3.272.0" +"@aws-sdk/util-waiter@npm:3.296.0": + version: 3.296.0 + resolution: "@aws-sdk/util-waiter@npm:3.296.0" dependencies: - "@aws-sdk/abort-controller": 3.272.0 - "@aws-sdk/types": 3.272.0 - tslib: ^2.3.1 - checksum: e931a9359dc582db9e5dcd62539572aecff5320ce424e5462c2f8d4a2d83acde07f87fe9ffc83850aaf70eaf17b06b6ffd4554350bab0f0f3a4427d1b7e776c6 + "@aws-sdk/abort-controller": 3.296.0 + "@aws-sdk/types": 3.296.0 + tslib: ^2.5.0 + checksum: 9984297149735df1791791c2f02077bab47501113393efbef619f6af9d19fb1c44a6ac79be73dbc6725a9eb3343b77c04068dcdc0797ddc7da7b9f93df810d7c languageName: node linkType: hard -"@aws-sdk/xml-builder@npm:3.201.0": - version: 3.201.0 - resolution: "@aws-sdk/xml-builder@npm:3.201.0" +"@aws-sdk/xml-builder@npm:3.295.0": + version: 3.295.0 + resolution: "@aws-sdk/xml-builder@npm:3.295.0" dependencies: - tslib: ^2.3.1 - checksum: fd250c2edcf062e79af576fa39d555f624c155540f7bb27da05a400540f3c2ceb89f33841157eda5f4558a0b6c58d2686a105d26f79eeab5790e6b6bfbe18d4a + tslib: ^2.5.0 + checksum: a32bcea43104c049b995c967ea416887fac45da8a8ecf55f06836a08aff878683c702852b383a36c04a09368ebb091388169f46f0d0a49cf477392966b4bdbdd languageName: node linkType: hard @@ -3281,13 +3352,13 @@ __metadata: languageName: node linkType: hard -"@babel/runtime-corejs3@npm:^7.11.2, @babel/runtime-corejs3@npm:^7.18.9": - version: 7.18.9 - resolution: "@babel/runtime-corejs3@npm:7.18.9" +"@babel/runtime-corejs3@npm:^7.18.9, @babel/runtime-corejs3@npm:^7.20.13, @babel/runtime-corejs3@npm:^7.20.7": + version: 7.21.0 + resolution: "@babel/runtime-corejs3@npm:7.21.0" dependencies: - core-js-pure: ^3.20.2 - regenerator-runtime: ^0.13.4 - checksum: 249158b660ac996fa4f4b0d1ab5810db060af40fac4d0bb5da23f55539a151313ae254aa64afc2ab7000d95167824e21a689f74bc24b36fd0f5ca030d522133d + core-js-pure: ^3.25.1 + regenerator-runtime: ^0.13.11 + checksum: a47927671672b1e1644771458f804e03802303eeffcafd55f85cb121d3d3ca33032cc2fe68e086e3de6923049343d0aa599fc3eb3ad5749e30646e2a2ef6f11d languageName: node linkType: hard @@ -3593,7 +3664,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/catalog-client@workspace:^, @backstage/catalog-client@workspace:packages/catalog-client": +"@backstage/catalog-client@^1.4.0, @backstage/catalog-client@workspace:^, @backstage/catalog-client@workspace:packages/catalog-client": version: 0.0.0-use.local resolution: "@backstage/catalog-client@workspace:packages/catalog-client" dependencies: @@ -3605,7 +3676,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/catalog-model@^1.1.3, @backstage/catalog-model@^1.1.5, @backstage/catalog-model@^1.2.0, @backstage/catalog-model@workspace:^, @backstage/catalog-model@workspace:packages/catalog-model": +"@backstage/catalog-model@^1.1.5, @backstage/catalog-model@^1.2.1, @backstage/catalog-model@workspace:^, @backstage/catalog-model@workspace:packages/catalog-model": version: 0.0.0-use.local resolution: "@backstage/catalog-model@workspace:packages/catalog-model" dependencies: @@ -3652,6 +3723,7 @@ __metadata: "@backstage/types": "workspace:^" "@esbuild-kit/cjs-loader": ^2.4.1 "@manypkg/get-packages": ^1.1.3 + "@octokit/oauth-app": ^4.2.0 "@octokit/request": ^6.0.0 "@pmmmwh/react-refresh-webpack-plugin": ^0.5.7 "@rollup/plugin-commonjs": ^23.0.0 @@ -3820,7 +3892,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/config@^1.0.4, @backstage/config@workspace:^, @backstage/config@workspace:packages/config": +"@backstage/config@^1.0.6, @backstage/config@^1.0.7, @backstage/config@workspace:^, @backstage/config@workspace:packages/config": version: 0.0.0-use.local resolution: "@backstage/config@workspace:packages/config" dependencies: @@ -3866,7 +3938,57 @@ __metadata: languageName: unknown linkType: soft -"@backstage/core-components@^0.12.0, @backstage/core-components@^0.12.3, @backstage/core-components@^0.12.4, @backstage/core-components@workspace:^, @backstage/core-components@workspace:packages/core-components": +"@backstage/core-components@npm:^0.12.3, @backstage/core-components@npm:^0.12.5": + version: 0.12.5 + resolution: "@backstage/core-components@npm:0.12.5" + dependencies: + "@backstage/config": ^1.0.7 + "@backstage/core-plugin-api": ^1.5.0 + "@backstage/errors": ^1.1.5 + "@backstage/theme": ^0.2.18 + "@backstage/version-bridge": ^1.0.3 + "@material-table/core": ^3.1.0 + "@material-ui/core": ^4.12.2 + "@material-ui/icons": ^4.9.1 + "@material-ui/lab": 4.0.0-alpha.57 + "@react-hookz/web": ^20.0.0 + "@types/react-sparklines": ^1.7.0 + "@types/react-text-truncate": ^0.14.0 + ansi-regex: ^6.0.1 + classnames: ^2.2.6 + d3-selection: ^3.0.0 + d3-shape: ^3.0.0 + d3-zoom: ^3.0.0 + dagre: ^0.8.5 + history: ^5.0.0 + immer: ^9.0.1 + lodash: ^4.17.21 + pluralize: ^8.0.0 + prop-types: ^15.7.2 + qs: ^6.9.4 + rc-progress: 3.4.1 + react-helmet: 6.1.0 + react-hook-form: ^7.12.2 + react-markdown: ^8.0.0 + react-sparklines: ^1.7.0 + react-syntax-highlighter: ^15.4.5 + react-text-truncate: ^0.19.0 + react-use: ^17.3.2 + react-virtualized-auto-sizer: ^1.0.6 + react-window: ^1.8.6 + remark-gfm: ^3.0.1 + zen-observable: ^0.10.0 + zod: ~3.18.0 + peerDependencies: + "@types/react": ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 + react-dom: ^16.13.1 || ^17.0.0 + react-router-dom: 6.0.0-beta.0 || ^6.3.0 + checksum: 8308c1b90247911f6cf22963b530cef169287f508ff29d159d0c83758134dd43bd5acd2113350690a46a02246bc05dca975bcc38325000aefb1c93c80e2f19c7 + languageName: node + linkType: hard + +"@backstage/core-components@workspace:^, @backstage/core-components@workspace:packages/core-components": version: 0.0.0-use.local resolution: "@backstage/core-components@workspace:packages/core-components" dependencies: @@ -3881,7 +4003,7 @@ __metadata: "@material-table/core": ^3.1.0 "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@react-hookz/web": ^20.0.0 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 @@ -3937,7 +4059,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/core-plugin-api@^1.1.0, @backstage/core-plugin-api@^1.3.0, @backstage/core-plugin-api@^1.4.0, @backstage/core-plugin-api@workspace:^, @backstage/core-plugin-api@workspace:packages/core-plugin-api": +"@backstage/core-plugin-api@^1.3.0, @backstage/core-plugin-api@^1.5.0, @backstage/core-plugin-api@workspace:^, @backstage/core-plugin-api@workspace:packages/core-plugin-api": version: 0.0.0-use.local resolution: "@backstage/core-plugin-api@workspace:packages/core-plugin-api" dependencies: @@ -4022,7 +4144,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/errors@workspace:^, @backstage/errors@workspace:packages/errors": +"@backstage/errors@^1.1.5, @backstage/errors@workspace:^, @backstage/errors@workspace:packages/errors": version: 0.0.0-use.local resolution: "@backstage/errors@workspace:packages/errors" dependencies: @@ -4063,7 +4185,26 @@ __metadata: languageName: unknown linkType: soft -"@backstage/integration-react@^1.1.10, @backstage/integration-react@workspace:^, @backstage/integration-react@workspace:packages/integration-react": +"@backstage/integration-react@npm:^1.1.11": + version: 1.1.11 + resolution: "@backstage/integration-react@npm:1.1.11" + dependencies: + "@backstage/config": ^1.0.7 + "@backstage/core-components": ^0.12.5 + "@backstage/core-plugin-api": ^1.5.0 + "@backstage/integration": ^1.4.3 + "@backstage/theme": ^0.2.18 + "@material-ui/core": ^4.12.2 + "@material-ui/icons": ^4.9.1 + "@material-ui/lab": 4.0.0-alpha.57 + react-use: ^17.2.4 + peerDependencies: + react: ^16.13.1 || ^17.0.0 + checksum: ea3946236486a4d36c7851cf2f6562eacf10da00923cd7d51bb1f50e60bba766008745fd431ec26de9843cf5acc8fd6b3ba7a654e4e43a815f6d02151eeee235 + languageName: node + linkType: hard + +"@backstage/integration-react@workspace:^, @backstage/integration-react@workspace:packages/integration-react": version: 0.0.0-use.local resolution: "@backstage/integration-react@workspace:packages/integration-react" dependencies: @@ -4077,7 +4218,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -4090,7 +4231,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/integration@workspace:^, @backstage/integration@workspace:packages/integration": +"@backstage/integration@^1.4.3, @backstage/integration@workspace:^, @backstage/integration@workspace:packages/integration": version: 0.0.0-use.local resolution: "@backstage/integration@workspace:packages/integration" dependencies: @@ -4168,7 +4309,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -4221,7 +4362,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -4250,7 +4391,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -4278,7 +4419,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -4304,7 +4445,7 @@ __metadata: "@backstage/test-utils": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -4348,7 +4489,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -4383,7 +4524,6 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@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 @@ -4560,7 +4700,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -4622,7 +4762,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -4674,7 +4814,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -4725,7 +4865,7 @@ __metadata: "@date-io/luxon": 1.x "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@material-ui/pickers": ^3.3.10 "@testing-library/jest-dom": ^5.10.1 cross-fetch: ^3.1.5 @@ -4766,7 +4906,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -5032,6 +5172,7 @@ __metadata: "@backstage/cli": "workspace:^" "@backstage/config": "workspace:^" "@backstage/errors": "workspace:^" + "@backstage/plugin-catalog-common": "workspace:^" "@backstage/plugin-catalog-node": "workspace:^" "@backstage/types": "workspace:^" "@types/ldapjs": ^2.2.0 @@ -5055,6 +5196,7 @@ __metadata: "@backstage/catalog-model": "workspace:^" "@backstage/cli": "workspace:^" "@backstage/config": "workspace:^" + "@backstage/plugin-catalog-common": "workspace:^" "@backstage/plugin-catalog-node": "workspace:^" "@microsoft/microsoft-graph-types": ^2.6.0 "@types/lodash": ^4.14.151 @@ -5082,6 +5224,7 @@ __metadata: "@backstage/config": "workspace:^" "@backstage/integration": "workspace:^" "@backstage/plugin-catalog-backend": "workspace:^" + "@backstage/plugin-catalog-common": "workspace:^" "@backstage/plugin-catalog-node": "workspace:^" "@backstage/types": "workspace:^" openapi-types: ^12.0.0 @@ -5132,6 +5275,7 @@ __metadata: "@backstage/plugin-permission-common": "workspace:^" "@backstage/plugin-permission-node": "workspace:^" "@backstage/plugin-scaffolder-common": "workspace:^" + "@backstage/plugin-search-backend-module-catalog": "workspace:^" "@backstage/plugin-search-backend-node": "workspace:^" "@backstage/plugin-search-common": "workspace:^" "@backstage/types": "workspace:^" @@ -5169,7 +5313,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-catalog-common@^1.0.8, @backstage/plugin-catalog-common@workspace:^, @backstage/plugin-catalog-common@workspace:plugins/catalog-common": +"@backstage/plugin-catalog-common@^1.0.10, @backstage/plugin-catalog-common@^1.0.12, @backstage/plugin-catalog-common@workspace:^, @backstage/plugin-catalog-common@workspace:plugins/catalog-common": version: 0.0.0-use.local resolution: "@backstage/plugin-catalog-common@workspace:plugins/catalog-common" dependencies: @@ -5198,7 +5342,7 @@ __metadata: "@backstage/types": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/react-hooks": ^8.0.0 @@ -5219,6 +5363,8 @@ __metadata: version: 0.0.0-use.local resolution: "@backstage/plugin-catalog-graphql@workspace:plugins/catalog-graphql" dependencies: + "@apollo/client": ^3.0.0 + "@apollo/server": ^4.0.0 "@backstage/catalog-model": "workspace:^" "@backstage/cli": "workspace:^" "@backstage/config": "workspace:^" @@ -5229,7 +5375,6 @@ __metadata: "@graphql-codegen/typescript": ^3.0.0 "@graphql-codegen/typescript-resolvers": ^3.0.0 "@graphql-tools/schema": ^9.0.0 - apollo-server: ^3.0.0 graphql: ^16.0.0 graphql-modules: ^2.0.0 graphql-tag: ^2.11.0 @@ -5260,7 +5405,7 @@ __metadata: "@backstage/test-utils": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@octokit/rest": ^19.0.3 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 @@ -5297,7 +5442,42 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-catalog-react@^1.2.1, @backstage/plugin-catalog-react@^1.2.4, @backstage/plugin-catalog-react@^1.3.0, @backstage/plugin-catalog-react@workspace:^, @backstage/plugin-catalog-react@workspace:plugins/catalog-react": +"@backstage/plugin-catalog-react@npm:^1.2.4, @backstage/plugin-catalog-react@npm:^1.4.0": + version: 1.4.0 + resolution: "@backstage/plugin-catalog-react@npm:1.4.0" + dependencies: + "@backstage/catalog-client": ^1.4.0 + "@backstage/catalog-model": ^1.2.1 + "@backstage/core-components": ^0.12.5 + "@backstage/core-plugin-api": ^1.5.0 + "@backstage/errors": ^1.1.5 + "@backstage/integration": ^1.4.3 + "@backstage/plugin-catalog-common": ^1.0.12 + "@backstage/plugin-permission-common": ^0.7.4 + "@backstage/plugin-permission-react": ^0.4.11 + "@backstage/theme": ^0.2.18 + "@backstage/types": ^1.0.2 + "@backstage/version-bridge": ^1.0.3 + "@material-ui/core": ^4.12.2 + "@material-ui/icons": ^4.9.1 + "@material-ui/lab": 4.0.0-alpha.57 + classnames: ^2.2.6 + jwt-decode: ^3.1.0 + lodash: ^4.17.21 + material-ui-popup-state: ^1.9.3 + qs: ^6.9.4 + react-use: ^17.2.4 + yaml: ^2.0.0 + zen-observable: ^0.10.0 + peerDependencies: + "@types/react": ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 + react-router-dom: 6.0.0-beta.0 || ^6.3.0 + checksum: 40af3a97f3f8fd87b8bb8dcde2e54e47937be9e1fc0872df7d767d0e6caf6271293fd8160899c1adb7d19599de204255c1b2652cf04e0126d2db29af22321abc + languageName: node + linkType: hard + +"@backstage/plugin-catalog-react@workspace:^, @backstage/plugin-catalog-react@workspace:plugins/catalog-react": version: 0.0.0-use.local resolution: "@backstage/plugin-catalog-react@workspace:plugins/catalog-react" dependencies: @@ -5319,7 +5499,7 @@ __metadata: "@backstage/version-bridge": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/react-hooks": ^8.0.0 @@ -5366,7 +5546,7 @@ __metadata: "@backstage/types": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -5410,7 +5590,7 @@ __metadata: "@date-io/luxon": ^1.3.13 "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@material-ui/pickers": ^3.3.10 "@types/luxon": ^3.0.0 "@types/react": ^16.13.1 || ^17.0.0 @@ -5440,7 +5620,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -5474,7 +5654,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -5504,7 +5684,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -5566,7 +5746,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@material-ui/styles": ^4.11.0 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 @@ -5601,7 +5781,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": ^4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -5632,7 +5812,7 @@ __metadata: "@backstage/types": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -5672,7 +5852,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@material-ui/styles": ^4.9.6 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 @@ -5715,7 +5895,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -5779,7 +5959,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.9.13 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/react-hooks": ^8.0.1 @@ -5816,7 +5996,7 @@ __metadata: "@codemirror/view": ^6.0.0 "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": ^4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@react-hookz/web": ^20.0.0 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 @@ -5972,6 +6152,7 @@ __metadata: "@backstage/cli": "workspace:^" "@backstage/config": "workspace:^" "@backstage/plugin-explore-common": "workspace:^" + "@backstage/plugin-search-backend-module-explore": "workspace:^" "@backstage/plugin-search-common": "workspace:^" "@types/express": "*" "@types/supertest": ^2.0.8 @@ -6033,7 +6214,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -6064,7 +6245,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -6094,7 +6275,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -6123,7 +6304,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@maxim_mazurok/gapi.client.calendar": ^3.0.20220408 "@tanstack/react-query": ^4.1.3 "@testing-library/jest-dom": ^5.10.1 @@ -6158,7 +6339,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@react-hookz/web": ^20.0.0 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 @@ -6186,7 +6367,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@octokit/rest": ^19.0.3 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 @@ -6223,7 +6404,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@octokit/rest": ^19.0.3 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 @@ -6257,7 +6438,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@octokit/graphql": ^5.0.0 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 @@ -6289,7 +6470,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.4 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": ^4.0.0-alpha.61 + "@material-ui/lab": 4.0.0-alpha.61 "@spotify/prettier-config": ^14.0.0 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 @@ -6321,7 +6502,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@octokit/rest": ^19.0.3 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 @@ -6344,6 +6525,7 @@ __metadata: resolution: "@backstage/plugin-gitops-profiles@workspace:plugins/gitops-profiles" dependencies: "@backstage/cli": "workspace:^" + "@backstage/config": "workspace:^" "@backstage/core-app-api": "workspace:^" "@backstage/core-components": "workspace:^" "@backstage/core-plugin-api": "workspace:^" @@ -6352,7 +6534,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -6382,7 +6564,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -6413,7 +6595,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -6435,6 +6617,7 @@ __metadata: version: 0.0.0-use.local resolution: "@backstage/plugin-graphql-backend@workspace:plugins/graphql-backend" dependencies: + "@apollo/server": ^4.0.0 "@backstage/backend-common": "workspace:^" "@backstage/cli": "workspace:^" "@backstage/config": "workspace:^" @@ -6442,8 +6625,6 @@ __metadata: "@graphql-tools/schema": ^9.0.0 "@types/express": ^4.17.6 "@types/supertest": ^2.0.8 - apollo-server: ^3.0.0 - apollo-server-express: ^3.0.0 express: ^4.17.1 express-promise-router: ^4.1.0 graphql: ^16.0.0 @@ -6470,7 +6651,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -6484,7 +6665,30 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-home@^0.4.30, @backstage/plugin-home@workspace:^, @backstage/plugin-home@workspace:plugins/home": +"@backstage/plugin-home@npm:^0.4.32": + version: 0.4.32 + resolution: "@backstage/plugin-home@npm:0.4.32" + dependencies: + "@backstage/catalog-model": ^1.2.1 + "@backstage/config": ^1.0.7 + "@backstage/core-components": ^0.12.5 + "@backstage/core-plugin-api": ^1.5.0 + "@backstage/plugin-catalog-react": ^1.4.0 + "@backstage/theme": ^0.2.18 + "@material-ui/core": ^4.12.2 + "@material-ui/icons": ^4.9.1 + "@material-ui/lab": 4.0.0-alpha.57 + lodash: ^4.17.21 + react-use: ^17.2.4 + peerDependencies: + "@types/react": ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 + react-router-dom: 6.0.0-beta.0 || ^6.3.0 + checksum: 24e4b880be179b940098ab636333218200d26dbea249c883dc27b4e209bbec9ae74970d11340833c668dbd05d978a354be771d15dba96a105267365321f1db57 + languageName: node + linkType: hard + +"@backstage/plugin-home@workspace:^, @backstage/plugin-home@workspace:plugins/home": version: 0.0.0-use.local resolution: "@backstage/plugin-home@workspace:plugins/home" dependencies: @@ -6500,7 +6704,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -6533,7 +6737,7 @@ __metadata: "@date-io/luxon": 1.x "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@material-ui/pickers": ^3.3.10 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 @@ -6602,7 +6806,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -6657,7 +6861,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/react-hooks": ^8.0.0 @@ -6687,6 +6891,8 @@ __metadata: "@backstage/errors": "workspace:^" "@backstage/plugin-auth-node": "workspace:^" "@backstage/plugin-kubernetes-common": "workspace:^" + "@backstage/plugin-permission-common": "workspace:^" + "@backstage/plugin-permission-node": "workspace:^" "@google-cloud/container": ^4.0.0 "@jest-mock/express": ^2.0.1 "@kubernetes/client-node": 0.18.1 @@ -6723,6 +6929,7 @@ __metadata: dependencies: "@backstage/catalog-model": "workspace:^" "@backstage/cli": "workspace:^" + "@backstage/plugin-permission-common": "workspace:^" "@kubernetes/client-node": 0.18.1 languageName: unknown linkType: soft @@ -6745,7 +6952,7 @@ __metadata: "@kubernetes/client-node": 0.18.1 "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/react-hooks": ^8.0.0 @@ -6807,7 +7014,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/react-hooks": ^8.0.0 @@ -6879,7 +7086,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.9.13 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": ^4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -6940,7 +7147,7 @@ __metadata: "@backstage/plugin-catalog-react": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@types/react": ^16.13.1 || ^17.0.0 cross-fetch: ^3.1.5 @@ -6963,7 +7170,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -6991,7 +7198,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.9.13 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -7020,7 +7227,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": ^4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -7049,7 +7256,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -7082,7 +7289,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -7135,7 +7342,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -7178,7 +7385,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-permission-common@workspace:^, @backstage/plugin-permission-common@workspace:plugins/permission-common": +"@backstage/plugin-permission-common@^0.7.4, @backstage/plugin-permission-common@workspace:^, @backstage/plugin-permission-common@workspace:plugins/permission-common": version: 0.0.0-use.local resolution: "@backstage/plugin-permission-common@workspace:plugins/permission-common" dependencies: @@ -7215,7 +7422,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-permission-react@workspace:^, @backstage/plugin-permission-react@workspace:plugins/permission-react": +"@backstage/plugin-permission-react@^0.4.11, @backstage/plugin-permission-react@workspace:^, @backstage/plugin-permission-react@workspace:plugins/permission-react": version: 0.0.0-use.local resolution: "@backstage/plugin-permission-react@workspace:plugins/permission-react" dependencies: @@ -7296,7 +7503,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": ^4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/react-hooks": ^8.0.0 @@ -7383,7 +7590,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/react-hooks": ^8.0.0 @@ -7425,6 +7632,21 @@ __metadata: languageName: unknown linkType: soft +"@backstage/plugin-scaffolder-backend-module-gitlab@workspace:plugins/scaffolder-backend-module-gitlab": + version: 0.0.0-use.local + resolution: "@backstage/plugin-scaffolder-backend-module-gitlab@workspace:plugins/scaffolder-backend-module-gitlab" + dependencies: + "@backstage/backend-common": "workspace:^" + "@backstage/cli": "workspace:^" + "@backstage/config": "workspace:^" + "@backstage/core-app-api": "workspace:^" + "@backstage/errors": "workspace:^" + "@backstage/integration": "workspace:^" + "@backstage/plugin-scaffolder-node": "workspace:^" + "@gitbeaker/node": ^35.8.0 + languageName: unknown + linkType: soft + "@backstage/plugin-scaffolder-backend-module-rails@workspace:^, @backstage/plugin-scaffolder-backend-module-rails@workspace:plugins/scaffolder-backend-module-rails": version: 0.0.0-use.local resolution: "@backstage/plugin-scaffolder-backend-module-rails@workspace:plugins/scaffolder-backend-module-rails" @@ -7489,7 +7711,10 @@ __metadata: "@backstage/integration": "workspace:^" "@backstage/plugin-auth-node": "workspace:^" "@backstage/plugin-catalog-backend": "workspace:^" + "@backstage/plugin-catalog-common": "workspace:^" "@backstage/plugin-catalog-node": "workspace:^" + "@backstage/plugin-permission-common": "workspace:^" + "@backstage/plugin-permission-node": "workspace:^" "@backstage/plugin-scaffolder-common": "workspace:^" "@backstage/plugin-scaffolder-node": "workspace:^" "@backstage/types": "workspace:^" @@ -7500,6 +7725,7 @@ __metadata: "@types/express": ^4.17.6 "@types/fs-extra": ^9.0.1 "@types/git-url-parse": ^9.0.0 + "@types/luxon": ^3.0.0 "@types/mock-fs": ^4.13.0 "@types/nunjucks": ^3.1.4 "@types/supertest": ^2.0.8 @@ -7534,6 +7760,7 @@ __metadata: supertest: ^6.1.3 uuid: ^8.2.0 vm2: ^3.9.11 + wait-for-expect: ^3.0.2 winston: ^3.2.1 yaml: ^2.0.0 zen-observable: ^0.10.0 @@ -7547,6 +7774,7 @@ __metadata: dependencies: "@backstage/catalog-model": "workspace:^" "@backstage/cli": "workspace:^" + "@backstage/plugin-permission-common": "workspace:^" "@backstage/types": "workspace:^" languageName: unknown linkType: soft @@ -7588,14 +7816,14 @@ __metadata: "@backstage/version-bridge": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@react-hookz/web": ^20.0.0 "@rjsf/core": ^3.2.1 - "@rjsf/core-v5": "npm:@rjsf/core@5.1.0" + "@rjsf/core-v5": "npm:@rjsf/core@5.3.1" "@rjsf/material-ui": ^3.2.1 - "@rjsf/material-ui-v5": "npm:@rjsf/material-ui@5.1.0" - "@rjsf/utils": 5.1.0 - "@rjsf/validator-ajv8": 5.1.0 + "@rjsf/material-ui-v5": "npm:@rjsf/material-ui@5.3.1" + "@rjsf/utils": 5.3.1 + "@rjsf/validator-ajv8": 5.3.1 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/react-hooks": ^8.0.0 @@ -7652,12 +7880,12 @@ __metadata: "@codemirror/view": ^6.0.0 "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@react-hookz/web": ^20.0.0 "@rjsf/core": ^3.2.1 "@rjsf/material-ui": ^3.2.1 - "@rjsf/utils": 5.1.0 - "@rjsf/validator-ajv8": 5.1.0 + "@rjsf/utils": 5.3.1 + "@rjsf/validator-ajv8": 5.3.1 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/react-hooks": ^8.0.0 @@ -7690,11 +7918,32 @@ __metadata: languageName: unknown linkType: soft +"@backstage/plugin-search-backend-module-catalog@workspace:^, @backstage/plugin-search-backend-module-catalog@workspace:plugins/search-backend-module-catalog": + version: 0.0.0-use.local + resolution: "@backstage/plugin-search-backend-module-catalog@workspace:plugins/search-backend-module-catalog" + dependencies: + "@backstage/backend-common": "workspace:^" + "@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/plugin-catalog-common": "workspace:^" + "@backstage/plugin-permission-common": "workspace:^" + "@backstage/plugin-search-backend-node": "workspace:^" + "@backstage/plugin-search-common": "workspace:^" + msw: ^1.0.0 + languageName: unknown + linkType: soft + "@backstage/plugin-search-backend-module-elasticsearch@workspace:^, @backstage/plugin-search-backend-module-elasticsearch@workspace:plugins/search-backend-module-elasticsearch": version: 0.0.0-use.local resolution: "@backstage/plugin-search-backend-module-elasticsearch@workspace:plugins/search-backend-module-elasticsearch" dependencies: "@backstage/backend-common": "workspace:^" + "@backstage/backend-plugin-api": "workspace:^" "@backstage/cli": "workspace:^" "@backstage/config": "workspace:^" "@backstage/plugin-search-backend-node": "workspace:^" @@ -7712,11 +7961,30 @@ __metadata: languageName: unknown linkType: soft +"@backstage/plugin-search-backend-module-explore@workspace:^, @backstage/plugin-search-backend-module-explore@workspace:plugins/search-backend-module-explore": + version: 0.0.0-use.local + resolution: "@backstage/plugin-search-backend-module-explore@workspace:plugins/search-backend-module-explore" + dependencies: + "@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-explore-common": "workspace:^" + "@backstage/plugin-search-backend-node": "workspace:^" + "@backstage/plugin-search-common": "workspace:^" + node-fetch: ^2.6.7 + winston: ^3.2.1 + languageName: unknown + linkType: soft + "@backstage/plugin-search-backend-module-pg@workspace:^, @backstage/plugin-search-backend-module-pg@workspace:plugins/search-backend-module-pg": version: 0.0.0-use.local resolution: "@backstage/plugin-search-backend-module-pg@workspace:plugins/search-backend-module-pg" dependencies: "@backstage/backend-common": "workspace:^" + "@backstage/backend-plugin-api": "workspace:^" "@backstage/backend-test-utils": "workspace:^" "@backstage/cli": "workspace:^" "@backstage/config": "workspace:^" @@ -7729,11 +7997,37 @@ __metadata: languageName: unknown linkType: soft +"@backstage/plugin-search-backend-module-techdocs@workspace:^, @backstage/plugin-search-backend-module-techdocs@workspace:plugins/search-backend-module-techdocs": + version: 0.0.0-use.local + resolution: "@backstage/plugin-search-backend-module-techdocs@workspace:plugins/search-backend-module-techdocs" + dependencies: + "@backstage/backend-common": "workspace:^" + "@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/plugin-catalog-common": "workspace:^" + "@backstage/plugin-permission-common": "workspace:^" + "@backstage/plugin-search-backend-node": "workspace:^" + "@backstage/plugin-search-common": "workspace:^" + "@backstage/plugin-techdocs-node": "workspace:^" + lodash: ^4.17.21 + msw: ^1.0.0 + node-fetch: ^2.6.7 + p-limit: ^3.1.0 + winston: ^3.2.1 + languageName: unknown + linkType: soft + "@backstage/plugin-search-backend-node@workspace:^, @backstage/plugin-search-backend-node@workspace:plugins/search-backend-node": version: 0.0.0-use.local resolution: "@backstage/plugin-search-backend-node@workspace:plugins/search-backend-node" dependencies: "@backstage/backend-common": "workspace:^" + "@backstage/backend-plugin-api": "workspace:^" "@backstage/backend-tasks": "workspace:^" "@backstage/cli": "workspace:^" "@backstage/config": "workspace:^" @@ -7755,6 +8049,8 @@ __metadata: resolution: "@backstage/plugin-search-backend@workspace:plugins/search-backend" dependencies: "@backstage/backend-common": "workspace:^" + "@backstage/backend-plugin-api": "workspace:^" + "@backstage/backend-test-utils": "workspace:^" "@backstage/cli": "workspace:^" "@backstage/config": "workspace:^" "@backstage/errors": "workspace:^" @@ -7803,7 +8099,7 @@ __metadata: "@backstage/version-bridge": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/react-hooks": ^8.0.0 @@ -7839,7 +8135,7 @@ __metadata: "@backstage/version-bridge": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/react-hooks": ^8.0.0 @@ -7872,7 +8168,7 @@ __metadata: "@material-table/core": ^3.1.0 "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -7904,7 +8200,7 @@ __metadata: "@backstage/types": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -7971,7 +8267,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@material-ui/styles": ^4.10.0 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 @@ -8001,7 +8297,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -8081,7 +8377,6 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@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 @@ -8190,7 +8485,7 @@ __metadata: "@backstage/types": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -8219,7 +8514,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -8256,7 +8551,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -8288,6 +8583,7 @@ __metadata: "@backstage/integration": "workspace:^" "@backstage/plugin-catalog-common": "workspace:^" "@backstage/plugin-permission-common": "workspace:^" + "@backstage/plugin-search-backend-module-techdocs": "workspace:^" "@backstage/plugin-search-backend-node": "workspace:^" "@backstage/plugin-search-common": "workspace:^" "@backstage/plugin-techdocs-node": "workspace:^" @@ -8324,7 +8620,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@react-hookz/web": ^20.0.0 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 @@ -8398,7 +8694,7 @@ __metadata: "@backstage/theme": "workspace:^" "@backstage/version-bridge": "workspace:^" "@material-ui/core": ^4.12.2 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@material-ui/styles": ^4.11.0 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 @@ -8437,7 +8733,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@material-ui/styles": ^4.10.0 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 @@ -8505,7 +8801,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -8558,7 +8854,7 @@ __metadata: "@backstage/types": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -8617,7 +8913,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": ^4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -8644,7 +8940,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -8737,7 +9033,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/theme@^0.2.16, @backstage/theme@^0.2.17, @backstage/theme@workspace:^, @backstage/theme@workspace:packages/theme": +"@backstage/theme@^0.2.16, @backstage/theme@^0.2.18, @backstage/theme@workspace:^, @backstage/theme@workspace:packages/theme": version: 0.0.0-use.local resolution: "@backstage/theme@workspace:packages/theme" dependencies: @@ -8746,7 +9042,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/types@^1.0.1, @backstage/types@workspace:^, @backstage/types@workspace:packages/types": +"@backstage/types@^1.0.2, @backstage/types@workspace:^, @backstage/types@workspace:packages/types": version: 0.0.0-use.local resolution: "@backstage/types@workspace:packages/types" dependencies: @@ -8757,7 +9053,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/version-bridge@^1.0.2, @backstage/version-bridge@workspace:^, @backstage/version-bridge@workspace:packages/version-bridge": +"@backstage/version-bridge@^1.0.3, @backstage/version-bridge@workspace:^, @backstage/version-bridge@workspace:packages/version-bridge": version: 0.0.0-use.local resolution: "@backstage/version-bridge@workspace:packages/version-bridge" dependencies: @@ -8785,10 +9081,10 @@ __metadata: languageName: node linkType: hard -"@braintree/sanitize-url@npm:=6.0.0": - version: 6.0.0 - resolution: "@braintree/sanitize-url@npm:6.0.0" - checksum: 409ce7709dc1a0c67bc887d20af1becd4145d5c62cc5124b1c4c1f3ea2a8d69b0ee9f582d446469c6f5294b56442b99048cbbba6861dd5c834d4e019b95e1f40 +"@braintree/sanitize-url@npm:=6.0.2": + version: 6.0.2 + resolution: "@braintree/sanitize-url@npm:6.0.2" + checksum: 6a9dfd4081cc96516eeb281d1a83d3b5f1ad3d2837adf968fcc2ba18889ee833554f9c641b4083c36d3360a932e4504ddf25b0b51e9933c3742622df82cf7c9a languageName: node linkType: hard @@ -8837,8 +9133,8 @@ __metadata: linkType: hard "@changesets/cli@npm:^2.14.0": - version: 2.26.0 - resolution: "@changesets/cli@npm:2.26.0" + version: 2.26.1 + resolution: "@changesets/cli@npm:2.26.1" dependencies: "@babel/runtime": ^7.20.1 "@changesets/apply-release-plan": ^6.1.3 @@ -8875,7 +9171,7 @@ __metadata: tty-table: ^4.1.5 bin: changeset: bin.js - checksum: 12a911b4196ff390ce114e27b475e59f5f5e1fdc7049d1ab04effe73d4811d99db47a030de6abe332300b4b2c43cffc537cec4883476b59b69bc23aee07cd5c5 + checksum: d7d6445ebbc1b2718d97852a2275f59af32020e8a1e1efe666767819dd862c7794ce50627ad52f1f97ba4bc57c81bfc4750e92265757cc94ab2d44198d2afb10 languageName: node linkType: hard @@ -9072,11 +9368,11 @@ __metadata: linkType: hard "@codemirror/legacy-modes@npm:^6.1.0": - version: 6.3.1 - resolution: "@codemirror/legacy-modes@npm:6.3.1" + version: 6.3.2 + resolution: "@codemirror/legacy-modes@npm:6.3.2" dependencies: "@codemirror/language": ^6.0.0 - checksum: 9065e521bf14e33856e9d3ea114d7b352adf341a8b8d4fb94b4c866189336a32b5ed42ffc20f5d2fa3c839f1bdf29a868bbf9b74c105ed83fa9fd6080e0429e9 + checksum: fa5f5477fb9e19267251e2ecd3de8c1a4c2512813555bb60111dce3951f2c3f6080a2985a573b7542534ba1d2c34115f7e39ee23fdf8f6f81db6f8ce447c1efc languageName: node linkType: hard @@ -9122,13 +9418,13 @@ __metadata: linkType: hard "@codemirror/view@npm:^6.0.0": - version: 6.9.2 - resolution: "@codemirror/view@npm:6.9.2" + version: 6.9.3 + resolution: "@codemirror/view@npm:6.9.3" dependencies: "@codemirror/state": ^6.1.4 style-mod: ^4.0.0 w3c-keyname: ^2.2.4 - checksum: e6faaf1b2daf9e4605eafd1782a0a6363cf0ee8a6c4e1aa57ebea2b2cc2b402914f07448f12210da0144126860adab052442c51831911a326867a53c745a60cf + checksum: 718ecbb021ca75eb89003f73c846a07d36a708dcfec8345f0f0dbcfc0d0df5ea6f114918694b2730a6d49e5e50502bcce79ce7ff94ce55748e068e5a35073755 languageName: node linkType: hard @@ -9330,9 +9626,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/android-arm64@npm:0.17.11": - version: 0.17.11 - resolution: "@esbuild/android-arm64@npm:0.17.11" +"@esbuild/android-arm64@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/android-arm64@npm:0.17.12" conditions: os=android & cpu=arm64 languageName: node linkType: hard @@ -9351,9 +9647,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/android-arm@npm:0.17.11": - version: 0.17.11 - resolution: "@esbuild/android-arm@npm:0.17.11" +"@esbuild/android-arm@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/android-arm@npm:0.17.12" conditions: os=android & cpu=arm languageName: node linkType: hard @@ -9365,9 +9661,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/android-x64@npm:0.17.11": - version: 0.17.11 - resolution: "@esbuild/android-x64@npm:0.17.11" +"@esbuild/android-x64@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/android-x64@npm:0.17.12" conditions: os=android & cpu=x64 languageName: node linkType: hard @@ -9379,9 +9675,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/darwin-arm64@npm:0.17.11": - version: 0.17.11 - resolution: "@esbuild/darwin-arm64@npm:0.17.11" +"@esbuild/darwin-arm64@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/darwin-arm64@npm:0.17.12" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard @@ -9393,9 +9689,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/darwin-x64@npm:0.17.11": - version: 0.17.11 - resolution: "@esbuild/darwin-x64@npm:0.17.11" +"@esbuild/darwin-x64@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/darwin-x64@npm:0.17.12" conditions: os=darwin & cpu=x64 languageName: node linkType: hard @@ -9407,9 +9703,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/freebsd-arm64@npm:0.17.11": - version: 0.17.11 - resolution: "@esbuild/freebsd-arm64@npm:0.17.11" +"@esbuild/freebsd-arm64@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/freebsd-arm64@npm:0.17.12" conditions: os=freebsd & cpu=arm64 languageName: node linkType: hard @@ -9421,9 +9717,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/freebsd-x64@npm:0.17.11": - version: 0.17.11 - resolution: "@esbuild/freebsd-x64@npm:0.17.11" +"@esbuild/freebsd-x64@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/freebsd-x64@npm:0.17.12" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard @@ -9435,9 +9731,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-arm64@npm:0.17.11": - version: 0.17.11 - resolution: "@esbuild/linux-arm64@npm:0.17.11" +"@esbuild/linux-arm64@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/linux-arm64@npm:0.17.12" conditions: os=linux & cpu=arm64 languageName: node linkType: hard @@ -9449,9 +9745,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-arm@npm:0.17.11": - version: 0.17.11 - resolution: "@esbuild/linux-arm@npm:0.17.11" +"@esbuild/linux-arm@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/linux-arm@npm:0.17.12" conditions: os=linux & cpu=arm languageName: node linkType: hard @@ -9463,9 +9759,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-ia32@npm:0.17.11": - version: 0.17.11 - resolution: "@esbuild/linux-ia32@npm:0.17.11" +"@esbuild/linux-ia32@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/linux-ia32@npm:0.17.12" conditions: os=linux & cpu=ia32 languageName: node linkType: hard @@ -9484,9 +9780,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-loong64@npm:0.17.11": - version: 0.17.11 - resolution: "@esbuild/linux-loong64@npm:0.17.11" +"@esbuild/linux-loong64@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/linux-loong64@npm:0.17.12" conditions: os=linux & cpu=loong64 languageName: node linkType: hard @@ -9498,9 +9794,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-mips64el@npm:0.17.11": - version: 0.17.11 - resolution: "@esbuild/linux-mips64el@npm:0.17.11" +"@esbuild/linux-mips64el@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/linux-mips64el@npm:0.17.12" conditions: os=linux & cpu=mips64el languageName: node linkType: hard @@ -9512,9 +9808,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-ppc64@npm:0.17.11": - version: 0.17.11 - resolution: "@esbuild/linux-ppc64@npm:0.17.11" +"@esbuild/linux-ppc64@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/linux-ppc64@npm:0.17.12" conditions: os=linux & cpu=ppc64 languageName: node linkType: hard @@ -9526,9 +9822,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-riscv64@npm:0.17.11": - version: 0.17.11 - resolution: "@esbuild/linux-riscv64@npm:0.17.11" +"@esbuild/linux-riscv64@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/linux-riscv64@npm:0.17.12" conditions: os=linux & cpu=riscv64 languageName: node linkType: hard @@ -9540,9 +9836,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-s390x@npm:0.17.11": - version: 0.17.11 - resolution: "@esbuild/linux-s390x@npm:0.17.11" +"@esbuild/linux-s390x@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/linux-s390x@npm:0.17.12" conditions: os=linux & cpu=s390x languageName: node linkType: hard @@ -9554,9 +9850,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-x64@npm:0.17.11": - version: 0.17.11 - resolution: "@esbuild/linux-x64@npm:0.17.11" +"@esbuild/linux-x64@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/linux-x64@npm:0.17.12" conditions: os=linux & cpu=x64 languageName: node linkType: hard @@ -9568,9 +9864,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/netbsd-x64@npm:0.17.11": - version: 0.17.11 - resolution: "@esbuild/netbsd-x64@npm:0.17.11" +"@esbuild/netbsd-x64@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/netbsd-x64@npm:0.17.12" conditions: os=netbsd & cpu=x64 languageName: node linkType: hard @@ -9582,9 +9878,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/openbsd-x64@npm:0.17.11": - version: 0.17.11 - resolution: "@esbuild/openbsd-x64@npm:0.17.11" +"@esbuild/openbsd-x64@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/openbsd-x64@npm:0.17.12" conditions: os=openbsd & cpu=x64 languageName: node linkType: hard @@ -9596,9 +9892,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/sunos-x64@npm:0.17.11": - version: 0.17.11 - resolution: "@esbuild/sunos-x64@npm:0.17.11" +"@esbuild/sunos-x64@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/sunos-x64@npm:0.17.12" conditions: os=sunos & cpu=x64 languageName: node linkType: hard @@ -9610,9 +9906,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/win32-arm64@npm:0.17.11": - version: 0.17.11 - resolution: "@esbuild/win32-arm64@npm:0.17.11" +"@esbuild/win32-arm64@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/win32-arm64@npm:0.17.12" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard @@ -9624,9 +9920,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/win32-ia32@npm:0.17.11": - version: 0.17.11 - resolution: "@esbuild/win32-ia32@npm:0.17.11" +"@esbuild/win32-ia32@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/win32-ia32@npm:0.17.12" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard @@ -9638,9 +9934,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/win32-x64@npm:0.17.11": - version: 0.17.11 - resolution: "@esbuild/win32-x64@npm:0.17.11" +"@esbuild/win32-x64@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/win32-x64@npm:0.17.12" conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -9753,52 +10049,52 @@ __metadata: linkType: hard "@gitbeaker/browser@npm:^35.6.0": - version: 35.8.0 - resolution: "@gitbeaker/browser@npm:35.8.0" + version: 35.8.1 + resolution: "@gitbeaker/browser@npm:35.8.1" dependencies: - "@gitbeaker/core": ^35.8.0 - "@gitbeaker/requester-utils": ^35.8.0 + "@gitbeaker/core": ^35.8.1 + "@gitbeaker/requester-utils": ^35.8.1 delay: ^5.0.0 ky: 0.28.7 - checksum: 23fa14d64661108c03a5d141123037aebb68e257d84e26bd8f6241df65a0958eaa79b8b491e0f08159e325cdc3244f79b2426dedcc2354ad106316ea499415ac + checksum: 8a76322cfd19da3d691fb08c7ebc79971da02cfb950841578523f20de02cb5e2dcf9741eca048dfa17d6a9620eb4884c9a29d84a230ba9c8d18fc528deb830cd languageName: node linkType: hard -"@gitbeaker/core@npm:^35.6.0, @gitbeaker/core@npm:^35.8.0": - version: 35.8.0 - resolution: "@gitbeaker/core@npm:35.8.0" +"@gitbeaker/core@npm:^35.6.0, @gitbeaker/core@npm:^35.8.1": + version: 35.8.1 + resolution: "@gitbeaker/core@npm:35.8.1" dependencies: - "@gitbeaker/requester-utils": ^35.8.0 + "@gitbeaker/requester-utils": ^35.8.1 form-data: ^4.0.0 li: ^1.3.0 mime: ^3.0.0 query-string: ^7.0.0 xcase: ^2.0.1 - checksum: b894e1ac86dc8ac85f2db51d83d392899c10bb555b2448900f502ffeb49d9f36c1063c7151128ca96951ac472c11be6320584c4bec873501e96607bd7c25a37b + checksum: 8fc7b8d32a2162b70fd8e8ec4e019a3654da3fd1bcb7204b5030e8c9b4af52f4e7addafcd5503042e31dd4e4e3bdd7f8245dd963c77427d4471ab2e331266cf7 languageName: node linkType: hard -"@gitbeaker/node@npm:^35.1.0": - version: 35.8.0 - resolution: "@gitbeaker/node@npm:35.8.0" +"@gitbeaker/node@npm:^35.1.0, @gitbeaker/node@npm:^35.8.0": + version: 35.8.1 + resolution: "@gitbeaker/node@npm:35.8.1" dependencies: - "@gitbeaker/core": ^35.8.0 - "@gitbeaker/requester-utils": ^35.8.0 + "@gitbeaker/core": ^35.8.1 + "@gitbeaker/requester-utils": ^35.8.1 delay: ^5.0.0 got: ^11.8.3 xcase: ^2.0.1 - checksum: af75fa2348ec6fcdd1605f269df10c13bd7d53f9a5c42da7e013db920a1129075072de3a0ada97d800be732575bb838b8a462472faebcfaf9fe243b93d29a464 + checksum: b9439c8dadadc6c1c19c4528543226e18dffdff4bdb00904b18a0621af62f0449e203a500ec3f27f386c7a02adc373585e06a1f6e0f93b6b34a0be1ced857e92 languageName: node linkType: hard -"@gitbeaker/requester-utils@npm:^35.8.0": - version: 35.8.0 - resolution: "@gitbeaker/requester-utils@npm:35.8.0" +"@gitbeaker/requester-utils@npm:^35.8.1": + version: 35.8.1 + resolution: "@gitbeaker/requester-utils@npm:35.8.1" dependencies: form-data: ^4.0.0 qs: ^6.10.1 xcase: ^2.0.1 - checksum: 6bd49b821fb6f262c6306c06fc4812f41902c864a7d941b0d112381b352f680e50ebd6180840e21a89d761427cb1326d9829b74c98c95bf9fa2a5d53872a400a + checksum: c3c94ad90dab481887380f5bcff0416c1e1eee935fc3ca4f12d8db83d85c5f0d47f7f35cee6f2b05491bda99c03fb7eb88b849c986822eae3b1bfc26641ec899 languageName: node linkType: hard @@ -9906,8 +10202,8 @@ __metadata: linkType: hard "@graphql-codegen/cli@npm:^3.0.0": - version: 3.2.1 - resolution: "@graphql-codegen/cli@npm:3.2.1" + version: 3.2.2 + resolution: "@graphql-codegen/cli@npm:3.2.2" dependencies: "@babel/generator": ^7.18.13 "@babel/template": ^7.18.10 @@ -9928,12 +10224,12 @@ __metadata: "@whatwg-node/fetch": ^0.8.0 chalk: ^4.1.0 cosmiconfig: ^7.0.0 - cosmiconfig-typescript-loader: ^4.3.0 debounce: ^1.2.0 detect-indent: ^6.0.0 - graphql-config: ^4.4.0 + graphql-config: ^4.5.0 inquirer: ^8.0.0 is-glob: ^4.0.1 + jiti: ^1.17.1 json-to-pretty-yaml: ^1.2.2 listr2: ^4.0.5 log-symbols: ^4.0.0 @@ -9941,7 +10237,6 @@ __metadata: shell-quote: ^1.7.3 string-env-interpolation: ^1.0.1 ts-log: ^2.2.3 - ts-node: ^10.9.1 tslib: ^2.4.0 yaml: ^1.10.0 yargs: ^17.0.0 @@ -9952,7 +10247,7 @@ __metadata: graphql-code-generator: cjs/bin.js graphql-codegen: cjs/bin.js graphql-codegen-esm: esm/bin.js - checksum: b62e2a3cee866cb006163946272f25ba9cc59bb2d45b7b3df5d1b220096e79183929456a440e5c4980d6a5664d6b14d7870d7f1760eb250b9211f4743d2afad3 + checksum: b94284ac538a3504f96c7d507c140b7cfee30042209c4230ffc3068f05b6b27c75e1922b31c696363ab43e34e472ed194cc72996bbb10f59991cd2a4a35ff36e languageName: node linkType: hard @@ -9971,18 +10266,18 @@ __metadata: linkType: hard "@graphql-codegen/graphql-modules-preset@npm:^3.0.0": - version: 3.1.0 - resolution: "@graphql-codegen/graphql-modules-preset@npm:3.1.0" + version: 3.1.1 + resolution: "@graphql-codegen/graphql-modules-preset@npm:3.1.1" dependencies: "@graphql-codegen/plugin-helpers": ^4.1.0 - "@graphql-codegen/visitor-plugin-common": 3.0.1 + "@graphql-codegen/visitor-plugin-common": 3.0.2 "@graphql-tools/utils": ^9.0.0 change-case-all: 1.0.15 parse-filepath: ^1.0.2 tslib: ~2.5.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: cee2e7f8afbc0b0d81592abfc8894422b791f0eca6e878a789de980bf1710a3c726786ade296e653cc83f920b2618aa9f5c9dbb6934ee9da0122b2d10ef5bdb5 + checksum: f437590afa33ac308c075d214b501404ae2f99888cac8071d05cc2b8c7ceaea5aef8f86bb60e7a9a45902126dc99bd20d77e951c0beef665aaa31ac3c2217e26 languageName: node linkType: hard @@ -10016,39 +10311,39 @@ __metadata: linkType: hard "@graphql-codegen/typescript-resolvers@npm:^3.0.0": - version: 3.1.0 - resolution: "@graphql-codegen/typescript-resolvers@npm:3.1.0" + version: 3.1.1 + resolution: "@graphql-codegen/typescript-resolvers@npm:3.1.1" dependencies: "@graphql-codegen/plugin-helpers": ^4.1.0 - "@graphql-codegen/typescript": ^3.0.1 - "@graphql-codegen/visitor-plugin-common": 3.0.1 + "@graphql-codegen/typescript": ^3.0.2 + "@graphql-codegen/visitor-plugin-common": 3.0.2 "@graphql-tools/utils": ^9.0.0 auto-bind: ~4.0.0 tslib: ~2.5.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: 05888a9dfd1556fe15465a524750c36881334c231297e2e89bccb536450bed61fde2ba182ba4e79e34be846ce2e2439f3f6b31a67e7437f03a4e4ace62e84dcd + checksum: 88faa1ca2335096aa9939101f3591007d9fa477836d969a3c622dbf67704505600387a2e9fbb416d61b5ef42dbd79a0d351003037c0756d8d0c7f32c7961e783 languageName: node linkType: hard -"@graphql-codegen/typescript@npm:^3.0.0, @graphql-codegen/typescript@npm:^3.0.1": - version: 3.0.1 - resolution: "@graphql-codegen/typescript@npm:3.0.1" +"@graphql-codegen/typescript@npm:^3.0.0, @graphql-codegen/typescript@npm:^3.0.2": + version: 3.0.2 + resolution: "@graphql-codegen/typescript@npm:3.0.2" dependencies: "@graphql-codegen/plugin-helpers": ^4.1.0 "@graphql-codegen/schema-ast": ^3.0.1 - "@graphql-codegen/visitor-plugin-common": 3.0.1 + "@graphql-codegen/visitor-plugin-common": 3.0.2 auto-bind: ~4.0.0 tslib: ~2.5.0 peerDependencies: graphql: ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 - checksum: 56a369237971cc4a5a4987628ec0fcceed66ec03a292b3d17b6ffb64279185cd085be351268c55be6b152634c430e885b9c584d816aaa25f067d91c6996c329a + checksum: e92dc54804b6ad45fb2499b91cb89743e455a984684e2b1df1b1a8f479a0bbffa5c625be97ccb55874ac8b7316a820b546e9e312b22eda78012acd5c27594a28 languageName: node linkType: hard -"@graphql-codegen/visitor-plugin-common@npm:3.0.1": - version: 3.0.1 - resolution: "@graphql-codegen/visitor-plugin-common@npm:3.0.1" +"@graphql-codegen/visitor-plugin-common@npm:3.0.2": + version: 3.0.2 + resolution: "@graphql-codegen/visitor-plugin-common@npm:3.0.2" dependencies: "@graphql-codegen/plugin-helpers": ^4.1.0 "@graphql-tools/optimize": ^1.3.0 @@ -10062,7 +10357,7 @@ __metadata: tslib: ~2.5.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: 32bf553f73938581f634b1bbdf8616b1cb30cc85c73d7a8f6088d2a81a957e198c7c278edf6582c1eee7328a4463cea4725316b1743b87b26dc3e9fdd8318648 + checksum: c8f941df7f8304b722b492ceaf15dddcf33e3a69bc29b54970908ffa12b14d92276958005bd307648e0cdc55f9e243d0fb390862f73a17a26bd50f6484ac42d6 languageName: node linkType: hard @@ -10080,20 +10375,6 @@ __metadata: languageName: node linkType: hard -"@graphql-tools/batch-execute@npm:8.5.1": - version: 8.5.1 - resolution: "@graphql-tools/batch-execute@npm:8.5.1" - dependencies: - "@graphql-tools/utils": 8.9.0 - dataloader: 2.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: 56c3b9bbab7e3402710186df4de5ae716dc31caa16f3dc51434b5167f0a513881afc1cd835f3df8ff0536f80462394dbb12e5246cda999dcee043e9bf37bcbe2 - languageName: node - linkType: hard - "@graphql-tools/batch-execute@npm:8.5.14": version: 8.5.14 resolution: "@graphql-tools/batch-execute@npm:8.5.14" @@ -10108,6 +10389,20 @@ __metadata: languageName: node linkType: hard +"@graphql-tools/batch-execute@npm:^8.5.18": + version: 8.5.18 + resolution: "@graphql-tools/batch-execute@npm:8.5.18" + dependencies: + "@graphql-tools/utils": 9.2.1 + dataloader: 2.2.2 + tslib: ^2.4.0 + value-or-promise: 1.0.12 + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + checksum: 4a5b5dec502a91bd657a4ddad74965d050d3994c89f036225fac58657b5a275bb374224b20484e3ba773525e75a5552c4a5af7b6d52859ce3a3b32aec2412b6e + languageName: node + linkType: hard + "@graphql-tools/code-file-loader@npm:^7.3.17": version: 7.3.21 resolution: "@graphql-tools/code-file-loader@npm:7.3.21" @@ -10123,22 +10418,6 @@ __metadata: languageName: node linkType: hard -"@graphql-tools/delegate@npm:8.8.1": - version: 8.8.1 - resolution: "@graphql-tools/delegate@npm:8.8.1" - dependencies: - "@graphql-tools/batch-execute": 8.5.1 - "@graphql-tools/schema": 8.5.1 - "@graphql-tools/utils": 8.9.0 - dataloader: 2.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: 5246c63fbb42a22f881a1857bc36fdc6092a4f8c4b0f82d4113eca75aeb676305c42319f65c564816b8c4f4eef2a7b93ee709ff548ff78e5fb3e6c0845ac6d7e - languageName: node - linkType: hard - "@graphql-tools/delegate@npm:9.0.21": version: 9.0.21 resolution: "@graphql-tools/delegate@npm:9.0.21" @@ -10156,6 +10435,23 @@ __metadata: languageName: node linkType: hard +"@graphql-tools/delegate@npm:9.0.28": + version: 9.0.28 + resolution: "@graphql-tools/delegate@npm:9.0.28" + dependencies: + "@graphql-tools/batch-execute": ^8.5.18 + "@graphql-tools/executor": ^0.0.15 + "@graphql-tools/schema": ^9.0.16 + "@graphql-tools/utils": ^9.2.1 + dataloader: ^2.2.2 + tslib: ^2.5.0 + value-or-promise: ^1.0.12 + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + checksum: e24c757ea15a2b654268194bbf76188fca6692486d1b019b0ad7d48c264f92b7b681a43c8a8355ace48a29f9dd566c20e8707b6cef281331a813f23ee1c94375 + languageName: node + linkType: hard + "@graphql-tools/executor-graphql-ws@npm:0.0.5": version: 0.0.5 resolution: "@graphql-tools/executor-graphql-ws@npm:0.0.5" @@ -10221,6 +10517,21 @@ __metadata: languageName: node linkType: hard +"@graphql-tools/executor@npm:^0.0.15": + version: 0.0.15 + resolution: "@graphql-tools/executor@npm:0.0.15" + dependencies: + "@graphql-tools/utils": 9.2.1 + "@graphql-typed-document-node/core": 3.1.2 + "@repeaterjs/repeater": 3.0.4 + tslib: ^2.4.0 + value-or-promise: 1.0.12 + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + checksum: 7a963d6fcd00bd9c2a42f35a33bc9178576a1eeac755ce69981aa1e2c61238953b7ab9c11ffcfc86e49fdcf4fc057698c6f7169d6be580298e286076276b1295 + languageName: node + linkType: hard + "@graphql-tools/git-loader@npm:^7.2.13": version: 7.2.13 resolution: "@graphql-tools/git-loader@npm:7.2.13" @@ -10340,30 +10651,6 @@ __metadata: languageName: node linkType: hard -"@graphql-tools/merge@npm:8.2.10": - version: 8.2.10 - resolution: "@graphql-tools/merge@npm:8.2.10" - dependencies: - "@graphql-tools/utils": 8.6.9 - tslib: ~2.3.0 - peerDependencies: - graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 - checksum: 7059d9f68cfb9b7c04d6024f528e5638fab165e681b3307877a6bad0fc461686595d19375350875bb5f4f7572b21d10272a1e4b08a8af5b6a67950a4a950012b - languageName: node - linkType: hard - -"@graphql-tools/merge@npm:8.3.1": - version: 8.3.1 - resolution: "@graphql-tools/merge@npm:8.3.1" - dependencies: - "@graphql-tools/utils": 8.9.0 - tslib: ^2.4.0 - peerDependencies: - graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - checksum: 16af6be2249f4f500a4c2f5d3db2e0efd56ad69b5e10499649c6fc979c257af12e131112304a16699654b54daab37a80737e0538478bc45a0053b9bc859a7ac1 - languageName: node - linkType: hard - "@graphql-tools/merge@npm:8.3.14": version: 8.3.14 resolution: "@graphql-tools/merge@npm:8.3.14" @@ -10400,20 +10687,6 @@ __metadata: languageName: node linkType: hard -"@graphql-tools/mock@npm:^8.1.2": - version: 8.6.8 - resolution: "@graphql-tools/mock@npm:8.6.8" - dependencies: - "@graphql-tools/schema": 8.3.10 - "@graphql-tools/utils": 8.6.9 - fast-json-stable-stringify: ^2.1.0 - tslib: ~2.3.0 - peerDependencies: - graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 - checksum: 594abfbb7766806e07910624d80e5c27cdf15e0b2d1a0eff4336b2d6c63bde3587ae6f7c889374217cb0893d8e9e87f696daf1cf1ce2fdae787dae22b8b4d228 - languageName: node - linkType: hard - "@graphql-tools/optimize@npm:^1.3.0": version: 1.3.0 resolution: "@graphql-tools/optimize@npm:1.3.0" @@ -10467,34 +10740,6 @@ __metadata: languageName: node linkType: hard -"@graphql-tools/schema@npm:8.3.10": - version: 8.3.10 - resolution: "@graphql-tools/schema@npm:8.3.10" - dependencies: - "@graphql-tools/merge": 8.2.10 - "@graphql-tools/utils": 8.6.9 - tslib: ~2.3.0 - value-or-promise: 1.0.11 - peerDependencies: - graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 - checksum: 8b225f4ae87d3f1d8d9772df605a27dfde069a2372f2af0a1459859c4310c5fef8243c1276c1959e316420f1584d739b9f52c55dd230d2ad177cde1019155b81 - languageName: node - linkType: hard - -"@graphql-tools/schema@npm:8.5.1, @graphql-tools/schema@npm:^8.0.0, @graphql-tools/schema@npm:^8.3.1": - version: 8.5.1 - resolution: "@graphql-tools/schema@npm:8.5.1" - dependencies: - "@graphql-tools/merge": 8.3.1 - "@graphql-tools/utils": 8.9.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: 91363cd4371e347af40ef66f7d903b5d4f5998bfaec9214768e6a795136ef6372f9f225e05e18daacd929e23695811f15e791c6cbe082bf5b5d03b16b1f874f8 - languageName: node - linkType: hard - "@graphql-tools/schema@npm:9.0.12": version: 9.0.12 resolution: "@graphql-tools/schema@npm:9.0.12" @@ -10523,7 +10768,7 @@ __metadata: languageName: node linkType: hard -"@graphql-tools/schema@npm:^9.0.0": +"@graphql-tools/schema@npm:9.0.17, @graphql-tools/schema@npm:^9.0.0, @graphql-tools/schema@npm:^9.0.16": version: 9.0.17 resolution: "@graphql-tools/schema@npm:9.0.17" dependencies: @@ -10560,17 +10805,6 @@ __metadata: languageName: node linkType: hard -"@graphql-tools/utils@npm:8.6.9": - version: 8.6.9 - resolution: "@graphql-tools/utils@npm:8.6.9" - dependencies: - tslib: ~2.3.0 - peerDependencies: - graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 - checksum: 73b9569a9c2409f86a6a9005f19026cfab6d136bf884dfbff436996a47fb0561ae24d3f6bb2abcfd600197aab85d6dfc177b9a0cbaba23905ba0c7591ef12110 - languageName: node - linkType: hard - "@graphql-tools/utils@npm:8.8.0": version: 8.8.0 resolution: "@graphql-tools/utils@npm:8.8.0" @@ -10626,7 +10860,7 @@ __metadata: languageName: node linkType: hard -"@graphql-tools/utils@npm:9.2.1, @graphql-tools/utils@npm:^9.0.0, @graphql-tools/utils@npm:^9.1.1": +"@graphql-tools/utils@npm:9.2.1, @graphql-tools/utils@npm:^9.0.0, @graphql-tools/utils@npm:^9.1.1, @graphql-tools/utils@npm:^9.2.1": version: 9.2.1 resolution: "@graphql-tools/utils@npm:9.2.1" dependencies: @@ -10653,22 +10887,22 @@ __metadata: languageName: node linkType: hard -"@graphql-tools/wrap@npm:^8.3.1": - version: 8.5.1 - resolution: "@graphql-tools/wrap@npm:8.5.1" +"@graphql-tools/wrap@npm:^9.0.0": + version: 9.3.8 + resolution: "@graphql-tools/wrap@npm:9.3.8" dependencies: - "@graphql-tools/delegate": 8.8.1 - "@graphql-tools/schema": 8.5.1 - "@graphql-tools/utils": 8.9.0 + "@graphql-tools/delegate": 9.0.28 + "@graphql-tools/schema": 9.0.17 + "@graphql-tools/utils": 9.2.1 tslib: ^2.4.0 - value-or-promise: 1.0.11 + value-or-promise: 1.0.12 peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - checksum: bc9350015adde545208709584cf1a3c5b4bc3bbfd82062b93b4da253481e366d9f9caad49d7f2f0aaa7fe070167d15b99da7ee76e431c0c6bee815923aafdb29 + checksum: 1f280b939f1c8c33be8fbd92c0584e9125e30c59ce6f75f20657235d24e5a2c01eb3214eda9ae74d431d9da072cdfa6cedeafdc5b352dd33de439ba42402efcb languageName: node linkType: hard -"@graphql-typed-document-node/core@npm:3.1.1, @graphql-typed-document-node/core@npm:^3.1.0, @graphql-typed-document-node/core@npm:^3.1.1": +"@graphql-typed-document-node/core@npm:3.1.1": version: 3.1.1 resolution: "@graphql-typed-document-node/core@npm:3.1.1" peerDependencies: @@ -10677,6 +10911,15 @@ __metadata: languageName: node linkType: hard +"@graphql-typed-document-node/core@npm:3.1.2, @graphql-typed-document-node/core@npm:^3.1.0, @graphql-typed-document-node/core@npm:^3.1.1": + version: 3.1.2 + resolution: "@graphql-typed-document-node/core@npm:3.1.2" + 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 || ^17.0.0 + checksum: a61afa025acdabd7833e4f654a5802fc1a526171f81e0c435c8e651050a5a0682499a2c7a51304ceb61fde36cd69fc7975ce5e1b16b9ba7ea474c649f33eea8b + languageName: node + linkType: hard + "@grpc/grpc-js@npm:~1.8.0": version: 1.8.9 resolution: "@grpc/grpc-js@npm:1.8.9" @@ -10828,7 +11071,7 @@ __metadata: "@backstage/theme": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 @@ -11530,7 +11773,7 @@ __metadata: languageName: node linkType: hard -"@material-ui/lab@npm:^4.0.0-alpha.57, @material-ui/lab@npm:^4.0.0-alpha.60, @material-ui/lab@npm:^4.0.0-alpha.61": +"@material-ui/lab@npm:4.0.0-alpha.61, @material-ui/lab@npm:^4.0.0-alpha.57, @material-ui/lab@npm:^4.0.0-alpha.60": version: 4.0.0-alpha.61 resolution: "@material-ui/lab@npm:4.0.0-alpha.61" dependencies: @@ -12265,9 +12508,9 @@ __metadata: languageName: node linkType: hard -"@octokit/oauth-app@npm:^4.0.4, @octokit/oauth-app@npm:^4.0.6": - version: 4.0.6 - resolution: "@octokit/oauth-app@npm:4.0.6" +"@octokit/oauth-app@npm:^4.0.4, @octokit/oauth-app@npm:^4.0.6, @octokit/oauth-app@npm:^4.2.0": + version: 4.2.0 + resolution: "@octokit/oauth-app@npm:4.2.0" dependencies: "@octokit/auth-oauth-app": ^5.0.0 "@octokit/auth-oauth-user": ^2.0.0 @@ -12276,13 +12519,9 @@ __metadata: "@octokit/oauth-authorization-url": ^5.0.0 "@octokit/oauth-methods": ^2.0.0 "@types/aws-lambda": ^8.10.83 - aws-lambda: ^1.0.7 fromentries: ^1.3.1 universal-user-agent: ^6.0.0 - dependenciesMeta: - aws-lambda: - optional: true - checksum: 0d7ceadda4668748a436f52f6c4ae3160a4a5c81a92592c0a6cfc75b0a065ed480880d8861efcabc6ca41b3ccf753d1c1044782a6c8d5fb481d6e8a0acf6d32e + checksum: 6cf5638d27e589daa577653177f2b135c0c346c8f74cc420d9fd0dc0f559a84040073eee147bd555a55bb5756bd0940e6dc4c3a6b3a508a818e3d5bee3837095 languageName: node linkType: hard @@ -12666,25 +12905,25 @@ __metadata: linkType: hard "@opentelemetry/api@npm:^1.0.1, @opentelemetry/api@npm:^1.3.0": - version: 1.4.0 - resolution: "@opentelemetry/api@npm:1.4.0" - checksum: 8dc522194e20d2e8aa6cac155dbce19d3fc9cfac59e953ece1064158c6348ccd9560ee99d2f2381e82c2f8c9a129b57fa7b640027383315504de1fa712b6d7f1 + version: 1.4.1 + resolution: "@opentelemetry/api@npm:1.4.1" + checksum: e783c40d1a518abf9c4c5d65223237c1392cd9a6c53ac6e2c3ef0c05ff7266e3dfc4fd9874316dae0dcb7a97950878deb513bcbadfaad653d48f0215f2a0911b languageName: node linkType: hard "@oriflame/backstage-plugin-score-card@npm:^0.6.0": - version: 0.6.2 - resolution: "@oriflame/backstage-plugin-score-card@npm:0.6.2" + version: 0.6.3 + resolution: "@oriflame/backstage-plugin-score-card@npm:0.6.3" dependencies: - "@backstage/catalog-model": ^1.1.3 - "@backstage/config": ^1.0.4 - "@backstage/core-components": ^0.12.0 - "@backstage/core-plugin-api": ^1.1.0 - "@backstage/plugin-catalog-common": ^1.0.8 - "@backstage/plugin-catalog-react": ^1.2.1 + "@backstage/catalog-model": ^1.1.5 + "@backstage/config": ^1.0.6 + "@backstage/core-components": ^0.12.3 + "@backstage/core-plugin-api": ^1.3.0 + "@backstage/plugin-catalog-common": ^1.0.10 + "@backstage/plugin-catalog-react": ^1.2.4 "@backstage/theme": ^0.2.16 - "@backstage/types": ^1.0.1 - "@backstage/version-bridge": ^1.0.2 + "@backstage/types": ^1.0.2 + "@backstage/version-bridge": ^1.0.3 "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.11.2 "@material-ui/lab": ^4.0.0-alpha.57 @@ -12692,7 +12931,7 @@ __metadata: peerDependencies: react: ^16.13.1 || ^17.0.0 react-dom: ^16.13.1 || ^17.0.0 - checksum: 6c8ca85981fde5af8e3951f0f5fc9c3873c890d286fd29067215246e9b8e9022ceea308c9caa8b0ccfe5380fe5640aaede48c9963a57c3c98f5c3b5feade9aae + checksum: cdf57bb0ea42b1ef3699b65e558c0d9f2483555fefd03bc3ff4e4d75524c904d723e4808987e8718eac63ab60da6257af82e7d45c70cd42fc00bb1a4c392578b languageName: node linkType: hard @@ -12898,18 +13137,19 @@ __metadata: languageName: node linkType: hard -"@rjsf/core-v5@npm:@rjsf/core@5.1.0": - version: 5.1.0 - resolution: "@rjsf/core@npm:5.1.0" +"@rjsf/core-v5@npm:@rjsf/core@5.3.1": + version: 5.3.1 + resolution: "@rjsf/core@npm:5.3.1" dependencies: lodash: ^4.17.15 lodash-es: ^4.17.15 + markdown-to-jsx: ^7.1.9 nanoid: ^3.3.4 prop-types: ^15.7.2 peerDependencies: "@rjsf/utils": ^5.0.0 react: ^16.14.0 || >=17 - checksum: ff38046bb25de86b57e404c5d1ccea84b0485e916caf33a3cb25b030a38ed930a9b89a411671a7c29b047da38e0c682e20b43b13e61d77df770299385ba3c67a + checksum: e7f5c05a594db0549c5289f1dc570977fa37c9ca0f1fed47ec17fa49dd4b6b85ffc3844c9c11d36455a66ff17f898469b6a2dca159223de348f84bdadd28ae32 languageName: node linkType: hard @@ -12932,16 +13172,16 @@ __metadata: languageName: node linkType: hard -"@rjsf/material-ui-v5@npm:@rjsf/material-ui@5.1.0": - version: 5.1.0 - resolution: "@rjsf/material-ui@npm:5.1.0" +"@rjsf/material-ui-v5@npm:@rjsf/material-ui@5.3.1": + version: 5.3.1 + resolution: "@rjsf/material-ui@npm:5.3.1" peerDependencies: "@material-ui/core": ^4.12.3 "@material-ui/icons": ^4.11.2 "@rjsf/core": ^5.0.0 "@rjsf/utils": ^5.0.0 react: ^16.14.0 || >=17 - checksum: f8e2c486f33a60703cae5bb42ae82bc431b3d743c239868ca71907e7b4127a39d1688200820c0c8acdf3ecd3f5eaddef4ba47264695feead28e9b439d9be7ce8 + checksum: 169d78e3983742b38008de95ab320cdc1f52995dabf2e75d44052c09fb0b734ecb45c58fbdf51dea18bf8bd45130aec01dc0b4b75a2635e82ef5c489d1d35af1 languageName: node linkType: hard @@ -12957,9 +13197,9 @@ __metadata: languageName: node linkType: hard -"@rjsf/utils@npm:5.1.0": - version: 5.1.0 - resolution: "@rjsf/utils@npm:5.1.0" +"@rjsf/utils@npm:5.3.1": + version: 5.3.1 + resolution: "@rjsf/utils@npm:5.3.1" dependencies: json-schema-merge-allof: ^0.8.1 jsonpointer: ^5.0.1 @@ -12968,13 +13208,13 @@ __metadata: react-is: ^18.2.0 peerDependencies: react: ^16.14.0 || >=17 - checksum: 76d7caf144f98b1547067bfdc2b1baecf452c63bd9d6f2cae6c162a99154bb4d2f5033f6abc0e26ab767dca9ea743f1f5a9d796696e90dd5ed1fdca5ee3c5280 + checksum: 400a17bf99a043557adbd4e0dc3651b9d1b47ab61a40acb8756c5b986d044a329bd26bf45263a667eb963acf51084d612c043c9409aeaac4e4c6ab66af0bb700 languageName: node linkType: hard -"@rjsf/validator-ajv8@npm:5.1.0": - version: 5.1.0 - resolution: "@rjsf/validator-ajv8@npm:5.1.0" +"@rjsf/validator-ajv8@npm:5.3.1": + version: 5.3.1 + resolution: "@rjsf/validator-ajv8@npm:5.3.1" dependencies: ajv: ^8.12.0 ajv-formats: ^2.1.1 @@ -12982,19 +13222,19 @@ __metadata: lodash-es: ^4.17.15 peerDependencies: "@rjsf/utils": ^5.0.0 - checksum: 3430a0aea8235deedd306b535ea3a62a9bcdd4dcf0bf1d022fe036041dceb5ca7c147b17ae50a0d25bb7c953729e987d96c68f5220f8fde4b56a89cf3f106a49 + checksum: b99e0d2df6b6431438ea81c2e31636aa5a1939d054153236851e5d8e8b06f8a1958c8c16887dd2babfd1608e18aa1ce3f1c0a778b3b3198028b92f0553e0383e languageName: node linkType: hard "@roadiehq/backstage-plugin-buildkite@npm:^2.0.8": - version: 2.1.6 - resolution: "@roadiehq/backstage-plugin-buildkite@npm:2.1.6" + version: 2.1.7 + resolution: "@roadiehq/backstage-plugin-buildkite@npm:2.1.7" dependencies: - "@backstage/catalog-model": ^1.2.0 - "@backstage/core-components": ^0.12.4 - "@backstage/core-plugin-api": ^1.4.0 - "@backstage/plugin-catalog-react": ^1.3.0 - "@backstage/theme": ^0.2.17 + "@backstage/catalog-model": ^1.2.1 + "@backstage/core-components": ^0.12.5 + "@backstage/core-plugin-api": ^1.5.0 + "@backstage/plugin-catalog-react": ^1.4.0 + "@backstage/theme": ^0.2.18 "@material-ui/core": ^4.12.1 "@material-ui/icons": ^4.11.2 "@material-ui/lab": 4.0.0-alpha.57 @@ -13006,20 +13246,20 @@ __metadata: react-dom: ^16.13.1 || ^17.0.0 react-router: 6.0.0-beta.0 || ^6.3.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 - checksum: 90d8ea1c3379f04e98a992e4192aeb46ea394a8970e50c9ffdf24171e731f4108b0117596b877ec0ff8d12434ca513ba566d957a71d9584cc12b2e097abb0b3f + checksum: 1b84acf97e22f3b481d4b4fbc1ccb1d184f811ec00998b92cc8ee6f4be95af2acebd9932ad4337c611d17ca15f8c34cd44310a44d775008a1d845fe1a197ae37 languageName: node linkType: hard "@roadiehq/backstage-plugin-github-insights@npm:^2.0.5": - version: 2.3.7 - resolution: "@roadiehq/backstage-plugin-github-insights@npm:2.3.7" + version: 2.3.8 + resolution: "@roadiehq/backstage-plugin-github-insights@npm:2.3.8" dependencies: - "@backstage/catalog-model": ^1.2.0 - "@backstage/core-components": ^0.12.4 - "@backstage/core-plugin-api": ^1.4.0 - "@backstage/integration-react": ^1.1.10 - "@backstage/plugin-catalog-react": ^1.3.0 - "@backstage/theme": ^0.2.17 + "@backstage/catalog-model": ^1.2.1 + "@backstage/core-components": ^0.12.5 + "@backstage/core-plugin-api": ^1.5.0 + "@backstage/integration-react": ^1.1.11 + "@backstage/plugin-catalog-react": ^1.4.0 + "@backstage/theme": ^0.2.18 "@date-io/core": 2.10.7 "@material-ui/core": ^4.11.0 "@material-ui/icons": ^4.9.1 @@ -13034,19 +13274,19 @@ __metadata: react: ^16.13.1 || ^17.0.0 react-dom: ^16.13.1 || ^17.0.0 react-router: 6.0.0-beta.0 || ^6.3.0 - checksum: 0818a109c6ebbcc312f1a9f6575cd8d47f7adec6201d3555cfc1ad2d25c5f80ff08ad26eee692a40d059283c7b3dadbb5a6533802318a8ae5c781c1fcaaf077d + checksum: 0a9027a035d41e46344d88da361ec91fbf43adb018bb9e383e5659d4478b67951ef9e32381b020a2104bf16be5009ae7e97c07182dcbe04721d6385e93ec8ce2 languageName: node linkType: hard "@roadiehq/backstage-plugin-github-pull-requests@npm:^2.2.7": - version: 2.5.2 - resolution: "@roadiehq/backstage-plugin-github-pull-requests@npm:2.5.2" + version: 2.5.5 + resolution: "@roadiehq/backstage-plugin-github-pull-requests@npm:2.5.5" dependencies: - "@backstage/catalog-model": ^1.1.5 - "@backstage/core-components": ^0.12.3 - "@backstage/core-plugin-api": ^1.3.0 - "@backstage/plugin-catalog-react": ^1.2.4 - "@backstage/plugin-home": ^0.4.30 + "@backstage/catalog-model": ^1.2.1 + "@backstage/core-components": ^0.12.5 + "@backstage/core-plugin-api": ^1.5.0 + "@backstage/plugin-catalog-react": ^1.4.0 + "@backstage/plugin-home": ^0.4.32 "@material-ui/core": ^4.11.0 "@material-ui/icons": ^4.9.1 "@material-ui/lab": ^4.0.0-alpha.60 @@ -13063,19 +13303,19 @@ __metadata: react: ^16.13.1 || ^17.0.0 react-dom: ^16.13.1 || ^17.0.0 react-router: 6.0.0-beta.0 || ^6.3.0 - checksum: dd8c3301867cd8ccaf094eb62c64b2923c4614e9ba384249c5ddb80b6375bc7f5e8828a7fc12f9e7785ca230948895e03a9c1521be45f69797f663b28cecc3c7 + checksum: 3a17a21665c397b3bd94c277e31b9f1005387b458a14b1c4c3bd28f6ef1400289fcf24e44bb8c54e07b99b59af49fe608c587f49e27d15cf01ef4d539cc25354 languageName: node linkType: hard "@roadiehq/backstage-plugin-travis-ci@npm:^2.0.5": - version: 2.1.6 - resolution: "@roadiehq/backstage-plugin-travis-ci@npm:2.1.6" + version: 2.1.7 + resolution: "@roadiehq/backstage-plugin-travis-ci@npm:2.1.7" dependencies: - "@backstage/catalog-model": ^1.2.0 - "@backstage/core-components": ^0.12.4 - "@backstage/core-plugin-api": ^1.4.0 - "@backstage/plugin-catalog-react": ^1.3.0 - "@backstage/theme": ^0.2.17 + "@backstage/catalog-model": ^1.2.1 + "@backstage/core-components": ^0.12.5 + "@backstage/core-plugin-api": ^1.5.0 + "@backstage/plugin-catalog-react": ^1.4.0 + "@backstage/theme": ^0.2.18 "@material-ui/core": ^4.11.3 "@material-ui/icons": ^4.11.2 "@material-ui/lab": 4.0.0-alpha.57 @@ -13089,7 +13329,7 @@ __metadata: react-dom: ^16.13.1 || ^17.0.0 react-router: 6.0.0-beta.0 || ^6.3.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 - checksum: 657e58579bdc9387edb61538f4541be4ba2b33f33fcac9129f533b35dc6d207d9930e0eae0937435def7ebf5e791118727417d818dd96de05126bda1041f15d1 + checksum: 1a00d0128e1bdacac93ffa7b1aa1534ec91b603899d40967ed387e3fd91f35bbc5f9babfc7b811279775d60e28db7747211fd5c0d368db23b5a184b054e918c1 languageName: node linkType: hard @@ -13605,90 +13845,455 @@ __metadata: languageName: node linkType: hard -"@swc/core-darwin-arm64@npm:1.3.38": - version: 1.3.38 - resolution: "@swc/core-darwin-arm64@npm:1.3.38" +"@swagger-api/apidom-ast@npm:^0.69.0": + version: 0.69.0 + resolution: "@swagger-api/apidom-ast@npm:0.69.0" + dependencies: + "@babel/runtime-corejs3": ^7.20.7 + "@types/ramda": =0.28.23 + ramda: =0.28.0 + ramda-adjunct: =3.4.0 + stampit: =4.3.2 + unraw: =2.0.1 + checksum: 59625e7f3543766d901227d9afec0ebce0cc1368cc63d22ad5f348a9da0b3777ea83acce7eb0eecdbe6210022f3bf0fafdb46d59b0e90d630ad55c428ede14a2 + languageName: node + linkType: hard + +"@swagger-api/apidom-core@npm:=0.69.0, @swagger-api/apidom-core@npm:^0.69.0": + version: 0.69.0 + resolution: "@swagger-api/apidom-core@npm:0.69.0" + dependencies: + "@babel/runtime-corejs3": ^7.20.7 + "@swagger-api/apidom-ast": ^0.69.0 + "@types/ramda": =0.28.23 + minim: =0.23.8 + ramda: =0.28.0 + ramda-adjunct: =3.4.0 + short-unique-id: =4.4.4 + stampit: =4.3.2 + checksum: 036dc1198014fff9d7e879529186c4b0db423ae4c933eecec90650985e198cb3745638feff8681f85940f124703484d1b071dfca4eaf7b9457a4f99186c98972 + languageName: node + linkType: hard + +"@swagger-api/apidom-json-pointer@npm:=0.69.0, @swagger-api/apidom-json-pointer@npm:^0.69.0": + version: 0.69.0 + resolution: "@swagger-api/apidom-json-pointer@npm:0.69.0" + dependencies: + "@babel/runtime-corejs3": ^7.20.7 + "@swagger-api/apidom-core": ^0.69.0 + "@types/ramda": =0.28.23 + ramda: =0.28.0 + ramda-adjunct: =3.4.0 + checksum: 7930d938011c608d5c227c3b1cbfcb120eeebd32aedd447220219b079d030af6387a9a61e74461fe53578c06ba29aa78e5e5fdfcd561d5611d5a07ef5534ee49 + languageName: node + linkType: hard + +"@swagger-api/apidom-ns-api-design-systems@npm:^0.69.0": + version: 0.69.0 + resolution: "@swagger-api/apidom-ns-api-design-systems@npm:0.69.0" + dependencies: + "@babel/runtime-corejs3": ^7.20.7 + "@swagger-api/apidom-core": ^0.69.0 + "@swagger-api/apidom-ns-openapi-3-1": ^0.69.0 + "@types/ramda": =0.28.23 + ramda: =0.28.0 + ramda-adjunct: =3.4.0 + stampit: =4.3.2 + checksum: 1c3047d4081cd07bbbdce6fa19c62407d1c57f7bf05b85947fd1e9b3cc2c2792fb85a926a54d3376c761a123ce3b130b06e38830ca68743a20c684aae89275f1 + languageName: node + linkType: hard + +"@swagger-api/apidom-ns-asyncapi-2@npm:^0.69.0": + version: 0.69.0 + resolution: "@swagger-api/apidom-ns-asyncapi-2@npm:0.69.0" + dependencies: + "@babel/runtime-corejs3": ^7.20.7 + "@swagger-api/apidom-core": ^0.69.0 + "@swagger-api/apidom-ns-json-schema-draft-7": ^0.69.0 + "@types/ramda": =0.28.23 + ramda: =0.28.0 + ramda-adjunct: =3.4.0 + stampit: =4.3.2 + checksum: c5b9161166ddce0be047a474e7257520a756ed3fe426b806c19122334535d07b48529be60638dd560ab6ff23899641cee1110932cad16b4bf93f8fbe8f52ca05 + languageName: node + linkType: hard + +"@swagger-api/apidom-ns-json-schema-draft-4@npm:^0.69.0": + version: 0.69.0 + resolution: "@swagger-api/apidom-ns-json-schema-draft-4@npm:0.69.0" + dependencies: + "@babel/runtime-corejs3": ^7.20.7 + "@swagger-api/apidom-core": ^0.69.0 + "@types/ramda": =0.28.23 + ramda: =0.28.0 + ramda-adjunct: =3.4.0 + stampit: =4.3.2 + checksum: d308227f5849071be3481bd8d4a8dc16d0e9e99edb61250927da88ed34595d176d59792003a2a666a49585643ff659a16774826790aab718a316beda9ce617c3 + languageName: node + linkType: hard + +"@swagger-api/apidom-ns-json-schema-draft-6@npm:^0.69.0": + version: 0.69.0 + resolution: "@swagger-api/apidom-ns-json-schema-draft-6@npm:0.69.0" + dependencies: + "@babel/runtime-corejs3": ^7.20.7 + "@swagger-api/apidom-core": ^0.69.0 + "@swagger-api/apidom-ns-json-schema-draft-4": ^0.69.0 + "@types/ramda": =0.28.23 + ramda: =0.28.0 + ramda-adjunct: =3.4.0 + stampit: =4.3.2 + checksum: df237753d0c9aa7d22029c22b5355310a14aa7a77aa484cc86d46850bd994db3f0901804510a6c62196e181c150e15fc7a031b97f0f45983b6f819fb7ed71ccb + languageName: node + linkType: hard + +"@swagger-api/apidom-ns-json-schema-draft-7@npm:^0.69.0": + version: 0.69.0 + resolution: "@swagger-api/apidom-ns-json-schema-draft-7@npm:0.69.0" + dependencies: + "@babel/runtime-corejs3": ^7.20.7 + "@swagger-api/apidom-core": ^0.69.0 + "@swagger-api/apidom-ns-json-schema-draft-6": ^0.69.0 + "@types/ramda": =0.28.23 + ramda: =0.28.0 + ramda-adjunct: =3.4.0 + stampit: =4.3.2 + checksum: a2059092cfb1797c90b15384270df65fadd6d1e8b469350082ab46d25a1840fd05ff0bea72a8005068f77ab277a049110962a15f1fbeeac63b9c0a34d21d78c2 + languageName: node + linkType: hard + +"@swagger-api/apidom-ns-openapi-3-0@npm:^0.69.0": + version: 0.69.0 + resolution: "@swagger-api/apidom-ns-openapi-3-0@npm:0.69.0" + dependencies: + "@babel/runtime-corejs3": ^7.20.7 + "@swagger-api/apidom-core": ^0.69.0 + "@swagger-api/apidom-ns-json-schema-draft-4": ^0.69.0 + "@types/ramda": =0.28.23 + ramda: =0.28.0 + ramda-adjunct: =3.4.0 + stampit: =4.3.2 + checksum: e53bda9fada416e23a5220dd8987b3e4082b3020e3db40c5532fdd454aaa02953d4d72223fd0372897b0a6a73b321f89e83504d60bb8b52fa4fbcdfb5f097e59 + languageName: node + linkType: hard + +"@swagger-api/apidom-ns-openapi-3-1@npm:=0.69.0, @swagger-api/apidom-ns-openapi-3-1@npm:^0.69.0": + version: 0.69.0 + resolution: "@swagger-api/apidom-ns-openapi-3-1@npm:0.69.0" + dependencies: + "@babel/runtime-corejs3": ^7.20.7 + "@swagger-api/apidom-core": ^0.69.0 + "@swagger-api/apidom-ns-openapi-3-0": ^0.69.0 + "@types/ramda": =0.28.23 + ramda: =0.28.0 + ramda-adjunct: =3.4.0 + stampit: =4.3.2 + checksum: 7f194ebb36891655fdcd8dfe88e664e70f6efcd713ac6defc75dadefb0087d3fd0358b656dec4920d876342d23c44ff1cee034fa32cfa1f8b3d49ceba9509dbb + languageName: node + linkType: hard + +"@swagger-api/apidom-parser-adapter-api-design-systems-json@npm:^0.69.0": + version: 0.69.0 + resolution: "@swagger-api/apidom-parser-adapter-api-design-systems-json@npm:0.69.0" + dependencies: + "@babel/runtime-corejs3": ^7.20.7 + "@swagger-api/apidom-core": ^0.69.0 + "@swagger-api/apidom-ns-api-design-systems": ^0.69.0 + "@swagger-api/apidom-parser-adapter-json": ^0.69.0 + "@types/ramda": =0.28.23 + ramda: =0.28.0 + ramda-adjunct: =3.4.0 + checksum: 68b43e19effd7b9c26e52381903a39fff7ef0990ad3cbcbf4aa7de01cf3454d915dc10d8f688aa0fa4405b11f1a6d8f49bc160e6b72c482fadb484bd787bdebd + languageName: node + linkType: hard + +"@swagger-api/apidom-parser-adapter-api-design-systems-yaml@npm:^0.69.0": + version: 0.69.0 + resolution: "@swagger-api/apidom-parser-adapter-api-design-systems-yaml@npm:0.69.0" + dependencies: + "@babel/runtime-corejs3": ^7.20.7 + "@swagger-api/apidom-core": ^0.69.0 + "@swagger-api/apidom-ns-api-design-systems": ^0.69.0 + "@swagger-api/apidom-parser-adapter-yaml-1-2": ^0.69.0 + "@types/ramda": =0.28.23 + ramda: =0.28.0 + ramda-adjunct: =3.4.0 + checksum: 6ded590b93087ad4b848ba4f742c6baeb35a572195d763a1ae0b479b8de4ae7d331175d5042116dab26684413ca6a58680080fb4b28ca5c66c7d72d6e624e174 + languageName: node + linkType: hard + +"@swagger-api/apidom-parser-adapter-asyncapi-json-2@npm:^0.69.0": + version: 0.69.0 + resolution: "@swagger-api/apidom-parser-adapter-asyncapi-json-2@npm:0.69.0" + dependencies: + "@babel/runtime-corejs3": ^7.20.7 + "@swagger-api/apidom-core": ^0.69.0 + "@swagger-api/apidom-ns-asyncapi-2": ^0.69.0 + "@swagger-api/apidom-parser-adapter-json": ^0.69.0 + "@types/ramda": =0.28.23 + ramda: =0.28.0 + ramda-adjunct: =3.4.0 + checksum: c13b4ea5a603d7422ebf4dd87851a72a999c0036ff451b080cd37b96aa1b455f6483c447e4962303af52b44ac0fca3517573dfeeddbdb7f8d04cb7ff8796089f + languageName: node + linkType: hard + +"@swagger-api/apidom-parser-adapter-asyncapi-yaml-2@npm:^0.69.0": + version: 0.69.0 + resolution: "@swagger-api/apidom-parser-adapter-asyncapi-yaml-2@npm:0.69.0" + dependencies: + "@babel/runtime-corejs3": ^7.20.7 + "@swagger-api/apidom-core": ^0.69.0 + "@swagger-api/apidom-ns-asyncapi-2": ^0.69.0 + "@swagger-api/apidom-parser-adapter-yaml-1-2": ^0.69.0 + "@types/ramda": =0.28.23 + ramda: =0.28.0 + ramda-adjunct: =3.4.0 + checksum: f3415e86371f98e3677d22f432214f4b4e2267b80da2f505ed28d89c711fa32a627cea94040c6071e83d2ea3cf6aabc454331951d2fd3bcc138b091e78286423 + languageName: node + linkType: hard + +"@swagger-api/apidom-parser-adapter-json@npm:^0.69.0": + version: 0.69.0 + resolution: "@swagger-api/apidom-parser-adapter-json@npm:0.69.0" + dependencies: + "@babel/runtime-corejs3": ^7.20.7 + "@swagger-api/apidom-ast": ^0.69.0 + "@swagger-api/apidom-core": ^0.69.0 + "@types/ramda": =0.28.23 + node-gyp: latest + ramda: =0.28.0 + ramda-adjunct: =3.4.0 + stampit: =4.3.2 + tree-sitter: =0.20.1 + tree-sitter-json: =0.20.0 + web-tree-sitter: =0.20.7 + checksum: e640ffbf749285f70ea4d125cbb030ff9920b011e8694e3cd5c379b3a6f3f387805c9535af7786c2bed6f0f67bfd9f6daad6eb65a64ca76b48b45f283933f4d5 + languageName: node + linkType: hard + +"@swagger-api/apidom-parser-adapter-openapi-json-3-0@npm:^0.69.0": + version: 0.69.0 + resolution: "@swagger-api/apidom-parser-adapter-openapi-json-3-0@npm:0.69.0" + dependencies: + "@babel/runtime-corejs3": ^7.20.7 + "@swagger-api/apidom-core": ^0.69.0 + "@swagger-api/apidom-ns-openapi-3-0": ^0.69.0 + "@swagger-api/apidom-parser-adapter-json": ^0.69.0 + "@types/ramda": =0.28.23 + ramda: =0.28.0 + ramda-adjunct: =3.4.0 + checksum: 50c61b46d16ed2a24816665ee810c295f6e82cad8a031ebc91d91aa3650bae92ddcede99ceea4346dcb69ca6edd811213018ebe8b23929012c08b425103a807d + languageName: node + linkType: hard + +"@swagger-api/apidom-parser-adapter-openapi-json-3-1@npm:^0.69.0": + version: 0.69.0 + resolution: "@swagger-api/apidom-parser-adapter-openapi-json-3-1@npm:0.69.0" + dependencies: + "@babel/runtime-corejs3": ^7.20.7 + "@swagger-api/apidom-core": ^0.69.0 + "@swagger-api/apidom-ns-openapi-3-1": ^0.69.0 + "@swagger-api/apidom-parser-adapter-json": ^0.69.0 + "@types/ramda": =0.28.23 + ramda: =0.28.0 + ramda-adjunct: =3.4.0 + checksum: 9c657b1eb82814958ed2b2c4e710a51378cbb11ca6957d0cc57ec544e0cba4a3bac412475f923e47c1fff8130f5a42cf8edcd99080703316150de8f1b30891b8 + languageName: node + linkType: hard + +"@swagger-api/apidom-parser-adapter-openapi-yaml-3-0@npm:^0.69.0": + version: 0.69.0 + resolution: "@swagger-api/apidom-parser-adapter-openapi-yaml-3-0@npm:0.69.0" + dependencies: + "@babel/runtime-corejs3": ^7.20.7 + "@swagger-api/apidom-core": ^0.69.0 + "@swagger-api/apidom-ns-openapi-3-0": ^0.69.0 + "@swagger-api/apidom-parser-adapter-yaml-1-2": ^0.69.0 + "@types/ramda": =0.28.23 + ramda: =0.28.0 + ramda-adjunct: =3.4.0 + checksum: ee32fc65e053ccda7eae265ad1a43e5acd0688460620912363156ada3babf3115fbec0dd35423ca633aaf78e9e4ed71ee4be030385cfdcc9ed69e8438319cc19 + languageName: node + linkType: hard + +"@swagger-api/apidom-parser-adapter-openapi-yaml-3-1@npm:^0.69.0": + version: 0.69.0 + resolution: "@swagger-api/apidom-parser-adapter-openapi-yaml-3-1@npm:0.69.0" + dependencies: + "@babel/runtime-corejs3": ^7.20.7 + "@swagger-api/apidom-core": ^0.69.0 + "@swagger-api/apidom-ns-openapi-3-1": ^0.69.0 + "@swagger-api/apidom-parser-adapter-yaml-1-2": ^0.69.0 + "@types/ramda": =0.28.23 + ramda: =0.28.0 + ramda-adjunct: =3.4.0 + checksum: c21f6ad4b149f64bb5af24d7d7ba5bd8342c2ab2e0e37d85617ca0d4d3333ee45a4603ce7cdca460d4dcb17c6d41b47f733390d3ef6754664ae11705a628fe9c + languageName: node + linkType: hard + +"@swagger-api/apidom-parser-adapter-yaml-1-2@npm:^0.69.0": + version: 0.69.0 + resolution: "@swagger-api/apidom-parser-adapter-yaml-1-2@npm:0.69.0" + dependencies: + "@babel/runtime-corejs3": ^7.20.7 + "@swagger-api/apidom-ast": ^0.69.0 + "@swagger-api/apidom-core": ^0.69.0 + "@types/ramda": =0.28.23 + node-gyp: latest + ramda: =0.28.0 + ramda-adjunct: =3.4.0 + stampit: =4.3.2 + tree-sitter: =0.20.1 + tree-sitter-yaml: =0.5.0 + web-tree-sitter: =0.20.7 + checksum: 6067347f6ab9d2cfbbe55f13345609c86b1660bebb7cea215c90739eab011498695d785bc7bb75fc95055ea98bafc765bbc0d304ad19f72647b72ee4308d249e + languageName: node + linkType: hard + +"@swagger-api/apidom-reference@npm:=0.69.0": + version: 0.69.0 + resolution: "@swagger-api/apidom-reference@npm:0.69.0" + dependencies: + "@babel/runtime-corejs3": ^7.20.7 + "@swagger-api/apidom-core": ^0.69.0 + "@swagger-api/apidom-json-pointer": ^0.69.0 + "@swagger-api/apidom-ns-asyncapi-2": ^0.69.0 + "@swagger-api/apidom-ns-openapi-3-0": ^0.69.0 + "@swagger-api/apidom-ns-openapi-3-1": ^0.69.0 + "@swagger-api/apidom-parser-adapter-api-design-systems-json": ^0.69.0 + "@swagger-api/apidom-parser-adapter-api-design-systems-yaml": ^0.69.0 + "@swagger-api/apidom-parser-adapter-asyncapi-json-2": ^0.69.0 + "@swagger-api/apidom-parser-adapter-asyncapi-yaml-2": ^0.69.0 + "@swagger-api/apidom-parser-adapter-json": ^0.69.0 + "@swagger-api/apidom-parser-adapter-openapi-json-3-0": ^0.69.0 + "@swagger-api/apidom-parser-adapter-openapi-json-3-1": ^0.69.0 + "@swagger-api/apidom-parser-adapter-openapi-yaml-3-0": ^0.69.0 + "@swagger-api/apidom-parser-adapter-openapi-yaml-3-1": ^0.69.0 + "@swagger-api/apidom-parser-adapter-yaml-1-2": ^0.69.0 + "@types/ramda": =0.28.23 + axios: =1.3.4 + minimatch: =7.3.0 + process: =0.11.10 + ramda: =0.28.0 + ramda-adjunct: =3.4.0 + stampit: =4.3.2 + dependenciesMeta: + "@swagger-api/apidom-json-pointer": + optional: true + "@swagger-api/apidom-ns-asyncapi-2": + optional: true + "@swagger-api/apidom-ns-openapi-3-0": + optional: true + "@swagger-api/apidom-ns-openapi-3-1": + optional: true + "@swagger-api/apidom-parser-adapter-api-design-systems-json": + optional: true + "@swagger-api/apidom-parser-adapter-api-design-systems-yaml": + optional: true + "@swagger-api/apidom-parser-adapter-asyncapi-json-2": + optional: true + "@swagger-api/apidom-parser-adapter-asyncapi-yaml-2": + optional: true + "@swagger-api/apidom-parser-adapter-json": + optional: true + "@swagger-api/apidom-parser-adapter-openapi-json-3-0": + optional: true + "@swagger-api/apidom-parser-adapter-openapi-json-3-1": + optional: true + "@swagger-api/apidom-parser-adapter-openapi-yaml-3-0": + optional: true + "@swagger-api/apidom-parser-adapter-openapi-yaml-3-1": + optional: true + "@swagger-api/apidom-parser-adapter-yaml-1-2": + optional: true + checksum: f176e51e64377c09449e9f5bf50438be7a05fa63d4ff2f9ec5c45cf0722439537aafbe4804e2197661a652cec013c1aaa78f6a2a7ac4f6d63083aa07875c8671 + languageName: node + linkType: hard + +"@swc/core-darwin-arm64@npm:1.3.42": + version: 1.3.42 + resolution: "@swc/core-darwin-arm64@npm:1.3.42" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@swc/core-darwin-x64@npm:1.3.38": - version: 1.3.38 - resolution: "@swc/core-darwin-x64@npm:1.3.38" +"@swc/core-darwin-x64@npm:1.3.42": + version: 1.3.42 + resolution: "@swc/core-darwin-x64@npm:1.3.42" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@swc/core-linux-arm-gnueabihf@npm:1.3.38": - version: 1.3.38 - resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.38" +"@swc/core-linux-arm-gnueabihf@npm:1.3.42": + version: 1.3.42 + resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.42" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@swc/core-linux-arm64-gnu@npm:1.3.38": - version: 1.3.38 - resolution: "@swc/core-linux-arm64-gnu@npm:1.3.38" +"@swc/core-linux-arm64-gnu@npm:1.3.42": + version: 1.3.42 + resolution: "@swc/core-linux-arm64-gnu@npm:1.3.42" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-arm64-musl@npm:1.3.38": - version: 1.3.38 - resolution: "@swc/core-linux-arm64-musl@npm:1.3.38" +"@swc/core-linux-arm64-musl@npm:1.3.42": + version: 1.3.42 + resolution: "@swc/core-linux-arm64-musl@npm:1.3.42" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@swc/core-linux-x64-gnu@npm:1.3.38": - version: 1.3.38 - resolution: "@swc/core-linux-x64-gnu@npm:1.3.38" +"@swc/core-linux-x64-gnu@npm:1.3.42": + version: 1.3.42 + resolution: "@swc/core-linux-x64-gnu@npm:1.3.42" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-x64-musl@npm:1.3.38": - version: 1.3.38 - resolution: "@swc/core-linux-x64-musl@npm:1.3.38" +"@swc/core-linux-x64-musl@npm:1.3.42": + version: 1.3.42 + resolution: "@swc/core-linux-x64-musl@npm:1.3.42" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@swc/core-win32-arm64-msvc@npm:1.3.38": - version: 1.3.38 - resolution: "@swc/core-win32-arm64-msvc@npm:1.3.38" +"@swc/core-win32-arm64-msvc@npm:1.3.42": + version: 1.3.42 + resolution: "@swc/core-win32-arm64-msvc@npm:1.3.42" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@swc/core-win32-ia32-msvc@npm:1.3.38": - version: 1.3.38 - resolution: "@swc/core-win32-ia32-msvc@npm:1.3.38" +"@swc/core-win32-ia32-msvc@npm:1.3.42": + version: 1.3.42 + resolution: "@swc/core-win32-ia32-msvc@npm:1.3.42" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@swc/core-win32-x64-msvc@npm:1.3.38": - version: 1.3.38 - resolution: "@swc/core-win32-x64-msvc@npm:1.3.38" +"@swc/core-win32-x64-msvc@npm:1.3.42": + version: 1.3.42 + resolution: "@swc/core-win32-x64-msvc@npm:1.3.42" conditions: os=win32 & cpu=x64 languageName: node linkType: hard "@swc/core@npm:^1.3.9": - version: 1.3.38 - resolution: "@swc/core@npm:1.3.38" + version: 1.3.42 + resolution: "@swc/core@npm:1.3.42" dependencies: - "@swc/core-darwin-arm64": 1.3.38 - "@swc/core-darwin-x64": 1.3.38 - "@swc/core-linux-arm-gnueabihf": 1.3.38 - "@swc/core-linux-arm64-gnu": 1.3.38 - "@swc/core-linux-arm64-musl": 1.3.38 - "@swc/core-linux-x64-gnu": 1.3.38 - "@swc/core-linux-x64-musl": 1.3.38 - "@swc/core-win32-arm64-msvc": 1.3.38 - "@swc/core-win32-ia32-msvc": 1.3.38 - "@swc/core-win32-x64-msvc": 1.3.38 + "@swc/core-darwin-arm64": 1.3.42 + "@swc/core-darwin-x64": 1.3.42 + "@swc/core-linux-arm-gnueabihf": 1.3.42 + "@swc/core-linux-arm64-gnu": 1.3.42 + "@swc/core-linux-arm64-musl": 1.3.42 + "@swc/core-linux-x64-gnu": 1.3.42 + "@swc/core-linux-x64-musl": 1.3.42 + "@swc/core-win32-arm64-msvc": 1.3.42 + "@swc/core-win32-ia32-msvc": 1.3.42 + "@swc/core-win32-x64-msvc": 1.3.42 dependenciesMeta: "@swc/core-darwin-arm64": optional: true @@ -13710,7 +14315,7 @@ __metadata: optional: true "@swc/core-win32-x64-msvc": optional: true - checksum: c55d30e57638bcd21f788add8490c3f3e71bfe027aa5a8b153e1b1b9686ecddd6deeaaa6a6b17717c7eab4c1e2a232b465b6755b6c891506fc0d03139badfbf7 + checksum: 5c28c03ee6a4e1f630c4a519b56d7e23a0102f70fad977a3ab144a3da96231cf4849e473cdc9ee7be6b9266ba0838d0bc0b6b3575a75540f302befe96cc9606e languageName: node linkType: hard @@ -13744,18 +14349,18 @@ __metadata: languageName: node linkType: hard -"@tanstack/query-core@npm:4.24.10": - version: 4.24.10 - resolution: "@tanstack/query-core@npm:4.24.10" - checksum: 8268b9dca4a2ed39f8575976d8a3e2f839bb6f4fb821dc00ba8e2aeffffe2f73e23344bcc24b9cb6dae9dbfe3ba2b14c76a1e0a38b4064c83beb9aa607fd94bc +"@tanstack/query-core@npm:4.27.0": + version: 4.27.0 + resolution: "@tanstack/query-core@npm:4.27.0" + checksum: 914b4f01ac75632f4603b650e9105f64c739b79250baf76aad16cee216f7bad6060c04eda0c70838fe61a5f6c17883e19fcc3075b2433a906539da95ce785796 languageName: node linkType: hard "@tanstack/react-query@npm:^4.1.3": - version: 4.24.10 - resolution: "@tanstack/react-query@npm:4.24.10" + version: 4.28.0 + resolution: "@tanstack/react-query@npm:4.28.0" dependencies: - "@tanstack/query-core": 4.24.10 + "@tanstack/query-core": 4.27.0 use-sync-external-store: ^1.2.0 peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -13766,7 +14371,7 @@ __metadata: optional: true react-native: optional: true - checksum: 576a2c73e98cf6a3c9584283989383d5ac63b01efe546cc7580ec7b1edf0c0cb8958a3071778cb0af908f5269d45c7516fa388e5f856e37f5b2d3c6110974cbe + checksum: 7baa70d22b55cfa22f8a1d92ba9f8379c5436ee81fce3f0e7df4a8c29bb26bfef4a83759cf10f752b40ae2940099fcce88ce91a773240f4999ae91136980c6e3 languageName: node linkType: hard @@ -13793,6 +14398,7 @@ __metadata: dockerode: ^3.3.1 find-process: ^1.4.5 fs-extra: ^10.0.1 + global-agent: ^3.0.0 http-proxy: ^1.18.1 nodemon: ^2.0.2 react-dev-utils: ^12.0.0-next.60 @@ -13975,15 +14581,6 @@ __metadata: languageName: node linkType: hard -"@types/accepts@npm:^1.3.5": - version: 1.3.5 - resolution: "@types/accepts@npm:1.3.5" - dependencies: - "@types/node": "*" - checksum: 590b7580570534a640510c071e09074cf63b5958b237a728f94322567350aea4d239f8a9d897a12b15c856b992ee4d7907e9812bb079886af2c00714e7fb3f60 - languageName: node - linkType: hard - "@types/ansi-regex@npm:^5.0.0": version: 5.0.0 resolution: "@types/ansi-regex@npm:5.0.0" @@ -14082,7 +14679,7 @@ __metadata: languageName: node linkType: hard -"@types/body-parser@npm:*, @types/body-parser@npm:1.19.2, @types/body-parser@npm:^1.19.0": +"@types/body-parser@npm:*, @types/body-parser@npm:^1.19.0": version: 1.19.2 resolution: "@types/body-parser@npm:1.19.2" dependencies: @@ -14253,13 +14850,6 @@ __metadata: languageName: node linkType: hard -"@types/cors@npm:2.8.12": - version: 2.8.12 - resolution: "@types/cors@npm:2.8.12" - checksum: 8c45f112c7d1d2d831b4b266f2e6ed33a1887a35dcbfe2a18b28370751fababb7cd045e745ef84a523c33a25932678097bf79afaa367c6cb3fa0daa7a6438257 - languageName: node - linkType: hard - "@types/cors@npm:^2.8.6": version: 2.8.13 resolution: "@types/cors@npm:2.8.13" @@ -14270,12 +14860,12 @@ __metadata: linkType: hard "@types/cron@npm:^2.0.0": - version: 2.0.0 - resolution: "@types/cron@npm:2.0.0" + version: 2.0.1 + resolution: "@types/cron@npm:2.0.1" dependencies: "@types/luxon": "*" "@types/node": "*" - checksum: 392d2cfca51504140397533c30be8facd2196251074eb26ee09232a7e983144ff1d8364cd64922ed22d142686a4724934a70672fc8353b441fea729ac0ed0611 + checksum: 4268c784750a1373036b4de95cd1f35ab4fa5227c1639302eedb25a35900d7805271e33b557ad7ccccd6d1829944963df25cd0d9d0d603abf3bcdf148b69ea5d languageName: node linkType: hard @@ -14358,9 +14948,9 @@ __metadata: linkType: hard "@types/d3-selection@npm:*, @types/d3-selection@npm:^3.0.1": - version: 3.0.4 - resolution: "@types/d3-selection@npm:3.0.4" - checksum: b1e486db7f020610c854996a96b2f59a43b89d48bc7ac2ef9479f6f6e6324d3b21d7dfc8031a0b6d049a84b769b14eca65d73fc42613ab0044ef67973a9fe6ca + version: 3.0.5 + resolution: "@types/d3-selection@npm:3.0.5" + checksum: 77ea35c92273cd2d736355ab5a4cf6477086b064a1f608489a6fef4198ee6bc1d5440e5dfd880099265ac96c4f4b4fda659d89fbaaef37ba03708663196ba8ad languageName: node linkType: hard @@ -14425,9 +15015,9 @@ __metadata: linkType: hard "@types/diff@npm:^5.0.0": - version: 5.0.2 - resolution: "@types/diff@npm:5.0.2" - checksum: 8fbc419b5aca33f494026bf5f70e026f76367689677ef114f9c078ac738d7dbe96e6dda3fd8290e4a7c35281e2b60b034e3d7e3c968b850cf06a21279e7ddcbe + version: 5.0.3 + resolution: "@types/diff@npm:5.0.3" + checksum: d8a7d4de12f1aba0bd0c17b0b0d1e45c83824d3d6cc65763fbad371cd8315361a7e16fbae3f260a83bfdf30cebe1c876b42cec4518698055bc430fb09db1cbc8 languageName: node linkType: hard @@ -14442,12 +15032,12 @@ __metadata: linkType: hard "@types/dockerode@npm:^3.3.0, @types/dockerode@npm:^3.3.8": - version: 3.3.14 - resolution: "@types/dockerode@npm:3.3.14" + version: 3.3.15 + resolution: "@types/dockerode@npm:3.3.15" dependencies: "@types/docker-modem": "*" "@types/node": "*" - checksum: 6a8472622861fb0c97908963a8236d6e439c9feefc845b866326272ad0e5c33f537206fb4633424c5e3c8ec63559cb14bc737e2f88f0fcdf11496a9162d5b139 + checksum: b8fa13f86c761175a5813eb41fbd1e46d0646f008e5c84738b51c1aa82ce4f3758502efe8c3c583463e7cb7dc77e2faadfff91f4e6274e844e68a0ebf9deeae5 languageName: node linkType: hard @@ -14515,7 +15105,7 @@ __metadata: languageName: node linkType: hard -"@types/express-serve-static-core@npm:*, @types/express-serve-static-core@npm:^4.17.18, @types/express-serve-static-core@npm:^4.17.31, @types/express-serve-static-core@npm:^4.17.5": +"@types/express-serve-static-core@npm:*, @types/express-serve-static-core@npm:^4.17.30, @types/express-serve-static-core@npm:^4.17.33, @types/express-serve-static-core@npm:^4.17.5": version: 4.17.33 resolution: "@types/express-serve-static-core@npm:4.17.33" dependencies: @@ -14526,23 +15116,12 @@ __metadata: languageName: node linkType: hard -"@types/express-serve-static-core@npm:4.17.31": - version: 4.17.31 - resolution: "@types/express-serve-static-core@npm:4.17.31" - dependencies: - "@types/node": "*" - "@types/qs": "*" - "@types/range-parser": "*" - checksum: 009bfbe1070837454a1056aa710d0390ee5fb8c05dfe5a1691cc3e2ca88dc256f80e1ca27cb51a978681631d2f6431bfc9ec352ea46dd0c6eb183d0170bde5df - languageName: node - linkType: hard - "@types/express-session@npm:^1.17.2": - version: 1.17.6 - resolution: "@types/express-session@npm:1.17.6" + version: 1.17.7 + resolution: "@types/express-session@npm:1.17.7" dependencies: "@types/express": "*" - checksum: f5f2201d6b9568d8b9319735a4f6806b5ca144cee450274965aec54bc0a0331ba8bfffc1ad5addadf2e625769e13813a48cb5aea5b166fa05f474a12302dbb38 + checksum: 4764eafaf4e26842e891e83fa9fee30b92cc3724d91987aac3a658322f9a69fb544dae24fc3aba6e15fe9575ed862760ebecd7ff97a947afb695284967434a65 languageName: node linkType: hard @@ -14557,26 +15136,14 @@ __metadata: linkType: hard "@types/express@npm:*, @types/express@npm:^4.17.13, @types/express@npm:^4.17.6": - version: 4.17.16 - resolution: "@types/express@npm:4.17.16" + version: 4.17.17 + resolution: "@types/express@npm:4.17.17" dependencies: "@types/body-parser": "*" - "@types/express-serve-static-core": ^4.17.31 + "@types/express-serve-static-core": ^4.17.33 "@types/qs": "*" "@types/serve-static": "*" - checksum: 43f3ed2cea6e5e83c7c1098c5152f644e975fd764443717ff9c812a1518416a9e7e9f824ffe852c118888cbfb994ed023cad08331f49b19ced469bb185cdd5cd - languageName: node - linkType: hard - -"@types/express@npm:4.17.14": - version: 4.17.14 - resolution: "@types/express@npm:4.17.14" - dependencies: - "@types/body-parser": "*" - "@types/express-serve-static-core": ^4.17.18 - "@types/qs": "*" - "@types/serve-static": "*" - checksum: 15c1af46d02de834e4a225eccaa9d85c0370fdbb3ed4e1bc2d323d24872309961542b993ae236335aeb3e278630224a6ea002078d39e651d78a3b0356b1eaa79 + checksum: 0196dacc275ac3ce89d7364885cb08e7fb61f53ca101f65886dbf1daf9b7eb05c0943e2e4bbd01b0cc5e50f37e0eea7e4cbe97d0304094411ac73e1b7998f4da languageName: node linkType: hard @@ -14647,7 +15214,7 @@ __metadata: languageName: node linkType: hard -"@types/hoist-non-react-statics@npm:^3.3.0": +"@types/hoist-non-react-statics@npm:^3.3.0, @types/hoist-non-react-statics@npm:^3.3.1": version: 3.3.1 resolution: "@types/hoist-non-react-statics@npm:3.3.1" dependencies: @@ -15075,7 +15642,7 @@ __metadata: languageName: node linkType: hard -"@types/node-fetch@npm:^2.5.0, @types/node-fetch@npm:^2.5.12, @types/node-fetch@npm:^2.5.7": +"@types/node-fetch@npm:^2.5.0, @types/node-fetch@npm:^2.5.12, @types/node-fetch@npm:^2.5.7, @types/node-fetch@npm:^2.6.1": version: 2.6.2 resolution: "@types/node-fetch@npm:2.6.2" dependencies: @@ -15108,13 +15675,6 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:^10.1.0": - version: 10.17.60 - resolution: "@types/node@npm:10.17.60" - checksum: 2cdb3a77d071ba8513e5e8306fa64bf50e3c3302390feeaeff1fd325dd25c8441369715dfc8e3701011a72fed5958c7dfa94eb9239a81b3c286caa4d97db6eef - languageName: node - linkType: hard - "@types/node@npm:^12.7.1": version: 12.20.55 resolution: "@types/node@npm:12.20.55" @@ -15309,6 +15869,15 @@ __metadata: languageName: node linkType: hard +"@types/ramda@npm:=0.28.23": + version: 0.28.23 + resolution: "@types/ramda@npm:0.28.23" + dependencies: + ts-toolbelt: ^6.15.1 + checksum: 61d7416c0f4f189c6524e093c7546ca2f159553e54d7933836d46aac1332611aa7b02fd8c8bfa98c0865f262fd9e99e06e3d9538deba0bab1f6153cbcf841160 + languageName: node + linkType: hard + "@types/range-parser@npm:*": version: 1.2.3 resolution: "@types/range-parser@npm:1.2.3" @@ -15529,11 +16098,11 @@ __metadata: linkType: hard "@types/sanitize-html@npm:^2.6.2": - version: 2.8.1 - resolution: "@types/sanitize-html@npm:2.8.1" + version: 2.9.0 + resolution: "@types/sanitize-html@npm:2.9.0" dependencies: htmlparser2: ^8.0.0 - checksum: 9c07d3a9d925e291472f74b097fb179b32659ea01834f728887811e5fc75cf2b17d844e32e97c0e583eba993af86a3f8250c82c8fa3152abf9ff2a8582972906 + checksum: b60f42b740bbfb1b1434ce8b43925a38ecc608b60aa654fd009d2e22e33f324b61d370768c55bd2fd98e03de08518ffa8911d61606c483526fb931bb8b59d1b0 languageName: node linkType: hard @@ -15798,6 +16367,13 @@ __metadata: languageName: node linkType: hard +"@types/use-sync-external-store@npm:^0.0.3": + version: 0.0.3 + resolution: "@types/use-sync-external-store@npm:0.0.3" + checksum: 161ddb8eec5dbe7279ac971531217e9af6b99f7783213566d2b502e2e2378ea19cf5e5ea4595039d730aa79d3d35c6567d48599f69773a02ffcff1776ec2a44e + languageName: node + linkType: hard + "@types/uuid@npm:^8.0.0": version: 8.3.4 resolution: "@types/uuid@npm:8.3.4" @@ -16359,6 +16935,33 @@ __metadata: languageName: node linkType: hard +"@wry/context@npm:^0.7.0": + version: 0.7.0 + resolution: "@wry/context@npm:0.7.0" + dependencies: + tslib: ^2.3.0 + checksum: f4ff78023a0b949122037aae766232b7d2284dc415204d22d9ea6d7969ff8f5f29b18128bc9a40e68dc054c8a12b1bf5868a357fdb50c398c447290c3a5b0496 + languageName: node + linkType: hard + +"@wry/equality@npm:^0.5.0": + version: 0.5.3 + resolution: "@wry/equality@npm:0.5.3" + dependencies: + tslib: ^2.3.0 + checksum: 7ea8ded51462911217183b93cc3ffbb4d18dc02a62d4a79e0d9983463739bf54106aaeb25649bf33168120bd044b61d135018bfcf4fefad8099c13eac9238aa6 + languageName: node + linkType: hard + +"@wry/trie@npm:^0.3.0": + version: 0.3.2 + resolution: "@wry/trie@npm:0.3.2" + dependencies: + tslib: ^2.3.0 + checksum: 151d06b519e1ff1c3acf6ee6846161b1d7d50bbecd4c48e5cd1b05f9e37c30602aff02e88f20105f6e6c54ae4123f9c4eb7715044d7fd927d4ba4ec3e755cd36 + languageName: node + linkType: hard + "@xmldom/xmldom@npm:^0.7.0, @xmldom/xmldom@npm:^0.7.5, @xmldom/xmldom@npm:^0.7.6": version: 0.7.9 resolution: "@xmldom/xmldom@npm:0.7.9" @@ -16448,7 +17051,7 @@ __metadata: languageName: node linkType: hard -"accepts@npm:^1.3.5, accepts@npm:~1.3.4, accepts@npm:~1.3.5, accepts@npm:~1.3.8": +"accepts@npm:~1.3.4, accepts@npm:~1.3.5, accepts@npm:~1.3.8": version: 1.3.8 resolution: "accepts@npm:1.3.8" dependencies: @@ -16748,137 +17351,6 @@ __metadata: languageName: node linkType: hard -"apollo-datasource@npm:^3.3.2": - version: 3.3.2 - resolution: "apollo-datasource@npm:3.3.2" - dependencies: - "@apollo/utils.keyvaluecache": ^1.0.1 - apollo-server-env: ^4.2.1 - checksum: 70244e792655b357213b92e9dd0e8ca553724857847c9bedb53a1dbf7a92fc0d8b05a60d77203d6c30331599b44c5d7cc5f4d94c934465fa05b146b681ed2293 - languageName: node - linkType: hard - -"apollo-reporting-protobuf@npm:^3.3.1, apollo-reporting-protobuf@npm:^3.4.0": - version: 3.4.0 - resolution: "apollo-reporting-protobuf@npm:3.4.0" - dependencies: - "@apollo/protobufjs": 1.2.6 - checksum: 5bf50e9cecd3c2334cd12e0ebe59be6c4d7b1b9ee443c7d913011ea1b84513f57561fb6c3ceb66083321acb6d1c56f72e2ab0edf378cf742693409eb8dcdc46b - languageName: node - linkType: hard - -"apollo-server-core@npm:^3.12.0": - version: 3.12.0 - resolution: "apollo-server-core@npm:3.12.0" - dependencies: - "@apollo/utils.keyvaluecache": ^1.0.1 - "@apollo/utils.logger": ^1.0.0 - "@apollo/utils.usagereporting": ^1.0.0 - "@apollographql/apollo-tools": ^0.5.3 - "@apollographql/graphql-playground-html": 1.6.29 - "@graphql-tools/mock": ^8.1.2 - "@graphql-tools/schema": ^8.0.0 - "@josephg/resolvable": ^1.0.0 - apollo-datasource: ^3.3.2 - apollo-reporting-protobuf: ^3.4.0 - apollo-server-env: ^4.2.1 - apollo-server-errors: ^3.3.1 - apollo-server-plugin-base: ^3.7.2 - apollo-server-types: ^3.8.0 - 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: b7a37a78901d38a330c9df8fe870da3dcf512f43ab60fdf9ab0ba37be03977db5d4b72eabf51a830d2a9dcfb2974d7bfbc5aa8719e3afac113c8bd7222740b8f - languageName: node - linkType: hard - -"apollo-server-env@npm:^4.2.1": - version: 4.2.1 - resolution: "apollo-server-env@npm:4.2.1" - dependencies: - node-fetch: ^2.6.7 - checksum: 039c7eeed82aff072237f9943629ab24b7c62b97535d756a31178f9e7352187951ee654a377d49d775d2ac221fe024914d9989257ca8a7e65c8e5f438c044f18 - languageName: node - linkType: hard - -"apollo-server-errors@npm:^3.3.1": - version: 3.3.1 - resolution: "apollo-server-errors@npm:3.3.1" - peerDependencies: - graphql: ^15.3.0 || ^16.0.0 - checksum: d09b66e7ac3e2cbc60774280d30118ac4d98f945b5cc1013bb81b9970aae49c0717a550e161fe978d69d7039ec053aeba495890f6eebf452532a2c5e94071a80 - languageName: node - linkType: hard - -"apollo-server-express@npm:^3.0.0, apollo-server-express@npm:^3.12.0": - version: 3.12.0 - resolution: "apollo-server-express@npm:3.12.0" - dependencies: - "@types/accepts": ^1.3.5 - "@types/body-parser": 1.19.2 - "@types/cors": 2.8.12 - "@types/express": 4.17.14 - "@types/express-serve-static-core": 4.17.31 - accepts: ^1.3.5 - apollo-server-core: ^3.12.0 - apollo-server-types: ^3.8.0 - 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: bd4bc213f506e2aeb2be961961de51e431f8774344b349e9b02f475714a623703eb62423ad968a8f8b6859919ae0d1912c40cf15a4df24e6f81b4f4c5653e70b - languageName: node - linkType: hard - -"apollo-server-plugin-base@npm:^3.7.2": - version: 3.7.2 - resolution: "apollo-server-plugin-base@npm:3.7.2" - dependencies: - apollo-server-types: ^3.8.0 - peerDependencies: - graphql: ^15.3.0 || ^16.0.0 - checksum: d6ea6dbfad8bb82959286eae89878ccccbd09743c3df2b76bf790f470cbf5441ba06dcb6835a25f0bf32f4df05722cce157ae983ce32db4b69de8a72c9949e2e - languageName: node - linkType: hard - -"apollo-server-types@npm:^3.8.0": - version: 3.8.0 - resolution: "apollo-server-types@npm:3.8.0" - dependencies: - "@apollo/utils.keyvaluecache": ^1.0.1 - "@apollo/utils.logger": ^1.0.0 - apollo-reporting-protobuf: ^3.4.0 - apollo-server-env: ^4.2.1 - peerDependencies: - graphql: ^15.3.0 || ^16.0.0 - checksum: 20accd42b65ceb95819a1610c410488fbe548ee309227d7fa22fd17dd1205e557091ba9c9a20efa532192098a4193e34eb58fc91d762b55fdf31229ac9fc7133 - languageName: node - linkType: hard - -"apollo-server@npm:^3.0.0": - version: 3.12.0 - resolution: "apollo-server@npm:3.12.0" - dependencies: - "@types/express": 4.17.14 - apollo-server-core: ^3.12.0 - apollo-server-express: ^3.12.0 - express: ^4.17.1 - peerDependencies: - graphql: ^15.3.0 || ^16.0.0 - checksum: 6f3dade76f202f04a890b2385923a0319a859a0ab48121b1636e22d5eae83afe042d7a0a501aff3d8816e67de4f29f8efa598e350814a40f41d079610dee346e - languageName: node - linkType: hard - "aproba@npm:^1.0.3": version: 1.2.0 resolution: "aproba@npm:1.2.0" @@ -17267,20 +17739,6 @@ __metadata: languageName: node linkType: hard -"aws-lambda@npm:^1.0.7": - version: 1.0.7 - resolution: "aws-lambda@npm:1.0.7" - dependencies: - aws-sdk: ^2.814.0 - commander: ^3.0.2 - js-yaml: ^3.14.1 - watchpack: ^2.0.0-beta.10 - bin: - lambda: bin/lambda - checksum: 11316e87b5c4fc36e6bd0495742a3c0ed13befc9527a7b251a58180d141d9afd68b684f37aeb3b53d117d3c2f96747eace31826b683543f1edddc03f392865fd - languageName: node - linkType: hard - "aws-os-connection@npm:^0.2.0": version: 0.2.0 resolution: "aws-os-connection@npm:0.2.0" @@ -17294,14 +17752,14 @@ __metadata: linkType: hard "aws-sdk-client-mock-jest@npm:^2.0.0": - version: 2.1.0 - resolution: "aws-sdk-client-mock-jest@npm:2.1.0" + version: 2.1.1 + resolution: "aws-sdk-client-mock-jest@npm:2.1.1" dependencies: "@types/jest": ^28.1.3 tslib: ^2.1.0 peerDependencies: - aws-sdk-client-mock: 2.1.0 - checksum: 567e2084d71c90f71e5bfa82f2a4b592fec5ea818cb4edf3586f922454cee4fec1403d4161d3d91a3db3ccebe1db5babe069754d76204c7f6986ab71bafb1084 + aws-sdk-client-mock: 2.1.1 + checksum: 4b5ca96bbcaa60ea3ea947821c7ff1f073c1342a12ce5c778b70832bdcc6106e10591e98e09b22c5b0d83dfc6fe554e8a08d5df5cf067a7eaadb804087b891ed languageName: node linkType: hard @@ -17327,7 +17785,7 @@ __metadata: languageName: node linkType: hard -"aws-sdk@npm:^2.1231.0, aws-sdk@npm:^2.814.0, aws-sdk@npm:^2.840.0, aws-sdk@npm:^2.948.0": +"aws-sdk@npm:^2.1231.0, aws-sdk@npm:^2.840.0, aws-sdk@npm:^2.948.0": version: 2.1279.0 resolution: "aws-sdk@npm:2.1279.0" dependencies: @@ -17389,6 +17847,17 @@ __metadata: languageName: node linkType: hard +"axios@npm:=1.3.4": + version: 1.3.4 + resolution: "axios@npm:1.3.4" + dependencies: + follow-redirects: ^1.15.0 + form-data: ^4.0.0 + proxy-from-env: ^1.1.0 + checksum: 7440edefcf8498bc3cdf39de00443e8101f249972c83b739c6e880d9d669fea9486372dbe8739e88b3bf8bb1ad15f6106693f206f078f4516fe8fd47b1c3093c + languageName: node + linkType: hard + "axios@npm:^0.21.1": version: 0.21.4 resolution: "axios@npm:0.21.4" @@ -17875,7 +18344,7 @@ __metadata: languageName: node linkType: hard -"body-parser@npm:1.20.1, body-parser@npm:^1.19.0": +"body-parser@npm:1.20.1": version: 1.20.1 resolution: "body-parser@npm:1.20.1" dependencies: @@ -17895,6 +18364,26 @@ __metadata: languageName: node linkType: hard +"body-parser@npm:^1.20.0": + version: 1.20.2 + resolution: "body-parser@npm:1.20.2" + dependencies: + bytes: 3.1.2 + content-type: ~1.0.5 + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + on-finished: 2.4.1 + qs: 6.11.0 + raw-body: 2.5.2 + type-is: ~1.6.18 + unpipe: 1.0.0 + checksum: 14d37ec638ab5c93f6099ecaed7f28f890d222c650c69306872e00b9efa081ff6c596cd9afb9930656aae4d6c4e1c17537bea12bb73c87a217cb3cfea8896737 + languageName: node + linkType: hard + "bonjour-service@npm:^1.0.11": version: 1.0.11 resolution: "bonjour-service@npm:1.0.11" @@ -18497,6 +18986,13 @@ __metadata: languageName: node linkType: hard +"chalk@npm:5.2.0": + version: 5.2.0 + resolution: "chalk@npm:5.2.0" + checksum: 03d8060277de6cf2fd567dc25fcf770593eb5bb85f460ce443e49255a30ff1242edd0c90a06a03803b0466ff0687a939b41db1757bec987113e83de89a003caa + languageName: node + linkType: hard + "chalk@npm:^3.0.0": version: 3.0.0 resolution: "chalk@npm:3.0.0" @@ -19178,10 +19674,10 @@ __metadata: languageName: node linkType: hard -"commander@npm:*, commander@npm:^9.1.0, commander@npm:^9.4.1, commander@npm:^9.5.0": - version: 9.5.0 - resolution: "commander@npm:9.5.0" - checksum: c7a3e27aa59e913b54a1bafd366b88650bc41d6651f0cbe258d4ff09d43d6a7394232a4dadd0bf518b3e696fdf595db1028a0d82c785b88bd61f8a440cecfade +"commander@npm:*, commander@npm:^10.0.0": + version: 10.0.0 + resolution: "commander@npm:10.0.0" + checksum: 9f6495651f878213005ac744dd87a85fa3d9f2b8b90d1c19d0866d666bda7f735adfd7c2f10dfff345782e2f80ea258f98bb4efcef58e4e502f25f883940acfd languageName: node linkType: hard @@ -19199,20 +19695,13 @@ __metadata: languageName: node linkType: hard -"commander@npm:^2.20.0, commander@npm:^2.20.3, commander@npm:^2.7.1": +"commander@npm:^2.20.0, commander@npm:^2.7.1": version: 2.20.3 resolution: "commander@npm:2.20.3" checksum: ab8c07884e42c3a8dbc5dd9592c606176c7eb5c1ca5ff274bcf907039b2c41de3626f684ea75ccf4d361ba004bbaff1f577d5384c155f3871e456bdf27becf9e languageName: node linkType: hard -"commander@npm:^3.0.2": - version: 3.0.2 - resolution: "commander@npm:3.0.2" - checksum: 6d14ad030d1904428139487ed31febcb04c1604db2b8d9fae711f60ee6718828dc0e11602249e91c8a97b0e721e9c6d53edbc166bad3cde1596851d59a8f824d - languageName: node - linkType: hard - "commander@npm:^4.0.0": version: 4.1.1 resolution: "commander@npm:4.1.1" @@ -19234,6 +19723,13 @@ __metadata: languageName: node linkType: hard +"commander@npm:^9.1.0, commander@npm:^9.5.0": + version: 9.5.0 + resolution: "commander@npm:9.5.0" + checksum: c7a3e27aa59e913b54a1bafd366b88650bc41d6651f0cbe258d4ff09d43d6a7394232a4dadd0bf518b3e696fdf595db1028a0d82c785b88bd61f8a440cecfade + languageName: node + linkType: hard + "common-ancestor-path@npm:^1.0.1": version: 1.0.1 resolution: "common-ancestor-path@npm:1.0.1" @@ -19486,10 +19982,10 @@ __metadata: languageName: node linkType: hard -"content-type@npm:~1.0.4": - version: 1.0.4 - resolution: "content-type@npm:1.0.4" - checksum: 3d93585fda985d1554eca5ebd251994327608d2e200978fdbfba21c0c679914d5faf266d17027de44b34a72c7b0745b18584ecccaa7e1fdfb6a68ac7114f12e0 +"content-type@npm:~1.0.4, content-type@npm:~1.0.5": + version: 1.0.5 + resolution: "content-type@npm:1.0.5" + checksum: 566271e0a251642254cde0f845f9dd4f9856e52d988f4eb0d0dcffbb7a1f8ec98de7a5215fc628f3bce30fe2fb6fd2bc064b562d721658c59b544e2d34ea2766 languageName: node linkType: hard @@ -19573,10 +20069,10 @@ __metadata: languageName: node linkType: hard -"core-js-pure@npm:^3.20.2, core-js-pure@npm:^3.23.3, core-js-pure@npm:^3.6.5": - version: 3.25.5 - resolution: "core-js-pure@npm:3.25.5" - checksum: e48799a8ab28f00ef3db18377142ff2c578574ab2b18ebddde6cbf12823e0181a57c80e3caa6046ce2a2e439d603a252be767583ddc54248e3d1060bc5012127 +"core-js-pure@npm:^3.23.3, core-js-pure@npm:^3.25.1, core-js-pure@npm:^3.6.5": + version: 3.29.1 + resolution: "core-js-pure@npm:3.29.1" + checksum: 2ed91f79c13f23c1b70c31edf4224aca99a9ac3db38c79127798c294a36faac0ea0b21070218621741057cf84b3dadff595475580c1fac3a43e02cae575dc27b languageName: node linkType: hard @@ -19595,9 +20091,9 @@ __metadata: linkType: hard "core-js@npm:^3.6.5": - version: 3.28.0 - resolution: "core-js@npm:3.28.0" - checksum: 3155fd0ec16d0089106b145e9595280a4ea4bde0d7ff26aa14364cd4f1c203baf6620c3025acd284f363d08b9f21104101692766ca9a36ffeee7307bdf3e1881 + version: 3.29.1 + resolution: "core-js@npm:3.29.1" + checksum: b38446dbfcfd3887b3d4922990da487e2c95044cb4c5717aaf95e786a4c6b218f05c056c7ed6c699169b9794a49fec890e402659d54661fc56965a0eb717e7bd languageName: node linkType: hard @@ -19618,18 +20114,6 @@ __metadata: languageName: node linkType: hard -"cosmiconfig-typescript-loader@npm:^4.3.0": - version: 4.3.0 - resolution: "cosmiconfig-typescript-loader@npm:4.3.0" - peerDependencies: - "@types/node": "*" - cosmiconfig: ">=7" - ts-node: ">=10" - typescript: ">=3" - checksum: ea61dfd8e112cf2bb18df0ef89280bd3ae3dd5b997b4a9fc22bbabdc02513aadfbc6d4e15e922b6a9a5d987e9dad42286fa38caf77a9b8dcdbe7d4ce1c9db4fb - languageName: node - linkType: hard - "cosmiconfig@npm:8.0.0": version: 8.0.0 resolution: "cosmiconfig@npm:8.0.0" @@ -19752,20 +20236,20 @@ __metadata: linkType: hard "cron@npm:^2.0.0": - version: 2.2.0 - resolution: "cron@npm:2.2.0" + version: 2.3.0 + resolution: "cron@npm:2.3.0" dependencies: luxon: ^3.2.1 - checksum: 53905d0f55e052742cf4fed34598a4ebfc311f4f9143c90384225bb4376fa639cd12f485cbf5d3dca00db377bf5117f27a1cae405f15e4745d1f69808e4fb9ac + checksum: 70b220f3fc4b6bcd594f7f2c690bbf7a3a03b0e081eb0119f8e3ca21635f2da07d89e038d561d4c0742c8b0dd04977f25e307d0608455ef9f527a556b2da92fc languageName: node linkType: hard "cronstrue@npm:^2.2.0": - version: 2.23.0 - resolution: "cronstrue@npm:2.23.0" + version: 2.24.0 + resolution: "cronstrue@npm:2.24.0" bin: cronstrue: bin/cli.js - checksum: 050140ac6452468d6f9032f18038f41b16968502d411a996efd5d42243cfd882271ff20ed4a3cdb25c45bf8f88beeb0579e45e974a11987401e9d383af2641a8 + checksum: 2c7d4cfe43bec7b57b1824772641271bb5f5ed0209336ea53796f97b17966dd95cf15ae890f7c2494f639ba489d225bfb882950cda0ec7e5453fa7bf236842dd languageName: node linkType: hard @@ -19993,13 +20477,6 @@ __metadata: languageName: node linkType: hard -"cssfilter@npm:0.0.10": - version: 0.0.10 - resolution: "cssfilter@npm:0.0.10" - checksum: bc2c52bbb3426c3f2e4832edb6f8573e6cfa65b40b540932762d1e018f0f0157725e2991b77344bbc8266c6bbf4daa2803b0707cfb1bd0877505bf83a68e4b04 - languageName: node - linkType: hard - "cssnano-preset-default@npm:^5.1.7": version: 5.1.7 resolution: "cssnano-preset-default@npm:5.1.7" @@ -20450,7 +20927,7 @@ __metadata: languageName: node linkType: hard -"dataloader@npm:^2.0.0": +"dataloader@npm:2.2.2, dataloader@npm:^2.0.0, dataloader@npm:^2.2.2": version: 2.2.2 resolution: "dataloader@npm:2.2.2" checksum: 4dabd247089c29f194e94d5434d504f99156c5c214a03463c20f3f17f40398d7e179edee69a27c16e315519ac8739042a810090087ae26449a0e685156a02c65 @@ -20647,10 +21124,10 @@ __metadata: languageName: node linkType: hard -"deepmerge@npm:^4.2.2, deepmerge@npm:~4.2.2": - version: 4.2.2 - resolution: "deepmerge@npm:4.2.2" - checksum: a8c43a1ed8d6d1ed2b5bf569fa4c8eb9f0924034baf75d5d406e47e157a451075c4db353efea7b6bcc56ec48116a8ce72fccf867b6e078e7c561904b5897530b +"deepmerge@npm:^4.2.2, deepmerge@npm:~4.3.0": + version: 4.3.1 + resolution: "deepmerge@npm:4.3.1" + checksum: 2024c6a980a1b7128084170c4cf56b0fd58a63f2da1660dcfe977415f27b17dbe5888668b59d0b063753f3220719d5e400b7f113609489c90160bb9a5518d052 languageName: node linkType: hard @@ -20959,13 +21436,13 @@ __metadata: linkType: hard "dockerode@npm:^3.3.1": - version: 3.3.4 - resolution: "dockerode@npm:3.3.4" + version: 3.3.5 + resolution: "dockerode@npm:3.3.5" dependencies: "@balena/dockerignore": ^1.0.2 docker-modem: ^3.0.0 tar-fs: ~2.0.1 - checksum: 6cb4b9d1c42feb3acfa77daf103b070cc412351dc7dc0a1553cc774ccd1be1a1412a87f8aa13c3155c63ec5c61a7cadc833b4248c4d8342814bbf708f795b952 + checksum: 7f6650422b07fa7ea9d5801f04b1a432634446b5fe37b995b8302b953b64e93abf1bb4596c2fb574ba47aafee685ef2ab959cc86c9654add5a26d09541bbbcc6 languageName: node linkType: hard @@ -21102,9 +21579,9 @@ __metadata: linkType: hard "dompurify@npm:^2.2.7, dompurify@npm:^2.2.9, dompurify@npm:^2.3.6": - version: 2.4.3 - resolution: "dompurify@npm:2.4.3" - checksum: b440981f2a38cada2085759cc3d1e2f94571afc34343d011a8a6aa1ad91ae6abf651adbfa4994b0e2283f0ce81f7891cdb04b67d0b234c8d190cb70e9691f026 + version: 2.4.5 + resolution: "dompurify@npm:2.4.5" + checksum: d6d3c3b320f15cdb5b26aa1902c3275a3ab2c3705a9df4420bb94691d7c4df67959ec7b91e486c308320791b0ee000456f042734c45d76721e61c2768eac706e languageName: node linkType: hard @@ -21272,8 +21749,8 @@ __metadata: linkType: hard "elastic-builder@npm:^2.16.0": - version: 2.17.3 - resolution: "elastic-builder@npm:2.17.3" + version: 2.18.1 + resolution: "elastic-builder@npm:2.18.1" dependencies: lodash.has: ^4.5.2 lodash.hasin: ^4.5.2 @@ -21283,7 +21760,7 @@ __metadata: lodash.isobject: ^3.0.2 lodash.isstring: ^4.0.1 lodash.omit: ^4.5.0 - checksum: b1e47ad4d36e9974a1075e9e4f455e2d120eebc16d9e5c7e7219e89fcb64bcacd3015afddeae479a79f6b4cd92c4528f3e8535c9c9ca8d644286b9bb49635cdc + checksum: 54093daadc1fc3666ac8eef0a268267761e92a3fbb524e51936cf944ceeaeb231a269fc8ae9fb902ca41c976c76c0c037da692a34577d705da301ed727bd8e07 languageName: node linkType: hard @@ -21785,31 +22262,31 @@ __metadata: linkType: hard "esbuild@npm:^0.17.0": - version: 0.17.11 - resolution: "esbuild@npm:0.17.11" + version: 0.17.12 + resolution: "esbuild@npm:0.17.12" dependencies: - "@esbuild/android-arm": 0.17.11 - "@esbuild/android-arm64": 0.17.11 - "@esbuild/android-x64": 0.17.11 - "@esbuild/darwin-arm64": 0.17.11 - "@esbuild/darwin-x64": 0.17.11 - "@esbuild/freebsd-arm64": 0.17.11 - "@esbuild/freebsd-x64": 0.17.11 - "@esbuild/linux-arm": 0.17.11 - "@esbuild/linux-arm64": 0.17.11 - "@esbuild/linux-ia32": 0.17.11 - "@esbuild/linux-loong64": 0.17.11 - "@esbuild/linux-mips64el": 0.17.11 - "@esbuild/linux-ppc64": 0.17.11 - "@esbuild/linux-riscv64": 0.17.11 - "@esbuild/linux-s390x": 0.17.11 - "@esbuild/linux-x64": 0.17.11 - "@esbuild/netbsd-x64": 0.17.11 - "@esbuild/openbsd-x64": 0.17.11 - "@esbuild/sunos-x64": 0.17.11 - "@esbuild/win32-arm64": 0.17.11 - "@esbuild/win32-ia32": 0.17.11 - "@esbuild/win32-x64": 0.17.11 + "@esbuild/android-arm": 0.17.12 + "@esbuild/android-arm64": 0.17.12 + "@esbuild/android-x64": 0.17.12 + "@esbuild/darwin-arm64": 0.17.12 + "@esbuild/darwin-x64": 0.17.12 + "@esbuild/freebsd-arm64": 0.17.12 + "@esbuild/freebsd-x64": 0.17.12 + "@esbuild/linux-arm": 0.17.12 + "@esbuild/linux-arm64": 0.17.12 + "@esbuild/linux-ia32": 0.17.12 + "@esbuild/linux-loong64": 0.17.12 + "@esbuild/linux-mips64el": 0.17.12 + "@esbuild/linux-ppc64": 0.17.12 + "@esbuild/linux-riscv64": 0.17.12 + "@esbuild/linux-s390x": 0.17.12 + "@esbuild/linux-x64": 0.17.12 + "@esbuild/netbsd-x64": 0.17.12 + "@esbuild/openbsd-x64": 0.17.12 + "@esbuild/sunos-x64": 0.17.12 + "@esbuild/win32-arm64": 0.17.12 + "@esbuild/win32-ia32": 0.17.12 + "@esbuild/win32-x64": 0.17.12 dependenciesMeta: "@esbuild/android-arm": optional: true @@ -21857,7 +22334,7 @@ __metadata: optional: true bin: esbuild: bin/esbuild - checksum: febf218155513bb9c9c970508c03ec58e0aacfdc23394f425836a09f1da0dae0afa12949274adfd382782eef097f86b2d6b3032293062291f2f471de204f77ec + checksum: ea6d33eb1bc6c9e00dcee5e253c7e935251b4801d376661fd9f19a9dcffc27f970078a6f7116d6c78ee825ceff9b974594b0b616bd560ce4d875a951aa92977b languageName: node linkType: hard @@ -22019,13 +22496,13 @@ __metadata: linkType: hard "eslint-config-prettier@npm:^8.3.0": - version: 8.6.0 - resolution: "eslint-config-prettier@npm:8.6.0" + version: 8.8.0 + resolution: "eslint-config-prettier@npm:8.8.0" peerDependencies: eslint: ">=7.0.0" bin: eslint-config-prettier: bin/cli.js - checksum: ff0d0dfc839a556355422293428637e8d35693de58dabf8638bf0b6529131a109d0b2ade77521aa6e54573bb842d7d9d322e465dd73dd61c7590fa3834c3fa81 + checksum: 1e94c3882c4d5e41e1dcfa2c368dbccbfe3134f6ac7d40101644d3bfbe3eb2f2ffac757f3145910b5eacf20c0e85e02b91293d3126d770cbf3dc390b3564681c languageName: node linkType: hard @@ -22579,7 +23056,7 @@ __metadata: "@internal/plugin-catalog-customized": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.57 + "@material-ui/lab": 4.0.0-alpha.61 "@octokit/rest": ^19.0.3 "@oriflame/backstage-plugin-score-card": ^0.6.0 "@roadiehq/backstage-plugin-buildkite": ^2.0.8 @@ -22618,6 +23095,11 @@ __metadata: "@backstage/plugin-app-backend": "workspace:^" "@backstage/plugin-catalog-backend": "workspace:^" "@backstage/plugin-scaffolder-backend": "workspace:^" + "@backstage/plugin-search-backend": "workspace:^" + "@backstage/plugin-search-backend-module-catalog": "workspace:^" + "@backstage/plugin-search-backend-module-explore": "workspace:^" + "@backstage/plugin-search-backend-module-techdocs": "workspace:^" + "@backstage/plugin-search-backend-node": "workspace:^" "@backstage/plugin-techdocs-backend": "workspace:^" "@backstage/plugin-todo-backend": "workspace:^" languageName: unknown @@ -22727,20 +23209,20 @@ __metadata: languageName: node linkType: hard -"execa@npm:^6.1.0": - version: 6.1.0 - resolution: "execa@npm:6.1.0" +"execa@npm:^7.0.0": + version: 7.0.0 + resolution: "execa@npm:7.0.0" dependencies: cross-spawn: ^7.0.3 get-stream: ^6.0.1 - human-signals: ^3.0.1 + human-signals: ^4.3.0 is-stream: ^3.0.0 merge-stream: ^2.0.0 npm-run-path: ^5.1.0 onetime: ^6.0.0 signal-exit: ^3.0.7 strip-final-newline: ^3.0.0 - checksum: 1a4af799839134f5c72eb63d525b87304c1114a63aa71676c91d57ccef2e26f2f53e14c11384ab11c4ec479be1efa83d11c8190e00040355c2c5c3364327fa8e + checksum: be7c7b6d1e5473f628e46888b0cf8279da483c1a6000dd494a2059cc26591ded57ba46be1c9bdde1ec895e7eb8b18911174aba425cd971d41d140a9405da9a02 languageName: node linkType: hard @@ -23409,7 +23891,7 @@ __metadata: languageName: node linkType: hard -"follow-redirects@npm:^1.0.0, follow-redirects@npm:^1.14.0, follow-redirects@npm:^1.14.8, follow-redirects@npm:^1.14.9": +"follow-redirects@npm:^1.0.0, follow-redirects@npm:^1.14.0, follow-redirects@npm:^1.14.8, follow-redirects@npm:^1.14.9, follow-redirects@npm:^1.15.0": version: 1.15.2 resolution: "follow-redirects@npm:1.15.2" peerDependenciesMeta: @@ -24305,9 +24787,9 @@ __metadata: languageName: node linkType: hard -"graphql-config@npm:^4.4.0": - version: 4.4.0 - resolution: "graphql-config@npm:4.4.0" +"graphql-config@npm:^4.5.0": + version: 4.5.0 + resolution: "graphql-config@npm:4.5.0" dependencies: "@graphql-tools/graphql-file-loader": ^7.3.7 "@graphql-tools/json-file-loader": ^7.3.7 @@ -24316,14 +24798,17 @@ __metadata: "@graphql-tools/url-loader": ^7.9.7 "@graphql-tools/utils": ^9.0.0 cosmiconfig: 8.0.0 - minimatch: 4.2.1 + jiti: 1.17.1 + minimatch: 4.2.3 string-env-interpolation: 1.0.1 tslib: ^2.4.0 peerDependencies: cosmiconfig-toml-loader: ^1.0.0 - cosmiconfig-typescript-loader: ^4.0.0 graphql: ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 - checksum: 2f8cbb4710a7c0a411074eb843317bc66e5602fdab7eefa9765812d986d4b04fc2d285d3c0811ed0efaef12ea58351676561d704e79880f5848ed970badab500 + peerDependenciesMeta: + cosmiconfig-toml-loader: + optional: true + checksum: 8ab1a3ce3534598ddac2df213b6af2eecd9ebcca2268d39cc3e87a6e55749483389a6df222e9e0acd638dd2479378a5c8e8d90f980e6a54e700c4c4ae3522123 languageName: node linkType: hard @@ -24342,16 +24827,16 @@ __metadata: linkType: hard "graphql-modules@npm:^2.0.0": - version: 2.1.0 - resolution: "graphql-modules@npm:2.1.0" + version: 2.1.2 + resolution: "graphql-modules@npm:2.1.2" dependencies: - "@graphql-tools/schema": ^8.3.1 - "@graphql-tools/wrap": ^8.3.1 + "@graphql-tools/schema": ^9.0.0 + "@graphql-tools/wrap": ^9.0.0 "@graphql-typed-document-node/core": ^3.1.0 ramda: ^0.28.0 peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 - checksum: a57b63007815a8958ec49ecc14a640d559f8fd164968c123ffc3efdbcf35778d1c99f3570660a1dac4a523c986eeaf0c8834dfe0ed721de5111cedbce0ed6790 + checksum: 3a4732c54acb707350b7249d96952b5bb1e5a2c054090181d4e4f8adcd66d4d0675208d06f873bca75b924833df9a2c5bc7ce90aeb04b2d9e256605313a6080a languageName: node linkType: hard @@ -24369,7 +24854,7 @@ __metadata: languageName: node linkType: hard -"graphql-tag@npm:^2.11.0": +"graphql-tag@npm:^2.11.0, graphql-tag@npm:^2.12.6": version: 2.12.6 resolution: "graphql-tag@npm:2.12.6" dependencies: @@ -24410,7 +24895,7 @@ __metadata: languageName: node linkType: hard -"graphql-ws@npm:5.11.2, graphql-ws@npm:^5.4.1, graphql-ws@npm:^5.9.0": +"graphql-ws@npm:5.11.2": version: 5.11.2 resolution: "graphql-ws@npm:5.11.2" peerDependencies: @@ -24419,6 +24904,15 @@ __metadata: languageName: node linkType: hard +"graphql-ws@npm:^5.4.1, graphql-ws@npm:^5.9.0": + version: 5.12.0 + resolution: "graphql-ws@npm:5.12.0" + peerDependencies: + graphql: ">=0.11 <=16" + checksum: 5c683e2d5bdadfcfec0639eda69b8a66ef275e68e64f662bd75da6779a87b34395cbce8e37cb66830a9febca1871f7dc2575e6814f6f6e899904fe72e245f216 + languageName: node + linkType: hard + "graphql@npm:^15.0.0 || ^16.0.0, graphql@npm:^16.0.0": version: 16.6.0 resolution: "graphql@npm:16.6.0" @@ -25036,10 +25530,10 @@ __metadata: languageName: node linkType: hard -"human-signals@npm:^3.0.1": - version: 3.0.1 - resolution: "human-signals@npm:3.0.1" - checksum: f252a7769c8094a5c9dc6772816bdb417b188820b04c8b42d0fc468e03a0ba905b1dd07afabe9385cc83504af1ccc2b985cd1e4aeeeb8e0029896c5af2e6f354 +"human-signals@npm:^4.3.0": + version: 4.3.0 + resolution: "human-signals@npm:4.3.0" + checksum: 662b976b1063a8afb8fd7fa50bde6975997e17ea6ceba2aad54aacf1dc239a2cd7d14d27b3ceca0c6288627f4b45c56c2c89618455ff52cd9377c02d6328cd7c languageName: node linkType: hard @@ -25172,9 +25666,9 @@ __metadata: linkType: hard "immer@npm:^9.0.1, immer@npm:^9.0.7": - version: 9.0.19 - resolution: "immer@npm:9.0.19" - checksum: f02ee53989989c287cd548a3d817fccf0bfe56db919755ee94a72ea3ae78a00363fba93ee6c010fe54a664380c29c53d44ed4091c6a86cae60957ad2cfabc010 + version: 9.0.21 + resolution: "immer@npm:9.0.21" + checksum: 70e3c274165995352f6936695f0ef4723c52c92c92dd0e9afdfe008175af39fa28e76aafb3a2ca9d57d1fb8f796efc4dd1e1cc36f18d33fa5b74f3dfb0375432 languageName: node linkType: hard @@ -26260,8 +26754,8 @@ __metadata: linkType: hard "isomorphic-git@npm:^1.8.0": - version: 1.21.0 - resolution: "isomorphic-git@npm:1.21.0" + version: 1.23.0 + resolution: "isomorphic-git@npm:1.23.0" dependencies: async-lock: ^1.1.0 clean-git-ref: ^2.0.1 @@ -26276,7 +26770,7 @@ __metadata: simple-get: ^4.0.1 bin: isogit: cli.cjs - checksum: afbdf98000c586fdcb96f84c054d6ada392b0d2422a7b7baad89e5f5881a79426f8555bdadeebe25202be18bb8eaee3881f8c04b6a289d04b916790bdd5dd5df + checksum: a733c1183855a90edd6d82cfdccd467886045fa98af211a50df7cbb2d3088e122542b9eef0f79ebe9d5e127a81c62dfa0ff561d906f0c9d4e5eb7a0c1f13f56f languageName: node linkType: hard @@ -26950,6 +27444,24 @@ __metadata: languageName: node linkType: hard +"jiti@npm:1.17.1": + version: 1.17.1 + resolution: "jiti@npm:1.17.1" + bin: + jiti: bin/jiti.js + checksum: 56c6d8488e7e9cc6ee66a0f0d5e18db6669cb12b2e93364f393442289a9bc75a8e8c796249f59015e01c3ebdf9478e2ca8b76c30e29072c678ee00d39de757c7 + languageName: node + linkType: hard + +"jiti@npm:^1.17.1": + version: 1.17.2 + resolution: "jiti@npm:1.17.2" + bin: + jiti: bin/jiti.js + checksum: 51941fea3622d1ff80d914ec6ec95ae463ede598a4a2317f1e8ff018823212eba6b9ea1c638c97c18f681870b1c2b9f49fbb13021b7c2415c46c8a3b1910f1e3 + languageName: node + linkType: hard + "jju@npm:~1.4.0": version: 1.4.0 resolution: "jju@npm:1.4.0" @@ -27051,7 +27563,7 @@ __metadata: languageName: node linkType: hard -"js-yaml@npm:^3.10.0, js-yaml@npm:^3.13.0, js-yaml@npm:^3.13.1, js-yaml@npm:^3.14.1, js-yaml@npm:^3.6.1, js-yaml@npm:^3.8.3": +"js-yaml@npm:^3.10.0, js-yaml@npm:^3.13.0, js-yaml@npm:^3.13.1, js-yaml@npm:^3.6.1, js-yaml@npm:^3.8.3": version: 3.14.1 resolution: "js-yaml@npm:3.14.1" dependencies: @@ -27814,9 +28326,9 @@ __metadata: linkType: hard "kafkajs@npm:^2.0.0": - version: 2.2.3 - resolution: "kafkajs@npm:2.2.3" - checksum: 30f17de75da852942334b6069c5c515e2531a7b610997f0e4c6088281f16588df45ac920218411d9ae995c09af1f69186ed4d73cbe0e5f1247ec756dd9c7678e + version: 2.2.4 + resolution: "kafkajs@npm:2.2.4" + checksum: 83e9e8bc50a09b142f4ff79f6a2bd88ecc21b83bcefe6621ab1716118d624886befb7371731274f67812ce35dd50b53140ff3b49a06e5d9169fe6b164d72fea5 languageName: node linkType: hard @@ -27937,6 +28449,16 @@ __metadata: languageName: node linkType: hard +"launch-editor@npm:^2.6.0": + version: 2.6.0 + resolution: "launch-editor@npm:2.6.0" + dependencies: + picocolors: ^1.0.0 + shell-quote: ^1.7.3 + checksum: 48e4230643e8fdb5c14c11314706d58d9f3fbafe2606be3d6e37da1918ad8bfe39dd87875c726a1b59b9f4da99d87ec3e36d4c528464f0b820f9e91e5cb1c02d + languageName: node + linkType: hard + "lazy-ass@npm:1.6.0, lazy-ass@npm:^1.6.0": version: 1.6.0 resolution: "lazy-ass@npm:1.6.0" @@ -28050,10 +28572,10 @@ __metadata: languageName: node linkType: hard -"lilconfig@npm:2.0.6, lilconfig@npm:^2.0.3": - version: 2.0.6 - resolution: "lilconfig@npm:2.0.6" - checksum: 40a3cd72f103b1be5975f2ac1850810b61d4053e20ab09be8d3aeddfe042187e1ba70b4651a7e70f95efa1642e7dc8b2ae395b317b7d7753b241b43cef7c0f7d +"lilconfig@npm:2.1.0, lilconfig@npm:^2.0.3": + version: 2.1.0 + resolution: "lilconfig@npm:2.1.0" + checksum: 8549bb352b8192375fed4a74694cd61ad293904eee33f9d4866c2192865c44c4eb35d10782966242634e0cbc1e91fe62b1247f148dc5514918e3a966da7ea117 languageName: node linkType: hard @@ -28093,25 +28615,25 @@ __metadata: linkType: hard "lint-staged@npm:^13.0.0": - version: 13.1.2 - resolution: "lint-staged@npm:13.1.2" + version: 13.2.0 + resolution: "lint-staged@npm:13.2.0" dependencies: + chalk: 5.2.0 cli-truncate: ^3.1.0 - colorette: ^2.0.19 - commander: ^9.4.1 + commander: ^10.0.0 debug: ^4.3.4 - execa: ^6.1.0 - lilconfig: 2.0.6 - listr2: ^5.0.5 + execa: ^7.0.0 + lilconfig: 2.1.0 + listr2: ^5.0.7 micromatch: ^4.0.5 normalize-path: ^3.0.0 - object-inspect: ^1.12.2 + object-inspect: ^1.12.3 pidtree: ^0.6.0 string-argv: ^0.3.1 - yaml: ^2.1.3 + yaml: ^2.2.1 bin: lint-staged: bin/lint-staged.js - checksum: f854ad5c88542b8f06e27f3b4046927a4f3d4a451a04e079526559d819a325762268f65bd2df7156bcc0cb5f531f621c42cdb824b403f537c78305adc9e56a54 + checksum: dcaa8fbbde567eb8ac27230a18b3a22f30c278c524c0e27cf7d4110d662d5d33ed68a585a2e1b05075ef1c262e853f557a5ae046188b723603246d63e6b9f07b languageName: node linkType: hard @@ -28157,16 +28679,16 @@ __metadata: languageName: node linkType: hard -"listr2@npm:^5.0.5": - version: 5.0.5 - resolution: "listr2@npm:5.0.5" +"listr2@npm:^5.0.7": + version: 5.0.7 + resolution: "listr2@npm:5.0.7" dependencies: cli-truncate: ^2.1.0 colorette: ^2.0.19 log-update: ^4.0.0 p-map: ^4.0.0 rfdc: ^1.3.0 - rxjs: ^7.5.6 + rxjs: ^7.8.0 through: ^2.3.8 wrap-ansi: ^7.0.0 peerDependencies: @@ -28174,7 +28696,7 @@ __metadata: peerDependenciesMeta: enquirer: optional: true - checksum: 71c44eb648405d2725f248747ef8d5e192dd16938ec81df854c4a7e74ff1b3f4c3149461b1cff31c761bfbdf110f7f2603c9957c908294a1c6db299c9168608c + checksum: 5c2cb6ba3f7a5cfd548f89405febe73dc937acb6060227198c05da0ed5d5285a8107c61fcc4e33884e3bbdd447411aff7580af396bd22b6a11047ceab4950fab languageName: node linkType: hard @@ -28470,7 +28992,7 @@ __metadata: languageName: node linkType: hard -"lodash@npm:4.17.21, lodash@npm:^4.17.10, lodash@npm:^4.17.11, lodash@npm:^4.17.14, lodash@npm:^4.17.15, lodash@npm:^4.17.19, lodash@npm:^4.17.20, lodash@npm:^4.17.21, lodash@npm:^4.17.4, lodash@npm:^4.7.0, lodash@npm:~4.17.0, lodash@npm:~4.17.15": +"lodash@npm:4.17.21, lodash@npm:^4.15.0, lodash@npm:^4.17.10, lodash@npm:^4.17.11, lodash@npm:^4.17.14, lodash@npm:^4.17.15, lodash@npm:^4.17.19, lodash@npm:^4.17.20, lodash@npm:^4.17.21, lodash@npm:^4.17.4, lodash@npm:^4.7.0, lodash@npm:~4.17.0, lodash@npm:~4.17.15": version: 4.17.21 resolution: "lodash@npm:4.17.21" checksum: eb835a2e51d381e561e508ce932ea50a8e5a68f4ebdd771ea240d3048244a8d13658acbd502cd4829768c56f2e16bdd4340b9ea141297d472517b83868e677f7 @@ -28615,10 +29137,10 @@ __metadata: languageName: node linkType: hard -"lru-cache@npm:^7.10.1, lru-cache@npm:^7.7.1": - version: 7.10.1 - resolution: "lru-cache@npm:7.10.1" - checksum: e8b190d71ed0fcd7b29c71a3e9b01f851c92d1ef8865ff06b5581ca991db1e5e006920ed4da8b56da1910664ed51abfd76c46fb55e82ac252ff6c970ff910d72 +"lru-cache@npm:^7.10.1, lru-cache@npm:^7.14.1, lru-cache@npm:^7.7.1": + version: 7.18.3 + resolution: "lru-cache@npm:7.18.3" + checksum: e550d772384709deea3f141af34b6d4fa392e2e418c1498c078de0ee63670f1f46f5eee746e8ef7e69e1c895af0d4224e62ee33e66a543a14763b0f2e74c1356 languageName: node linkType: hard @@ -28822,6 +29344,15 @@ __metadata: languageName: node linkType: hard +"markdown-to-jsx@npm:^7.1.9": + version: 7.2.0 + resolution: "markdown-to-jsx@npm:7.2.0" + peerDependencies: + react: ">= 0.14.0" + checksum: ea417e684d7eec9f1beebc9423aba377116ef77c3cd83a2d622df1b9030ffef99aa9b3f431192b94f3237943a33560e6dda9be8a4c1d25187518d09986dad22f + languageName: node + linkType: hard + "marked@npm:^4.0.10, marked@npm:^4.0.14": version: 4.2.12 resolution: "marked@npm:4.2.12" @@ -29635,6 +30166,15 @@ __metadata: languageName: node linkType: hard +"minim@npm:=0.23.8": + version: 0.23.8 + resolution: "minim@npm:0.23.8" + dependencies: + lodash: ^4.15.0 + checksum: 98e19a431189cee4dfad766e19948fb65b3607780bda2dc3f76b7bb35f9a468f372fb1b4c4b2ebfe348191e09f2b981579967b29cf02038798efe4eab326ffca + languageName: node + linkType: hard + "minimalistic-assert@npm:^1.0.0, minimalistic-assert@npm:^1.0.1": version: 1.0.1 resolution: "minimalistic-assert@npm:1.0.1" @@ -29658,12 +30198,21 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:4.2.1": - version: 4.2.1 - resolution: "minimatch@npm:4.2.1" +"minimatch@npm:4.2.3": + version: 4.2.3 + resolution: "minimatch@npm:4.2.3" dependencies: brace-expansion: ^1.1.7 - checksum: 2b1514e3d0f29a549912f0db7ae7b82c5cab4a8f2dd0369f1c6451a325b3f12b2cf473c95873b6157bb8df183d6cf6db82ff03614b6adaaf1d7e055beccdfd01 + checksum: 3392388e3ef7de7ae9a3a48d48a27a323934452f4af81b925dfbe85ce2dc07da855e3dbcc69229888be4e5118f6c0b79847d30f3e7c0e0017b25e423c11c0409 + languageName: node + linkType: hard + +"minimatch@npm:=7.3.0": + version: 7.3.0 + resolution: "minimatch@npm:7.3.0" + dependencies: + brace-expansion: ^2.0.1 + checksum: c4d9af992958339d5fc593c9ce496f4b9615597e57cdd663e57bd3a745ebd208c2bba19c3290c25ed8dcf259586fa1f68e4e1acf304f8694927b84c5381167d0 languageName: node linkType: hard @@ -29947,8 +30496,8 @@ __metadata: linkType: hard "msw@npm:^1.0.0, msw@npm:^1.0.1": - version: 1.0.1 - resolution: "msw@npm:1.0.1" + version: 1.2.0 + resolution: "msw@npm:1.2.0" dependencies: "@mswjs/cookies": ^0.2.2 "@mswjs/interceptors": ^0.17.5 @@ -29970,13 +30519,13 @@ __metadata: type-fest: ^2.19.0 yargs: ^17.3.1 peerDependencies: - typescript: ">= 4.4.x <= 4.9.x" + typescript: ">= 4.4.x <= 5.0.x" peerDependenciesMeta: typescript: optional: true bin: msw: cli/index.js - checksum: e5d6cbe67067ca46f42aaa33011f53a4e5a873abcf81c52a6996536b3c41a88f522821d3a4cf589658252581506afddb58fd8c3dfd79a5cbf06e26e14f9570b6 + checksum: 2cea7fe0f2ebb59b11534896cbaa91dca65f4fb2272402549079cc4190847fc42f5367f331c552d576d59a3521f498da0384d53cf4960beaebd6165bbc44593b languageName: node linkType: hard @@ -30048,7 +30597,7 @@ __metadata: languageName: node linkType: hard -"nan@npm:^2.14.1, nan@npm:^2.15.0, nan@npm:^2.17.0": +"nan@npm:^2.14.0, nan@npm:^2.14.1, nan@npm:^2.15.0, nan@npm:^2.17.0": version: 2.17.0 resolution: "nan@npm:2.17.0" dependencies: @@ -30172,6 +30721,15 @@ __metadata: languageName: node linkType: hard +"node-abi@npm:^2.21.0": + version: 2.30.1 + resolution: "node-abi@npm:2.30.1" + dependencies: + semver: ^5.4.1 + checksum: 3f4b0c912ce4befcd7ceab4493ba90b51d60dfcc90f567c93f731d897ef8691add601cb64c181683b800f21d479d68f9a6e15d8ab8acd16a5706333b9e30a881 + languageName: node + linkType: hard + "node-abi@npm:^3.3.0": version: 3.8.0 resolution: "node-abi@npm:3.8.0" @@ -30181,10 +30739,10 @@ __metadata: languageName: node linkType: hard -"node-abort-controller@npm:^3.0.1": - version: 3.0.1 - resolution: "node-abort-controller@npm:3.0.1" - checksum: 2b3d75c65249fea99e8ba22da3a8bc553f034f44dd12f5f4b38b520f718b01c88718c978f0c24c2a460fc01de9a80b567028f547b94440cb47adeacfeb82c2ee +"node-abort-controller@npm:^3.0.1, node-abort-controller@npm:^3.1.1": + version: 3.1.1 + resolution: "node-abort-controller@npm:3.1.1" + checksum: 2c340916af9710328b11c0828223fc65ba320e0d082214a211311bf64c2891028e42ef276b9799188c4ada9e6e1c54cf7a0b7c05dd9d59fcdc8cd633304c8047 languageName: node linkType: hard @@ -30393,8 +30951,8 @@ __metadata: linkType: hard "nodemon@npm:^2.0.2": - version: 2.0.21 - resolution: "nodemon@npm:2.0.21" + version: 2.0.22 + resolution: "nodemon@npm:2.0.22" dependencies: chokidar: ^3.5.2 debug: ^3.2.7 @@ -30408,7 +30966,7 @@ __metadata: undefsafe: ^2.0.5 bin: nodemon: bin/nodemon.js - checksum: 0b9fe2d11fd95c51b66d61bd1ee85cddf579c9e674c9429752a74f445f1b98576235ae860858783728baa3666c87e4ef938ab67167cc34fe4bb8fcec74d6885b + checksum: 9c987e139748f5b5c480c6c9080bdc97304ee7d29172b7b3da1a7db590b1323ad57b96346304e9b522b0e445c336dc393ccd3f9f45c73b20d476d2347890dcd0 languageName: node linkType: hard @@ -30611,7 +31169,7 @@ __metadata: languageName: node linkType: hard -"npmlog@npm:^4.1.2": +"npmlog@npm:^4.0.1, npmlog@npm:^4.1.2": version: 4.1.2 resolution: "npmlog@npm:4.1.2" dependencies: @@ -30730,10 +31288,10 @@ __metadata: languageName: node linkType: hard -"object-inspect@npm:^1.12.2, object-inspect@npm:^1.9.0": - version: 1.12.2 - resolution: "object-inspect@npm:1.12.2" - checksum: a534fc1b8534284ed71f25ce3a496013b7ea030f3d1b77118f6b7b1713829262be9e6243acbcb3ef8c626e2b64186112cb7f6db74e37b2789b9c789ca23048b2 +"object-inspect@npm:^1.12.2, object-inspect@npm:^1.12.3, object-inspect@npm:^1.9.0": + version: 1.12.3 + resolution: "object-inspect@npm:1.12.3" + checksum: dabfd824d97a5f407e6d5d24810d888859f6be394d8b733a77442b277e0808860555176719c5905e765e3743a7cada6b8b0a3b85e5331c530fd418cc8ae991db languageName: node linkType: hard @@ -30959,6 +31517,16 @@ __metadata: languageName: node linkType: hard +"optimism@npm:^0.16.1": + version: 0.16.2 + resolution: "optimism@npm:0.16.2" + dependencies: + "@wry/context": ^0.7.0 + "@wry/trie": ^0.3.0 + checksum: a98ed9a0b8ee2b031010222099b60860d52860bf8182889f2695a7cf2185f21aca59020f78e2b47c0ae7697843caa576798d792967314ff59f6aa7c5d9de7f3a + languageName: node + linkType: hard + "optionator@npm:^0.8.1": version: 0.8.3 resolution: "optionator@npm:0.8.3" @@ -31391,7 +31959,7 @@ __metadata: languageName: node linkType: hard -"parseurl@npm:^1.3.3, parseurl@npm:~1.3.2, parseurl@npm:~1.3.3": +"parseurl@npm:~1.3.2, parseurl@npm:~1.3.3": version: 1.3.3 resolution: "parseurl@npm:1.3.3" checksum: 407cee8e0a3a4c5cd472559bca8b6a45b82c124e9a4703302326e9ab60fc1081442ada4e02628efef1eb16197ddc7f8822f5a91fd7d7c86b51f530aedb17dfa2 @@ -31477,7 +32045,7 @@ __metadata: languageName: node linkType: hard -"passport-oauth2@npm:1.6.1, passport-oauth2@npm:1.x.x, passport-oauth2@npm:^1.1.2, passport-oauth2@npm:^1.4.0, passport-oauth2@npm:^1.6.0, passport-oauth2@npm:^1.6.1": +"passport-oauth2@npm:1.6.1": version: 1.6.1 resolution: "passport-oauth2@npm:1.6.1" dependencies: @@ -31490,6 +32058,19 @@ __metadata: languageName: node linkType: hard +"passport-oauth2@npm:1.x.x, passport-oauth2@npm:^1.1.2, passport-oauth2@npm:^1.4.0, passport-oauth2@npm:^1.6.0, passport-oauth2@npm:^1.6.1": + version: 1.7.0 + resolution: "passport-oauth2@npm:1.7.0" + dependencies: + base64url: 3.x.x + oauth: 0.9.x + passport-strategy: 1.x.x + uid2: 0.0.x + utils-merge: 1.x.x + checksum: 9e93f1f47ad5c22ef119932e03f383b503f692012352f27d2a416cc45ca5448c5a97f726da51753fff9a2ec2b6255ac27f1e68c4b44538530d2a8de682f17d42 + languageName: node + linkType: hard + "passport-oauth@npm:1.0.0, passport-oauth@npm:^1.0.0": version: 1.0.0 resolution: "passport-oauth@npm:1.0.0" @@ -31799,12 +32380,12 @@ __metadata: languageName: node linkType: hard -"pg-pool@npm:^3.5.2": - version: 3.5.2 - resolution: "pg-pool@npm:3.5.2" +"pg-pool@npm:^3.6.0": + version: 3.6.0 + resolution: "pg-pool@npm:3.6.0" peerDependencies: pg: ">=8.0" - checksum: a5d029200257671f0c17ca54b9ab6213e2060e64e5cc792b78edd50ab471a26cd364890d05d546d9296949e079e943821cf2ceb4d488f4e6a6789fb781a628bf + checksum: f3fe050fbfe27406369340c4c26efcbe21a388ace085a876453de0ea496a315c38b2dc739ac97d4767a359e911da2ec4810467f72601eeec8ad540e58b27987c languageName: node linkType: hard @@ -31829,13 +32410,13 @@ __metadata: linkType: hard "pg@npm:^8.3.0, pg@npm:^8.4.0": - version: 8.9.0 - resolution: "pg@npm:8.9.0" + version: 8.10.0 + resolution: "pg@npm:8.10.0" dependencies: buffer-writer: 2.0.0 packet-reader: 1.0.0 pg-connection-string: ^2.5.0 - pg-pool: ^3.5.2 + pg-pool: ^3.6.0 pg-protocol: ^1.6.0 pg-types: ^2.1.0 pgpass: 1.x @@ -31844,7 +32425,7 @@ __metadata: peerDependenciesMeta: pg-native: optional: true - checksum: dfd158955318f9ffb9428eaada29f3ee98b9eb07e87ed4b56589a19984d109f23bb8f88db78b7d7f870553e5b75ca0d58d0ed55755a8c6aed5df44e038c1d529 + checksum: c6be78f2e823f2ae3c618c8e54a6622592dd71b556fb665d7eaedcbcc2fa5d210a8bcf519401e72526a65b9d797f19b772f48f29b9d9f31e98dd526fd27d61e0 languageName: node linkType: hard @@ -32517,6 +33098,29 @@ __metadata: languageName: node linkType: hard +"prebuild-install@npm:^6.0.1": + version: 6.1.4 + resolution: "prebuild-install@npm:6.1.4" + dependencies: + detect-libc: ^1.0.3 + expand-template: ^2.0.3 + github-from-package: 0.0.0 + minimist: ^1.2.3 + mkdirp-classic: ^0.5.3 + napi-build-utils: ^1.0.1 + node-abi: ^2.21.0 + npmlog: ^4.0.1 + pump: ^3.0.0 + rc: ^1.2.7 + simple-get: ^3.0.3 + tar-fs: ^2.0.0 + tunnel-agent: ^0.6.0 + bin: + prebuild-install: bin.js + checksum: de4313eda821305912af922700a2db04bb8e77fe8aa9c2788550f1000c026cbefc82da468ec0c0a37764c5417bd8169dbd540928535fb38d00bb9bbd673dd217 + languageName: node + linkType: hard + "prebuild-install@npm:^7.1.0, prebuild-install@npm:^7.1.1": version: 7.1.1 resolution: "prebuild-install@npm:7.1.1" @@ -32573,11 +33177,11 @@ __metadata: linkType: hard "prettier@npm:^2.2.1, prettier@npm:^2.7.1": - version: 2.8.4 - resolution: "prettier@npm:2.8.4" + version: 2.8.6 + resolution: "prettier@npm:2.8.6" bin: prettier: bin-prettier.js - checksum: c173064bf3df57b6d93d19aa98753b9b9dd7657212e33b41ada8e2e9f9884066bb9ca0b4005b89b3ab137efffdf8fbe0b462785aba20364798ff4303aadda57e + checksum: 8ac94fa67aec0e65743ea15ebf954ef2f1e52638abd129dc04e8b49e8bb3224c0233c98df6b5c98efd31bd2a43866590486559438ee4ead09dc81be389068572 languageName: node linkType: hard @@ -32662,7 +33266,7 @@ __metadata: languageName: node linkType: hard -"process@npm:^0.11.10": +"process@npm:=0.11.10, process@npm:^0.11.10": version: 0.11.10 resolution: "process@npm:0.11.10" checksum: bfcce49814f7d172a6e6a14d5fa3ac92cc3d0c3b9feb1279774708a719e19acd673995226351a082a9ae99978254e320ccda4240ddc474ba31a76c79491ca7c3 @@ -32677,11 +33281,11 @@ __metadata: linkType: hard "prom-client@npm:^14.0.1": - version: 14.1.1 - resolution: "prom-client@npm:14.1.1" + version: 14.2.0 + resolution: "prom-client@npm:14.2.0" dependencies: tdigest: ^0.1.1 - checksum: 7ff3e85636b1f0ca590b38ad7c7c5f9998b985c06a1c572ffffc69f052d5b4baf84c9124923e3824c63f78b5e8400081c6472173d04382ca296ebdf36d774a88 + checksum: d4c04e57616c72643dd02862d0d4bde09cf8869a19d0aef5e7b785e6e27d02439b66cdc165e3492f62d579fa91579183820870cc757a09b99399d2d02f46b9f1 languageName: node linkType: hard @@ -32885,7 +33489,7 @@ __metadata: languageName: node linkType: hard -"proxy-from-env@npm:1.1.0": +"proxy-from-env@npm:1.1.0, proxy-from-env@npm:^1.1.0": version: 1.1.0 resolution: "proxy-from-env@npm:1.1.0" checksum: ed7fcc2ba0a33404958e34d95d18638249a68c430e30fcb6c478497d72739ba64ce9810a24f53a7d921d0c065e5b78e3822759800698167256b04659366ca4d4 @@ -33081,7 +33685,16 @@ __metadata: languageName: node linkType: hard -"ramda@npm:^0.28.0": +"ramda-adjunct@npm:=3.4.0": + version: 3.4.0 + resolution: "ramda-adjunct@npm:3.4.0" + peerDependencies: + ramda: ">= 0.28.0 <= 0.28.0" + checksum: 05d4daa44a28879dafc75adba6d0b660f8fc0280c03ad62c51ba779d93b11fdaa28a039b28f7ea4a8ca42fdb0a2a750b793fa073125bcc74799630e58cd4770f + languageName: node + linkType: hard + +"ramda@npm:=0.28.0, ramda@npm:^0.28.0": version: 0.28.0 resolution: "ramda@npm:0.28.0" checksum: 44ea6e5010bba70151b6a92d8114a91915e8b5a16105cce65fae58c9d7386b812c429645e35f21141d7087568550ce383bc10ee1a65cdec951f4b69ea457e6a4 @@ -33150,7 +33763,7 @@ __metadata: languageName: node linkType: hard -"raw-body@npm:^2.4.1": +"raw-body@npm:2.5.2, raw-body@npm:^2.4.1": version: 2.5.2 resolution: "raw-body@npm:2.5.2" dependencies: @@ -33445,8 +34058,8 @@ __metadata: linkType: hard "react-markdown@npm:^8.0.0": - version: 8.0.5 - resolution: "react-markdown@npm:8.0.5" + version: 8.0.6 + resolution: "react-markdown@npm:8.0.6" dependencies: "@types/hast": ^2.0.0 "@types/prop-types": ^15.0.0 @@ -33466,11 +34079,11 @@ __metadata: peerDependencies: "@types/react": ">=16" react: ">=16" - checksum: 9d11b7aba16216d590e56b4744e05d2925141bfb0f5885b3d9400ccf006cd24b79ce3b3d20af8a083a01324215b58fa4c5979e44f69d54123ff1dd5dacb0dc89 + checksum: 59fd5dcd089df0cd9098755e3063d8fcf4b4635b1ac2d5e05fcda9923769724476396abdf2afb80fb8e7589a951deac50d6f89c4740d5ec6decd34076122c80c languageName: node linkType: hard -"react-redux@npm:^7.1.1, react-redux@npm:^7.2.4": +"react-redux@npm:^7.1.1": version: 7.2.5 resolution: "react-redux@npm:7.2.5" dependencies: @@ -33491,6 +34104,38 @@ __metadata: languageName: node linkType: hard +"react-redux@npm:^8.0.5": + version: 8.0.5 + resolution: "react-redux@npm:8.0.5" + dependencies: + "@babel/runtime": ^7.12.1 + "@types/hoist-non-react-statics": ^3.3.1 + "@types/use-sync-external-store": ^0.0.3 + hoist-non-react-statics: ^3.3.2 + react-is: ^18.0.0 + use-sync-external-store: ^1.0.0 + peerDependencies: + "@types/react": ^16.8 || ^17.0 || ^18.0 + "@types/react-dom": ^16.8 || ^17.0 || ^18.0 + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + react-native: ">=0.59" + redux: ^4 + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + react-dom: + optional: true + react-native: + optional: true + redux: + optional: true + checksum: a108f4f7ead6ac005e656d46051474a2bbdb31ede481bbbb3d8d779c1a35e1940b8655577cc5021313411864d305f67fc719aa48d6e5ed8288cf9cbe8b7042e4 + languageName: node + linkType: hard + "react-refresh@npm:^0.14.0": version: 0.14.0 resolution: "react-refresh@npm:0.14.0" @@ -34101,7 +34746,7 @@ __metadata: languageName: node linkType: hard -"regenerator-runtime@npm:^0.13.11, regenerator-runtime@npm:^0.13.4": +"regenerator-runtime@npm:^0.13.11": version: 0.13.11 resolution: "regenerator-runtime@npm:0.13.11" checksum: 27481628d22a1c4e3ff551096a683b424242a216fee44685467307f14d58020af1e19660bf2e26064de946bad7eff28950eae9f8209d55723e2d9351e632bbb4 @@ -34522,6 +35167,13 @@ __metadata: languageName: node linkType: hard +"response-iterator@npm:^0.2.6": + version: 0.2.6 + resolution: "response-iterator@npm:0.2.6" + checksum: b0db3c0665a0d698d65512951de9623c086b9c84ce015a76076d4bd0bf733779601d0b41f0931d16ae38132fba29e1ce291c1f8e6550fc32daaa2dc3ab4f338d + languageName: node + linkType: hard + "responselike@npm:^2.0.0": version: 2.0.0 resolution: "responselike@npm:2.0.0" @@ -34866,7 +35518,7 @@ __metadata: languageName: node linkType: hard -"rxjs@npm:^7.0.0, rxjs@npm:^7.2.0, rxjs@npm:^7.5.1, rxjs@npm:^7.5.5, rxjs@npm:^7.5.6, rxjs@npm:^7.8.0": +"rxjs@npm:^7.0.0, rxjs@npm:^7.2.0, rxjs@npm:^7.5.1, rxjs@npm:^7.5.5, rxjs@npm:^7.8.0": version: 7.8.0 resolution: "rxjs@npm:7.8.0" dependencies: @@ -35386,6 +36038,16 @@ __metadata: languageName: node linkType: hard +"short-unique-id@npm:=4.4.4": + version: 4.4.4 + resolution: "short-unique-id@npm:4.4.4" + bin: + short-unique-id: bin/short-unique-id + suid: bin/short-unique-id + checksum: 3507f2e97326e49180dd4edbf41dd762a76c591df3fd5b7c1e7592bfb0c2f5724d63e626cc6f581c717d3111374811ca1d77a728ac07b0b9041b2355700124d4 + languageName: node + linkType: hard + "shx@npm:^0.3.2": version: 0.3.4 resolution: "shx@npm:0.3.4" @@ -35988,6 +36650,13 @@ __metadata: languageName: node linkType: hard +"stampit@npm:=4.3.2": + version: 4.3.2 + resolution: "stampit@npm:4.3.2" + checksum: 731dfe564b98371293bb5e7cb76bb195336dd3589af4e448d1478ac6c99091fd302fd7f41a255daa4b0ec2c1f14ea4f0cc0a2f05cd3d786b29ba531850ad7f62 + languageName: node + linkType: hard + "standard-as-callback@npm:^2.1.0": version: 2.1.0 resolution: "standard-as-callback@npm:2.1.0" @@ -36414,11 +37083,11 @@ __metadata: linkType: hard "style-loader@npm:^3.3.1": - version: 3.3.1 - resolution: "style-loader@npm:3.3.1" + version: 3.3.2 + resolution: "style-loader@npm:3.3.2" peerDependencies: webpack: ^5.0.0 - checksum: 470feef680f59e2fce4d6601b5c55b88c01ad8d1dd693c528ffd591ff5fd7c01a4eff3bdbe62f26f847d6bd2430c9ab594be23307cfe7a3446ab236683f0d066 + checksum: 5ee5ce2dc885369eccb55d429376e83d02570d473ac5edeb69fd65ee894847f1e51429cf078351f617bd04516ece8a1dd967f9f40464bd8fa76d903c6b2a6f08 languageName: node linkType: hard @@ -36495,8 +37164,8 @@ __metadata: linkType: hard "sucrase@npm:^3.20.2": - version: 3.29.0 - resolution: "sucrase@npm:3.29.0" + version: 3.30.0 + resolution: "sucrase@npm:3.30.0" dependencies: commander: ^4.0.0 glob: 7.1.6 @@ -36507,7 +37176,7 @@ __metadata: bin: sucrase: bin/sucrase sucrase-node: bin/sucrase-node - checksum: fc8f04c34f29c0e9ca63109815df138182d62663dbe9565fcd94161b77a88a639f40c46559d0bb84d7acf9346ce23ea102476fd9168ec279330c7faecefb81eb + checksum: 9d53ee132f8063573c9f336c2dbc00a1f91fb976a4ad4dca29a15a898d361e6d4a06ada086c6881fe63389d96392cbd761d790a8175a6ecb184eaa337d58f363 languageName: node linkType: hard @@ -36605,14 +37274,18 @@ __metadata: languageName: node linkType: hard -"swagger-client@npm:^3.18.5": - version: 3.18.5 - resolution: "swagger-client@npm:3.18.5" +"swagger-client@npm:^3.19.1": + version: 3.19.2 + resolution: "swagger-client@npm:3.19.2" dependencies: - "@babel/runtime-corejs3": ^7.11.2 + "@babel/runtime-corejs3": ^7.20.13 + "@swagger-api/apidom-core": =0.69.0 + "@swagger-api/apidom-json-pointer": =0.69.0 + "@swagger-api/apidom-ns-openapi-3-1": =0.69.0 + "@swagger-api/apidom-reference": =0.69.0 cookie: ~0.5.0 cross-fetch: ^3.1.5 - deepmerge: ~4.2.2 + deepmerge: ~4.3.0 fast-json-patch: ^3.0.0-1 form-data-encoder: ^1.4.3 formdata-node: ^4.0.0 @@ -36622,16 +37295,16 @@ __metadata: qs: ^6.10.2 traverse: ~0.6.6 url: ~0.11.0 - checksum: 804260814abffbb97266b23be20ef8503cf21143684fb81f134ce4f7e0287e6b47b403f0fc0d9e2121bedb1309af6d50f76701ee4bf3390365558d82f4b40786 + checksum: 9613387191b6e72afbe1e551d70646b7c74a136160d2a69ac3220cf23007175c500d3035b0c9ebf1ef0b49769a65d54cf343eb3b0c0d260c5797338776c872ba languageName: node linkType: hard "swagger-ui-react@npm:^4.11.1": - version: 4.15.5 - resolution: "swagger-ui-react@npm:4.15.5" + version: 4.18.1 + resolution: "swagger-ui-react@npm:4.18.1" dependencies: "@babel/runtime-corejs3": ^7.18.9 - "@braintree/sanitize-url": =6.0.0 + "@braintree/sanitize-url": =6.0.2 base64-js: ^1.5.1 classnames: ^2.3.1 css.escape: 1.5.1 @@ -36651,7 +37324,7 @@ __metadata: react-immutable-proptypes: 2.2.0 react-immutable-pure-component: ^2.2.0 react-inspector: ^6.0.1 - react-redux: ^7.2.4 + react-redux: ^8.0.5 react-syntax-highlighter: ^15.5.0 redux: ^4.1.2 redux-immutable: ^4.0.0 @@ -36659,7 +37332,7 @@ __metadata: reselect: ^4.1.5 serialize-error: ^8.1.0 sha.js: ^2.4.11 - swagger-client: ^3.18.5 + swagger-client: ^3.19.1 url-parse: ^1.5.8 xml: =1.0.1 xml-but-prettier: ^1.0.1 @@ -36667,7 +37340,7 @@ __metadata: peerDependencies: react: ">=17.0.0" react-dom: ">=17.0.0" - checksum: 22a72947da865ebfa9269f66b42c2b50105b6285bcb6546f8f356cf73961f76e397b7d79003641c9569bfb2163ea98e2f3f73a27b5b66843d308786c37362e1c + checksum: 183e15d7ccab2ef9197b3695029b66fe1e0556c48bab10f63150feabc304492ae87529a1f1b3e0ee689d19f8b3645a168dff0f3edf421737ac7e8a2d320d26c4 languageName: node linkType: hard @@ -36691,13 +37364,13 @@ __metadata: linkType: hard "swr@npm:^2.0.0": - version: 2.1.0 - resolution: "swr@npm:2.1.0" + version: 2.1.1 + resolution: "swr@npm:2.1.1" dependencies: use-sync-external-store: ^1.2.0 peerDependencies: react: ^16.11.0 || ^17.0.0 || ^18.0.0 - checksum: 7de1799f319c7ebfb996cb843279169144b7087215ce7318dd6011590908341ac7d5bca93a197666557c2450b0297d9efbc610fd069b82dc3387130c619965fc + checksum: 77a7854f87c2a3244b4047eca5d88a0f5db6cb47f783fd13b8a38f5a611940142645c943e105fbfa64aac51e642361180366107ade0454744a80d6dedbe350db languageName: node linkType: hard @@ -36708,6 +37381,13 @@ __metadata: languageName: node linkType: hard +"symbol-observable@npm:^4.0.0": + version: 4.0.0 + resolution: "symbol-observable@npm:4.0.0" + checksum: 212c7edce6186634d671336a88c0e0bbd626c2ab51ed57498dc90698cce541839a261b969c2a1e8dd43762133d47672e8b62e0b1ce9cf4157934ba45fd172ba8 + languageName: node + linkType: hard + "symbol-tree@npm:^3.2.4": version: 3.2.4 resolution: "symbol-tree@npm:3.2.4" @@ -37256,6 +37936,37 @@ __metadata: languageName: node linkType: hard +"tree-sitter-json@npm:=0.20.0": + version: 0.20.0 + resolution: "tree-sitter-json@npm:0.20.0" + dependencies: + nan: ^2.14.1 + node-gyp: latest + checksum: 820e27b644e3ec62d8753976572660fbc314b0ffb10178384ae0d187187797c3d87223bec6b034e602445e4095484a28fb89ca67653a1d4f41fa13dd6adad0d2 + languageName: node + linkType: hard + +"tree-sitter-yaml@npm:=0.5.0": + version: 0.5.0 + resolution: "tree-sitter-yaml@npm:0.5.0" + dependencies: + nan: ^2.14.0 + node-gyp: latest + checksum: 7962aea3784dd67098daff4ae984145189eb49b8f981f5a9e72bac97b77859a75030580d199712d671cdced5326599192b3549a428e162e9858a3bbb4cb2fff6 + languageName: node + linkType: hard + +"tree-sitter@npm:=0.20.1": + version: 0.20.1 + resolution: "tree-sitter@npm:0.20.1" + dependencies: + nan: ^2.14.0 + node-gyp: latest + prebuild-install: ^6.0.1 + checksum: a33bf01f9dc558aa0075c9634d06743ed9b7fbf273d2acfbe96daf83f48aec46be7dc42d80d2423c36593d36d3bf189d3fa023d6ce389e20ff9527fae118b215 + languageName: node + linkType: hard + "treeverse@npm:^1.0.4": version: 1.0.4 resolution: "treeverse@npm:1.0.4" @@ -37305,6 +38016,15 @@ __metadata: languageName: node linkType: hard +"ts-invariant@npm:^0.10.3": + version: 0.10.3 + resolution: "ts-invariant@npm:0.10.3" + dependencies: + tslib: ^2.1.0 + checksum: bb07d56fe4aae69d8860e0301dfdee2d375281159054bc24bf1e49e513fb0835bf7f70a11351344d213a79199c5e695f37ebbf5a447188a377ce0cd81d91ddb5 + languageName: node + linkType: hard + "ts-log@npm:^2.2.3": version: 2.2.3 resolution: "ts-log@npm:2.2.3" @@ -37360,6 +38080,13 @@ __metadata: languageName: node linkType: hard +"ts-toolbelt@npm:^6.15.1": + version: 6.15.5 + resolution: "ts-toolbelt@npm:6.15.5" + checksum: 24ad00cfd9ce735c76c873a9b1347eac475b94e39ebbdf100c9019dce88dd5f4babed52884cf82bb456a38c28edd0099ab6f704b84b2e5e034852b618472c1f3 + languageName: node + linkType: hard + "tsconfig-paths@npm:^3.14.1": version: 3.14.1 resolution: "tsconfig-paths@npm:3.14.1" @@ -37379,7 +38106,7 @@ __metadata: languageName: node linkType: hard -"tslib@npm:2.3.1, tslib@npm:~2.3.0": +"tslib@npm:2.3.1": version: 2.3.1 resolution: "tslib@npm:2.3.1" checksum: de17a98d4614481f7fcb5cd53ffc1aaf8654313be0291e1bfaee4b4bb31a20494b7d218ff2e15017883e8ea9626599b3b0e0229c18383ba9dce89da2adf15cb9 @@ -37393,7 +38120,7 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^2.0.0, tslib@npm:^2.0.1, tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.2.0, tslib@npm:^2.3.1, tslib@npm:^2.4.0, tslib@npm:^2.4.1, tslib@npm:~2.5.0": +"tslib@npm:^2.0.0, tslib@npm:^2.0.1, tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.2.0, tslib@npm:^2.3.0, tslib@npm:^2.3.1, tslib@npm:^2.4.0, tslib@npm:^2.4.1, tslib@npm:^2.5.0, tslib@npm:~2.5.0": version: 2.5.0 resolution: "tslib@npm:2.5.0" checksum: ae3ed5f9ce29932d049908ebfdf21b3a003a85653a9a140d614da6b767a93ef94f460e52c3d787f0e4f383546981713f165037dc2274df212ea9f8a4541004e1 @@ -37915,6 +38642,13 @@ __metadata: languageName: node linkType: hard +"unraw@npm:=2.0.1": + version: 2.0.1 + resolution: "unraw@npm:2.0.1" + checksum: af9a9d2f6e420cb4f52fe2f1f5982e6b0be95da640d6ae8d6d9ff631d864771793cb9fe7e2a16ef1ce631b94065f4438e7bd7f1701076fc69296edc4e704d42f + languageName: node + linkType: hard + "untildify@npm:^4.0.0": version: 4.0.0 resolution: "untildify@npm:4.0.0" @@ -38052,7 +38786,7 @@ __metadata: languageName: node linkType: hard -"use-sync-external-store@npm:^1.2.0": +"use-sync-external-store@npm:^1.0.0, use-sync-external-store@npm:^1.2.0": version: 1.2.0 resolution: "use-sync-external-store@npm:1.2.0" peerDependencies: @@ -38261,7 +38995,7 @@ __metadata: languageName: node linkType: hard -"value-or-promise@npm:1.0.12, value-or-promise@npm:^1.0.11": +"value-or-promise@npm:1.0.12, value-or-promise@npm:^1.0.11, value-or-promise@npm:^1.0.12": version: 1.0.12 resolution: "value-or-promise@npm:1.0.12" checksum: f53a66c75b7447c90bbaf946a757ca09c094629cb80ba742f59c980ec3a69be0a385a0e75505dedb4e757862f1a994ca4beaf083a831f24d3ffb3d4bb18cd1e1 @@ -38467,7 +39201,7 @@ __metadata: languageName: node linkType: hard -"watchpack@npm:^2.0.0-beta.10, watchpack@npm:^2.4.0": +"watchpack@npm:^2.4.0": version: 2.4.0 resolution: "watchpack@npm:2.4.0" dependencies: @@ -38522,6 +39256,13 @@ __metadata: languageName: node linkType: hard +"web-tree-sitter@npm:=0.20.7": + version: 0.20.7 + resolution: "web-tree-sitter@npm:0.20.7" + checksum: f2949a679bbca5ecb225ab26a67ff99e6e3907fa905c6bd62bfe6d2cfa216347f8cc481efcd32f181cb6b964bc03c42f9611e16da0825bff43de389b17ff9f7f + languageName: node + linkType: hard + "webcrypto-core@npm:^1.7.4": version: 1.7.5 resolution: "webcrypto-core@npm:1.7.5" @@ -38579,8 +39320,8 @@ __metadata: linkType: hard "webpack-dev-server@npm:^4.7.3": - version: 4.11.1 - resolution: "webpack-dev-server@npm:4.11.1" + version: 4.13.1 + resolution: "webpack-dev-server@npm:4.13.1" dependencies: "@types/bonjour": ^3.5.9 "@types/connect-history-api-fallback": ^1.3.5 @@ -38601,6 +39342,7 @@ __metadata: html-entities: ^2.3.2 http-proxy-middleware: ^2.0.3 ipaddr.js: ^2.0.1 + launch-editor: ^2.6.0 open: ^8.0.9 p-retry: ^4.5.0 rimraf: ^3.0.2 @@ -38610,15 +39352,17 @@ __metadata: sockjs: ^0.3.24 spdy: ^4.0.2 webpack-dev-middleware: ^5.3.1 - ws: ^8.4.2 + ws: ^8.13.0 peerDependencies: webpack: ^4.37.0 || ^5.0.0 peerDependenciesMeta: + webpack: + optional: true webpack-cli: optional: true bin: webpack-dev-server: bin/webpack-dev-server.js - checksum: b7601a39ee0f413988259e29a36835b0a68522cfaa161de5b7ec99b3399acdd99d44189add4aaf4a5191258bb130f9cf3e68919324a1955c7557f5fe6ab0d96c + checksum: f70611544b7d964a31eb3d934d7c2b376b97e6927a89e03b2e21cfa5812bb639625cd18fd350de1604ba6c455b324135523a894032f28c69d90d90682e4f3b7d languageName: node linkType: hard @@ -38647,8 +39391,8 @@ __metadata: linkType: hard "webpack@npm:^5, webpack@npm:^5.70.0": - version: 5.74.0 - resolution: "webpack@npm:5.74.0" + version: 5.76.3 + resolution: "webpack@npm:5.76.3" dependencies: "@types/eslint-scope": ^3.7.3 "@types/estree": ^0.0.51 @@ -38679,7 +39423,7 @@ __metadata: optional: true bin: webpack: bin/webpack.js - checksum: 320c41369a75051b19e18c63f408b3dcc481852e992f83d311771c5ec0f05f2946385e8ebef62030cf3587f0a3d2f12779ffdb191569a966847289ba7313f946 + checksum: 363f536b56971d056e34ab4cffa4cbc630b220e51be1a8c3adea87d9f0b51c49cfc7c3720d6614a1fd2c8c63f1ab3100db916fe8367c8bb9299327ff8c3f856d languageName: node linkType: hard @@ -39023,9 +39767,9 @@ __metadata: languageName: node linkType: hard -"ws@npm:^8.11.0, ws@npm:^8.4.2, ws@npm:^8.8.0": - version: 8.12.0 - resolution: "ws@npm:8.12.0" +"ws@npm:^8.11.0, ws@npm:^8.13.0, ws@npm:^8.8.0": + version: 8.13.0 + resolution: "ws@npm:8.13.0" peerDependencies: bufferutil: ^4.0.1 utf-8-validate: ">=5.0.2" @@ -39034,7 +39778,7 @@ __metadata: optional: true utf-8-validate: optional: true - checksum: 818ff3f8749c172a95a114cceb8b89cedd27e43a82d65c7ad0f7882b1e96a2ee6709e3746a903c3fa88beec0c8bae9a9fcd75f20858b32a166dfb7519316a5d7 + checksum: 53e991bbf928faf5dc6efac9b8eb9ab6497c69feeb94f963d648b7a3530a720b19ec2e0ec037344257e05a4f35bd9ad04d9de6f289615ffb133282031b18c61c languageName: node linkType: hard @@ -39158,18 +39902,6 @@ __metadata: languageName: node linkType: hard -"xss@npm:^1.0.8": - version: 1.0.10 - resolution: "xss@npm:1.0.10" - dependencies: - commander: ^2.20.3 - cssfilter: 0.0.10 - bin: - xss: bin/xss - checksum: 0dbc70a716020d854569610d5bc949ba9d3b7f530b7af5508ffe84edaea228c34a4e1227f71cb3a4741373b1c49c3cb691f69dddefda45a594a31f112ae6a738 - languageName: node - linkType: hard - "xtend@npm:^4.0.0": version: 4.0.2 resolution: "xtend@npm:4.0.2" @@ -39233,10 +39965,10 @@ __metadata: languageName: node linkType: hard -"yaml@npm:^2.0.0, yaml@npm:^2.1.1, yaml@npm:^2.1.3": - version: 2.1.3 - resolution: "yaml@npm:2.1.3" - checksum: 91316062324a93f9cb547469092392e7d004ff8f70c40fecb420f042a4870b2181557350da56c92f07bd44b8f7a252b0be26e6ade1f548e1f4351bdd01c9d3c7 +"yaml@npm:^2.0.0, yaml@npm:^2.1.1, yaml@npm:^2.2.1": + version: 2.2.1 + resolution: "yaml@npm:2.2.1" + checksum: 84f68cbe462d5da4e7ded4a8bded949ffa912bc264472e5a684c3d45b22d8f73a3019963a32164023bdf3d83cfb6f5b58ff7b2b10ef5b717c630f40bd6369a23 languageName: node linkType: hard @@ -39481,7 +40213,7 @@ __metadata: languageName: node linkType: hard -"zen-observable-ts@npm:^1.1.0": +"zen-observable-ts@npm:^1.1.0, zen-observable-ts@npm:^1.2.5": version: 1.2.5 resolution: "zen-observable-ts@npm:1.2.5" dependencies: