diff --git a/.changeset/beige-crabs-itch.md b/.changeset/beige-crabs-itch.md
new file mode 100644
index 0000000000..9c66e42054
--- /dev/null
+++ b/.changeset/beige-crabs-itch.md
@@ -0,0 +1,6 @@
+---
+'@backstage/core-components': patch
+'@backstage/plugin-api-docs': patch
+---
+
+chore(deps): bump `react-syntax-highligher` and `swagger-ui-react`
diff --git a/.changeset/brave-pugs-fold.md b/.changeset/brave-pugs-fold.md
deleted file mode 100644
index f79867a719..0000000000
--- a/.changeset/brave-pugs-fold.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/test-utils': patch
----
-
-Add new `MockConfigApi` as a more discoverable and leaner method for mocking configuration.
diff --git a/.changeset/clean-wolves-jog.md b/.changeset/clean-wolves-jog.md
deleted file mode 100644
index 70ab23715f..0000000000
--- a/.changeset/clean-wolves-jog.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/config': patch
----
-
-The `ConfigReader#get` method now always returns a deep clone of the configuration data.
diff --git a/.changeset/cold-steaks-flash.md b/.changeset/cold-steaks-flash.md
deleted file mode 100644
index 74cdcbdec2..0000000000
--- a/.changeset/cold-steaks-flash.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/plugin-scaffolder-backend': patch
----
-
-fix: Register plugin to prioritise Component kind for entityRef
diff --git a/.changeset/cold-toes-sniff.md b/.changeset/cold-toes-sniff.md
deleted file mode 100644
index 7fcfb54408..0000000000
--- a/.changeset/cold-toes-sniff.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/integration': patch
----
-
-Adds a new GitHub credentials provider (DefaultGithubCredentialsProvider). It handles multiple app configurations. It looks up the app configuration based on the url.
diff --git a/.changeset/dependabot-2af4c1d.md b/.changeset/dependabot-2af4c1d.md
deleted file mode 100644
index 93dc1d1e21..0000000000
--- a/.changeset/dependabot-2af4c1d.md
+++ /dev/null
@@ -1,6 +0,0 @@
----
-'@backstage/plugin-bazaar': patch
-'@backstage/plugin-ilert': patch
----
-
-build(deps): bump `@date-io/luxon` from 1.3.13 to 2.11.1
diff --git a/.changeset/dry-boats-tap.md b/.changeset/dry-boats-tap.md
deleted file mode 100644
index c69c4360b5..0000000000
--- a/.changeset/dry-boats-tap.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/plugin-todo-backend': patch
----
-
-Properly exported all referenced types
diff --git a/.changeset/dull-bulldogs-laugh.md b/.changeset/dull-bulldogs-laugh.md
deleted file mode 100644
index f49aa694b6..0000000000
--- a/.changeset/dull-bulldogs-laugh.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/core-components': patch
----
-
-Create a short delay when `` is opened
diff --git a/.changeset/eight-rats-raise.md b/.changeset/eight-rats-raise.md
deleted file mode 100644
index 7bc2a07f04..0000000000
--- a/.changeset/eight-rats-raise.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/plugin-catalog-backend': patch
----
-
-Add catalog permission rules.
diff --git a/.changeset/fair-bikes-scream.md b/.changeset/fair-bikes-scream.md
deleted file mode 100644
index decdfd3828..0000000000
--- a/.changeset/fair-bikes-scream.md
+++ /dev/null
@@ -1,28 +0,0 @@
----
-'@backstage/cli': minor
----
-
-ESLint upgraded to version 8 and all it's plugins updated to newest version.
-
-If you use any custom plugins for ESLint please check compatibility.
-
-```diff
-- "@typescript-eslint/eslint-plugin": "^v4.33.0",
-- "@typescript-eslint/parser": "^v4.28.3",
-+ "@typescript-eslint/eslint-plugin": "^5.9.0",
-+ "@typescript-eslint/parser": "^5.9.0",
-- "eslint": "^7.30.0",
-+ "eslint": "^8.6.0",
-- "eslint-plugin-import": "^2.20.2",
-- "eslint-plugin-jest": "^24.1.0",
-- "eslint-plugin-jsx-a11y": "^6.2.1",
-+ "eslint-plugin-import": "^2.25.4",
-+ "eslint-plugin-jest": "^25.3.4",
-+ "eslint-plugin-jsx-a11y": "^6.5.1",
-- "eslint-plugin-react": "^7.12.4",
-- "eslint-plugin-react-hooks": "^4.0.0",
-+ "eslint-plugin-react": "^7.28.0",
-+ "eslint-plugin-react-hooks": "^4.3.0",
-```
-
-Please consult changelogs from packages if you find any problems.
diff --git a/.changeset/flat-shirts-watch.md b/.changeset/flat-shirts-watch.md
deleted file mode 100644
index af6ff350da..0000000000
--- a/.changeset/flat-shirts-watch.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/plugin-tech-insights': patch
----
-
-Added possibility to pass customized title and description for the scorecards instead of using hardcoded ones.
diff --git a/.changeset/four-ghosts-sniff.md b/.changeset/four-ghosts-sniff.md
deleted file mode 100644
index 9da0ab15ed..0000000000
--- a/.changeset/four-ghosts-sniff.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/core-plugin-api': minor
----
-
-Removed the deprecated `OldIconComponent` type.
diff --git a/.changeset/funny-llamas-yell.md b/.changeset/funny-llamas-yell.md
deleted file mode 100644
index 890caaa221..0000000000
--- a/.changeset/funny-llamas-yell.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/plugin-catalog-graphql': patch
----
-
-Bump graphql versions
diff --git a/.changeset/fuzzy-llamas-collect.md b/.changeset/fuzzy-llamas-collect.md
deleted file mode 100644
index 17ee925e56..0000000000
--- a/.changeset/fuzzy-llamas-collect.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/plugin-catalog-backend-module-ldap': patch
----
-
-Make sure to avoid accidental data sharing / mutation of `set` values
diff --git a/.changeset/healthy-toes-laugh.md b/.changeset/healthy-toes-laugh.md
deleted file mode 100644
index e0db38e5e3..0000000000
--- a/.changeset/healthy-toes-laugh.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/plugin-permission-node': patch
----
-
-Add helpers for creating PermissionRules with inferred types
diff --git a/.changeset/late-plums-act.md b/.changeset/late-plums-act.md
deleted file mode 100644
index 6822f40eeb..0000000000
--- a/.changeset/late-plums-act.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/plugin-catalog-backend': patch
----
-
-Allow a custom GithubCredentialsProvider to be passed to the GitHub processors.
diff --git a/.changeset/lazy-gorillas-tell.md b/.changeset/lazy-gorillas-tell.md
deleted file mode 100644
index 672d8c221b..0000000000
--- a/.changeset/lazy-gorillas-tell.md
+++ /dev/null
@@ -1,7 +0,0 @@
----
-'@backstage/core-plugin-api': minor
----
-
-Removed previously deprecated exports: `PluginHooks`, `PluginOutput`, and `FeatureFlagOutput`.
-
-The deprecated `register` method of `PluginConfig` has been removed, as well as the deprecated `output` method of `BackstagePlugin`.
diff --git a/.changeset/light-trainers-allow.md b/.changeset/light-trainers-allow.md
new file mode 100644
index 0000000000..0ea13cd19e
--- /dev/null
+++ b/.changeset/light-trainers-allow.md
@@ -0,0 +1,22 @@
+---
+'@backstage/backend-common': patch
+'@backstage/config': patch
+'@backstage/config-loader': patch
+'@backstage/plugin-app-backend': patch
+---
+
+Loading of app configurations now reference the `@deprecated` construct from
+JSDoc to determine if a property in-use has been deprecated. Users are notified
+of deprecated keys in the format:
+
+```txt
+The configuration key 'catalog.processors.githubOrg' of app-config.yaml is deprecated and may be removed soon. Configure a GitHub integration instead.
+```
+
+When the `withDeprecatedKeys` option is set to `true` in the `process` method
+of `loadConfigSchema`, the user will be notified that deprecated keys have been
+identified in their app configuration.
+
+The `backend-common` and `plugin-app-backend` packages have been updated to set
+`withDeprecatedKeys` to true so that users are notified of deprecated settings
+by default.
diff --git a/.changeset/long-clouds-rest.md b/.changeset/long-clouds-rest.md
new file mode 100644
index 0000000000..701be91536
--- /dev/null
+++ b/.changeset/long-clouds-rest.md
@@ -0,0 +1,12 @@
+---
+'@backstage/cli': patch
+---
+
+Introduce `--deprecated` option to `config:check` to log all deprecated app configuration properties
+
+```sh
+$ yarn backstage-cli config:check --lax --deprecated
+config:check --lax --deprecated
+Loaded config from app-config.yaml
+The configuration key 'catalog.processors.githubOrg' of app-config.yaml is deprecated and may be removed soon. Configure a GitHub integration instead.
+```
diff --git a/.changeset/long-otters-promise.md b/.changeset/long-otters-promise.md
deleted file mode 100644
index eecb97e8ac..0000000000
--- a/.changeset/long-otters-promise.md
+++ /dev/null
@@ -1,6 +0,0 @@
----
-'@backstage/plugin-catalog-backend-module-ldap': patch
-'@backstage/plugin-catalog-backend-module-msgraph': patch
----
-
-Clean up API report
diff --git a/.changeset/neat-rice-stare.md b/.changeset/neat-rice-stare.md
new file mode 100644
index 0000000000..3f373cbf90
--- /dev/null
+++ b/.changeset/neat-rice-stare.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-catalog-backend': patch
+---
+
+Fix bug with resource loading in permission integration
diff --git a/.changeset/nervous-starfishes-report.md b/.changeset/nervous-starfishes-report.md
deleted file mode 100644
index 2ac4179a2c..0000000000
--- a/.changeset/nervous-starfishes-report.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/plugin-home': patch
----
-
-Adds two new home components - CompanyLogo and Toolkit.
diff --git a/.changeset/olive-points-flash.md b/.changeset/olive-points-flash.md
deleted file mode 100644
index 64b23419de..0000000000
--- a/.changeset/olive-points-flash.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/cli': patch
----
-
-Switch Webpack minification to use `esbuild` instead of `terser`.
diff --git a/.changeset/patched.json b/.changeset/patched.json
new file mode 100644
index 0000000000..1029c8f106
--- /dev/null
+++ b/.changeset/patched.json
@@ -0,0 +1,3 @@
+{
+ "currentReleaseVersion": {}
+}
diff --git a/.changeset/pink-suns-walk.md b/.changeset/pink-suns-walk.md
deleted file mode 100644
index 1857b90811..0000000000
--- a/.changeset/pink-suns-walk.md
+++ /dev/null
@@ -1,25 +0,0 @@
----
-'@backstage/backend-common': patch
-'@backstage/core-components': patch
-'@backstage/create-app': patch
-'@backstage/integration': patch
-'@backstage/techdocs-common': patch
-'@backstage/plugin-apache-airflow': patch
-'@backstage/plugin-auth-backend': patch
-'@backstage/plugin-azure-devops': patch
-'@backstage/plugin-catalog-backend': patch
-'@backstage/plugin-catalog-import': patch
-'@backstage/plugin-catalog-react': patch
-'@backstage/plugin-code-coverage': patch
-'@backstage/plugin-code-coverage-backend': patch
-'@backstage/plugin-cost-insights': patch
-'@backstage/plugin-fossa': patch
-'@backstage/plugin-jenkins': patch
-'@backstage/plugin-scaffolder': patch
-'@backstage/plugin-scaffolder-backend': patch
-'@backstage/plugin-search-backend-node': patch
-'@backstage/plugin-techdocs': patch
-'@backstage/plugin-techdocs-backend': patch
----
-
-Cleaned up API exports
diff --git a/.changeset/plenty-eyes-brush.md b/.changeset/plenty-eyes-brush.md
deleted file mode 100644
index 354c216c3c..0000000000
--- a/.changeset/plenty-eyes-brush.md
+++ /dev/null
@@ -1,60 +0,0 @@
----
-'@backstage/create-app': patch
----
-
-Add permissions to create-app's PluginEnvironment
-
-`CatalogEnvironment` now has a `permissions` field, which means that a permission client must now be provided as part of `PluginEnvironment`. To apply these changes to an existing app, add the following to the `makeCreateEnv` function in `packages/backend/src/index.ts`:
-
-```diff
- // packages/backend/src/index.ts
-
-+ import { ServerPermissionClient } from '@backstage/plugin-permission-node';
-
- function makeCreateEnv(config: Config) {
- ...
-+ const permissions = ServerPerimssionClient.fromConfig(config, {
-+ discovery,
-+ tokenManager,
-+ });
-
- root.info(`Created UrlReader ${reader}`);
-
- return (plugin: string): PluginEnvironment => {
- ...
- return {
- logger,
- cache,
- database,
- config,
- reader,
- discovery,
- tokenManager,
- scheduler,
-+ permissions,
- };
- }
- }
-```
-
-And add a permissions field to the `PluginEnvironment` type in `packages/backend/src/types.ts`:
-
-```diff
- // packages/backend/src/types.ts
-
-+ import { PermissionAuthorizer } from '@backstage/plugin-permission-common';
-
- export type PluginEnvironment = {
- ...
-+ permissions: PermissionAuthorizer;
- };
-```
-
-[`@backstage/plugin-permission-common`](https://www.npmjs.com/package/@backstage/plugin-permission-common) and [`@backstage/plugin-permission-node`](https://www.npmjs.com/package/@backstage/plugin-permission-node) will need to be installed as dependencies:
-
-```diff
- // packages/backend/package.json
-
-+ "@backstage/plugin-permission-common": "...",
-+ "@backstage/plugin-permission-node": "...",
-```
diff --git a/.changeset/popular-cycles-work.md b/.changeset/popular-cycles-work.md
deleted file mode 100644
index 939f59de94..0000000000
--- a/.changeset/popular-cycles-work.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/backend-common': patch
----
-
-bump `logform` to use fixed version of `color` dependency
diff --git a/.changeset/quiet-carpets-shake.md b/.changeset/quiet-carpets-shake.md
deleted file mode 100644
index a0744651e3..0000000000
--- a/.changeset/quiet-carpets-shake.md
+++ /dev/null
@@ -1,7 +0,0 @@
----
-'@backstage/plugin-kubernetes': patch
-'@backstage/plugin-pagerduty': patch
-'@backstage/plugin-splunk-on-call': patch
----
-
-Clean up emptystate.svg image, removing wrong white artifact from the background
diff --git a/.changeset/rotten-files-wink.md b/.changeset/rotten-files-wink.md
deleted file mode 100644
index 65bd92bcc5..0000000000
--- a/.changeset/rotten-files-wink.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/core-components': patch
----
-
-Updated `ResponseErrorPanel` to not use the deprecated `data` property of `ResponseError`.
diff --git a/.changeset/rotten-olives-shop.md b/.changeset/rotten-olives-shop.md
deleted file mode 100644
index b7fb51ad06..0000000000
--- a/.changeset/rotten-olives-shop.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/cli': patch
----
-
-Update `config/eslint.js` to forbid imports of `@material-ui/icons/` as well.
diff --git a/.changeset/selfish-bikes-sleep.md b/.changeset/selfish-bikes-sleep.md
deleted file mode 100644
index f05518fde1..0000000000
--- a/.changeset/selfish-bikes-sleep.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-'@backstage/plugin-api-docs': patch
----
-
-Update @asyncapi/react-component to 1.0.0-next.26, which will fix the
-`ResizeObserver loop limit exceeded` errors which we encountered in several E2E
-tests.
-
-For more details check the following links:
-
-- https://github.com/backstage/backstage/pull/8088#issuecomment-991183968
-- https://github.com/asyncapi/asyncapi-react/issues/498
diff --git a/.changeset/shaggy-emus-look.md b/.changeset/shaggy-emus-look.md
deleted file mode 100644
index df8a1fe6fe..0000000000
--- a/.changeset/shaggy-emus-look.md
+++ /dev/null
@@ -1,7 +0,0 @@
----
-'@backstage/core-app-api': patch
----
-
-Fixed an issue where valid SAML and GitHub sessions would be considered invalid and not be stored.
-
-Deprecated the `SamlSession` and `GithubSession` types.
diff --git a/.changeset/short-shoes-fail.md b/.changeset/short-shoes-fail.md
deleted file mode 100644
index 0b45d67a32..0000000000
--- a/.changeset/short-shoes-fail.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/plugin-auth-backend': patch
----
-
-Removed `@backstage/test-utils` dependency.
diff --git a/.changeset/silent-nails-sleep.md b/.changeset/silent-nails-sleep.md
deleted file mode 100644
index a1587f8427..0000000000
--- a/.changeset/silent-nails-sleep.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/plugin-scaffolder-backend': patch
----
-
-Allow a GitHubCredentialsProvider to be passed to the GitHub scaffolder tasks actions.
diff --git a/.changeset/silver-falcons-nail.md b/.changeset/silver-falcons-nail.md
deleted file mode 100644
index 970bbd7fee..0000000000
--- a/.changeset/silver-falcons-nail.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/plugin-catalog-backend': patch
----
-
-Add apply-conditions endpoint for evaluating conditional permissions in catalog backend.
diff --git a/.changeset/silver-knives-change.md b/.changeset/silver-knives-change.md
deleted file mode 100644
index a2bbaf1e0b..0000000000
--- a/.changeset/silver-knives-change.md
+++ /dev/null
@@ -1,6 +0,0 @@
----
-'@backstage/cli': patch
-'@backstage/backend-common': patch
----
-
-Switched to using `@manypkg/get-packages` to list monorepo packages, which provides better support for different kind of monorepo setups.
diff --git a/.changeset/silver-mice-bake.md b/.changeset/silver-mice-bake.md
deleted file mode 100644
index 6cba2fdb0a..0000000000
--- a/.changeset/silver-mice-bake.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/core-app-api': minor
----
-
-Removed previously deprecated `ApiRegistry` export.
diff --git a/.changeset/slimy-eggs-carry.md b/.changeset/slimy-eggs-carry.md
deleted file mode 100644
index a58a3d8c61..0000000000
--- a/.changeset/slimy-eggs-carry.md
+++ /dev/null
@@ -1,7 +0,0 @@
----
-'@backstage/plugin-auth-backend': patch
----
-
-Switched the secure cookie mode set on the `express-session` to use `'auto'` rather than `true`. This works around an issue where cookies would not be set if TLS termination was handled in a proxy rather than having the backend served directly with HTTPS.
-
-The downside of this change is that secure cookies won't be used unless the backend is directly served with HTTPS. This will be remedied in a future update that allows the backend to configured for trusted proxy mode.
diff --git a/.changeset/stale-gorillas-mix.md b/.changeset/stale-gorillas-mix.md
deleted file mode 100644
index 4ffa1fd553..0000000000
--- a/.changeset/stale-gorillas-mix.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/backend-common': patch
----
-
-The GithubUrlReader is switched to use the DefaultGithubCredentialsProvider
diff --git a/.changeset/techdocs-light-onions-cover.md b/.changeset/techdocs-light-onions-cover.md
deleted file mode 100644
index 55c0873575..0000000000
--- a/.changeset/techdocs-light-onions-cover.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/plugin-techdocs': patch
----
-
-Fix an issue where the TechDocs sidebar is hidden when the Backstage sidebar is pinned at smaller screen sizes
diff --git a/.changeset/tender-cars-look.md b/.changeset/tender-cars-look.md
deleted file mode 100644
index f20ba447d4..0000000000
--- a/.changeset/tender-cars-look.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/backend-test-utils': patch
----
-
-Bump `testcontainers` dependency to version `8.1.2`
diff --git a/.changeset/thin-buckets-juggle.md b/.changeset/thin-buckets-juggle.md
deleted file mode 100644
index a95f8a86ad..0000000000
--- a/.changeset/thin-buckets-juggle.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/plugin-airbrake': minor
----
-
-A plugin for Airbrake (https://airbrake.io/) has been created
diff --git a/.changeset/three-sheep-sparkle.md b/.changeset/three-sheep-sparkle.md
deleted file mode 100644
index db6d8148ce..0000000000
--- a/.changeset/three-sheep-sparkle.md
+++ /dev/null
@@ -1,7 +0,0 @@
----
-'@backstage/plugin-catalog-backend': minor
----
-
-In order to integrate the permissions system with the refresh endpoint in catalog-backend, a new AuthorizedRefreshService was created as a thin wrapper around the existing refresh service which performs authorization and handles the case when authorization is denied. In order to instantiate AuthorizedRefreshService, a permission client is required, which was added as a new field to `CatalogEnvironment`.
-
-The new `permissions` field in `CatalogEnvironment` should already receive the permission client from the `PluginEnvrionment`, so there should be no changes required to the catalog backend setup. See [the create-app changelog](https://github.com/backstage/backstage/blob/master/packages/create-app/CHANGELOG.md) for more details.
diff --git a/.changeset/twelve-bears-fail.md b/.changeset/twelve-bears-fail.md
deleted file mode 100644
index 6112f5a980..0000000000
--- a/.changeset/twelve-bears-fail.md
+++ /dev/null
@@ -1,6 +0,0 @@
----
-'@backstage/core-app-api': patch
-'@backstage/core-plugin-api': patch
----
-
-Removed direct and transitive MUI dependencies.
diff --git a/.changeset/twelve-panthers-move.md b/.changeset/twelve-panthers-move.md
deleted file mode 100644
index f52050a488..0000000000
--- a/.changeset/twelve-panthers-move.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/backend-common': patch
----
-
-Clean up API reports
diff --git a/.changeset/violet-dingos-relate.md b/.changeset/violet-dingos-relate.md
deleted file mode 100644
index c8b0c03e2c..0000000000
--- a/.changeset/violet-dingos-relate.md
+++ /dev/null
@@ -1,7 +0,0 @@
----
-'@backstage/errors': minor
----
-
-Removed the deprecated exports `ErrorResponse` and `parseErrorResponse`.
-
-Removed the deprecated `constructor` and the deprecated `data` property of `ResponseError`.
diff --git a/.changeset/warm-crews-flash.md b/.changeset/warm-crews-flash.md
deleted file mode 100644
index b21a3ada02..0000000000
--- a/.changeset/warm-crews-flash.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/plugin-kubernetes-backend': patch
----
-
-Exclude the AWS session token from credential validation, because it's not necessary in this context.
diff --git a/.changeset/warm-moles-battle.md b/.changeset/warm-moles-battle.md
deleted file mode 100644
index 3d203ea1d3..0000000000
--- a/.changeset/warm-moles-battle.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/plugin-tech-insights': patch
----
-
-fix React warning because of missing `key` prop
diff --git a/.github/labeler.yml b/.github/labeler.yml
index f141107482..bfba5eb321 100644
--- a/.github/labeler.yml
+++ b/.github/labeler.yml
@@ -19,6 +19,7 @@ microsite:
- microsite/**/*
auth:
- plugins/auth-backend/**/*
+ - plugins/permission-*/**/*
- packages/core-app-api/src/apis/implementations/auth/**/*
- packages/core-app-api/src/lib/Auth*/**/*
- packages/core-plugin-api/src/apis/definitions/auth.ts
diff --git a/.github/styles/vocab.txt b/.github/styles/vocab.txt
index d3ea8c1c27..5a47b720b8 100644
--- a/.github/styles/vocab.txt
+++ b/.github/styles/vocab.txt
@@ -16,6 +16,7 @@ Autoscaling
autoselect
Avro
backrub
+backported
Bigtable
Billett
Bitbucket
@@ -68,6 +69,7 @@ deduplicated
deps
dependabot
destructured
+destructuring
dev
devops
devs
diff --git a/.github/workflows/changeset.yml b/.github/workflows/changeset.yml
index a649904a01..44ddbe3334 100644
--- a/.github/workflows/changeset.yml
+++ b/.github/workflows/changeset.yml
@@ -13,6 +13,8 @@ jobs:
- uses: actions/checkout@v2
- name: Install Dependencies
run: yarn --frozen-lockfile
+ - name: Run release preparations
+ run: node scripts/prepare-release.js
- name: Create Release Pull Request
uses: changesets/action@master
with:
diff --git a/.github/workflows/dependabot-changeset-maker.yml b/.github/workflows/dependabot-changeset-maker.yml
index dcf9f47a54..e6439f7beb 100644
--- a/.github/workflows/dependabot-changeset-maker.yml
+++ b/.github/workflows/dependabot-changeset-maker.yml
@@ -1,6 +1,7 @@
name: 'Dependabot changeset maker'
on:
- - pull_request_target
+ pull_request_target:
+ branches: 'dependabot/**'
jobs:
generate-changeset:
@@ -34,8 +35,8 @@ jobs:
async function createChangeset(fileName, commitMessage, packages) {
const pkgs = packages.map(pkg => `'${pkg}': patch`).join('\n');
- const message = commitMessage.replace(/([bB])ump ([\S]+)/, '$1ump `$2`');
- const body = `---\n${pkgs}\n---\n\n${message}`;
+ const message = commitMessage.replace(/([bB])ump ([\S]+)/, '$1ump `$2`').trim();
+ const body = `---\n${pkgs}\n---\n\n${message}\n`;
await fs.writeFile(fileName, body);
}
diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml
index 8106dd1198..2a6e3dc6f9 100644
--- a/.github/workflows/master.yml
+++ b/.github/workflows/master.yml
@@ -3,7 +3,7 @@ name: Main Master Build
on:
workflow_dispatch:
push:
- branches: [master]
+ branches: [master, release-*-patch]
jobs:
build:
diff --git a/ADOPTERS.md b/ADOPTERS.md
index 1c19fe559e..8c9b3e7ca4 100644
--- a/ADOPTERS.md
+++ b/ADOPTERS.md
@@ -81,3 +81,5 @@
| [Hotmart](https://www.hotmart.com) | [@fabioviana-hotmart](https://github.com/fabioviana-hotmart) | The main Developers Portal to centralize docs, applications and technical metrics. |
| [EF Education First](https://www.ef.com) | [Daan Boerlage](https://github.com/runebaas), [RafaĆ Nowosielski](https://github.com/rnowosielski) | Our developer portal - primarily used for cataloging and scaffolding with the ambition to expand with more feature adoptions over time |
| [Power Home Remodeling](https://www.techatpower.com) | [Ben Langfeld](https://github.com/benlangfeld) | Developer portal to our internal services, build on open-source software (including Kubernetes) in our own datacenters. Our Portal allows our team members to navigate inherant complexity and standardise. |
+| [Livspace](https://www.livspace.com) | [Praveen Kumar](https://github.com/praveen-livspace) | Developer portal, service catalog, tech docs, API docs and plugins |
+| [Just Eat Takeaway](https://www.justeattakeaway.com) | [Kim Wilson](https://github.com/kwilson541) | Our developer portal which centralises applications, reduces cognitive load and provides teams insights. |
diff --git a/STYLE.md b/STYLE.md
new file mode 100644
index 0000000000..d968d387fc
--- /dev/null
+++ b/STYLE.md
@@ -0,0 +1,218 @@
+# Introduction
+
+This file describes the various style and design conventions that are used in the Backstage main repository. While you may choose to use these conventions in your own Backstage projects, it is not required.
+
+# TypeScript Coding Conventions
+
+Our TypeScript style is inspired by the [style guidelines](https://github.com/Microsoft/TypeScript/wiki/Coding-guidelines) of the TypeScript implementation itself.
+
+## Naming
+
+1. Use PascalCase for type names.
+1. Do not use `I` as a prefix for interface names.
+1. Use PascalCase for `enum` values.
+1. Use camelCase for function names.
+1. Use camelCase for property names and local variables.
+1. Do not use `_` as a prefix for private properties.
+1. Use whole words in names when possible.
+1. Give type parameters names prefixed with `T`, for example `Request
`.
+
+## Syntax and Types
+
+1. Use `undefined`. Do not use `null`.
+1. Prefer `for..of` over `.forEach`.
+1. Do not introduce new types/values to the global namespace.
+
+## File and Export Structure
+
+1. Shared types should be defined in `types.ts`.
+1. Keep `index.ts` free from implementation, it should only contain re-exports.
+1. If a file has a single or a main export, name the file after the export.
+
+## Error Handling
+
+1. Rely on `@backstage/errors` for custom error types.
+ ```ts
+ throw new NotFoundError(`Could not find resource with id '${id}'`);
+ ```
+1. Check error types by comparing the name
+ ```ts
+ if (error.name === 'NotFoundError') {
+ // ...
+ }
+ ```
+1. Use `ResponseError` to convert `fetch` error responses.
+ ```ts
+ if (!res.ok) {
+ throw await ResponseError.fromResponse(res);
+ }
+ ```
+
+## API Design
+
+This section describes guidelines for designing public APIs. It can also be applied to internal implementations, but it is less necessary.
+
+1. Keep [SOLID](https://en.wikipedia.org/wiki/SOLID) principles in mind.
+1. Be mindful of the number of top-level exports of each package, strive to keep it low.
+1. Prioritize consistency over correctness, stick to existing patterns within the same class/file/folder/package.
+1. Consume interfaces rather than concrete implementations.
+1. Prefer classes for encapsulating functionality and implementing interfaces.
+1. Suffix the name of concrete implementations with the name of the implemented interface. Use a prefix that describes the behavior of the implementation, or use a `Default` prefix.
+
+ ```ts
+ interface ImageLoader { ... } // interface for loading images
+
+ class DefaultImageLoader implements ImageLoader { /* loads an image */ }
+ class CachingImageLoader implements ImageLoader { /* caches loaded images */ }
+ class ResizingImageLoader implements ImageLoader { /* resizes loaded images */ }
+ ```
+
+1. Keep constructors private, prefer static factory methods for creating instances.
+
+ ```ts
+ class DefaultImageLoader implements ImageLoader {
+ // Use `create` for the main way to create an instance.
+ static create(options?: ImageLoaderOptions) {
+ /* ... */
+ }
+
+ // If there are multiple different types of instances that can be
+ // created, suffix the create method.
+ static createWithCaching(options?: ImageLoaderOptions) {
+ /* ... */
+ }
+
+ // If the instantiation process is based on a specific value, use `from*`.
+ // The most common example of this is reading from configuration.
+ // Use a second parameter in case additional options are needed.
+ static fromConfig(config: Config, deps: { logger: Logger }) {
+ /* ... */
+ }
+
+ // Other types of values can work too
+ static fromUrl(url: URL) {
+ /* ... */
+ }
+
+ private constructor(/* ... */) {
+ /* ... */
+ }
+ }
+ ```
+
+1. When a type relates directly to other symbols, use the name of those as prefix for the type.
+
+ ```ts
+ // Always prefix a prop type with the name of the component.
+ function MyComponent(props: MyComponentProps) {}
+
+ // Option types should be prefixed with the name of the operation.
+ function upgradeWidget(options: UpgradeWidgetOptions) {}
+ function activateWidget(options: ActivateWidgetOptions) {}
+
+ // An exception to this are create methods, where the name of the thing
+ // being created may be used as the prefix instead.
+ function createWidget(options: WidgetOptions) {}
+
+ // In this case the related names for request types are `ReportsApi` and
+ // the method name. If there is a low risk of conflict we can keep them
+ // short by only prefixing with the method name, but if there is a higher
+ // risk of conflict then we would want to use the full prefix instead, while
+ // omitting redundant parts, i.e. `ReportsApiUploadRequest.
+ interface ReportsApi {
+ uploadReports(request: UploadReportsRequest): Promise;
+ deleteReport(request: DeleteReportRequest): Promise;
+ }
+ ```
+
+# Documentation Guidelines
+
+We use [API Extractor](https://api-extractor.com/pages/overview/demo_docs/) to generate our documentation, which in turn uses [TSDoc](https://github.com/microsoft/tsdoc) to parse our doc comments.
+
+The doc comments are of the good old `/** ... */` format, with tags of the format `@` used to mark various things. The [TSDoc website](https://tsdoc.org/) has a good index of all available tags.
+
+There are a few things to pay attention to make the documentation show up in a nice way on the website...
+
+## Declare exported functions using the `function` keyword
+
+API documenter will not recognize arrow functions as functions, but rather as a constant that shows up in the list of exported variables. By declaring functions using the `function` keyword, they will show up in the list of functions. They will also get a much nicer documentation page for the individual function that shows information about parameters and return types.
+
+This also extends to React components, since API documenter doesn't have any special handling of those. By always defining exported React components using the `function` keyword, we make them show up among the list of functions in the API reference, where they are then easily discoverable through the `(props)` args (which you should be sure to include!).
+
+
+
+```ts
+/**
+ * Properties for {@link ErrorPanel}.
+ */
+export interface ErrorPanelProps {
+ ...
+}
+
+/**
+ * Renders a warning panel as the effect of an error.
+ */
+export function ErrorPanel(props: ErrorPanelProps) {
+ ...
+}
+```
+
+## Do not destruct parameters in public function declarations
+
+If the parameters of a function are destructed in the parameter list, they will show up in the documentation like this:
+
+
+
+Instead prefer to use a single parameter variable and then move the destructuring into the function body instead, which will look much nicer:
+
+
+
+Also be sure to check that the type used by the parameter is exported, as it otherwise won't be discoverable through documentation.
+
+## Use `@remarks` to split long descriptions
+
+The API reference has an index of exported symbols for each package, which uses a short description, while clicking through to the page for a symbol shows the full description. By default all descriptions are considered "short", and you have to manually add a divider where the description should be cut off using the `@remarks` tag.
+
+```ts
+/**
+ * This function helps you create a thing.
+ *
+ * @remarks
+ *
+ * Here is a much longer and more elaborate description of how the
+ * creation of a thing works, which is way too long to fit on the index page.
+ */
+function createTheThing() {}
+```
+
+## Use `@param` to document parameters
+
+When using the `@param` tag to document a parameter it will show up in the **Parameters** section:
+
+
+
+Be sure to include a `-` after the parameter name as well as [required by TSDoc](https://tsdoc.org/pages/tags/param/), or you'll get a warning in the API report.
+
+```ts
+/**
+ * Generates a PluginCacheManager for consumption by plugins.
+ *
+ * @param pluginId - The plugin that the cache manager should be created for. Plugin names should be unique.
+ */
+forPlugin(pluginId: string): PluginCacheManager {
+ ...
+}
+```
+
+## Fill in missing references using `{@link ...}`
+
+Not all types are detected and referenced on the documentation page. Most notably variables, and therefore `ApiRef`s, will not have clickable links to other symbols that they reference. We instead fill in this missing information using inline `{@link ...}` tags in the description:
+
+```ts
+/**
+ * {@link ApiRef} for the {@link DiscoveryApi}.
+ */
+export const discoveryApiRef: ApiRef = createApiRef(...);
+```
+
+
diff --git a/app-config.yaml b/app-config.yaml
index 2837d97d2f..b43a229ae9 100644
--- a/app-config.yaml
+++ b/app-config.yaml
@@ -107,6 +107,13 @@ proxy:
headers:
Authorization: ${AIRFLOW_BASIC_AUTH_HEADER}
+ '/gocd':
+ target: https://your.gocd.instance.com/go/api
+ allowedMethods: ['GET']
+ allowedHeaders: ['Authorization']
+ headers:
+ Authorization: Basic ${GOCD_AUTH_CREDENTIALS}
+
organization:
name: My Company
@@ -450,3 +457,6 @@ azureDevOps:
apacheAirflow:
baseUrl: https://your.airflow.instance.com
+
+gocd:
+ baseUrl: https://your.gocd.instance.com
diff --git a/docs/auth/google/gcp-iap-auth.md b/docs/auth/google/gcp-iap-auth.md
new file mode 100644
index 0000000000..29951951d1
--- /dev/null
+++ b/docs/auth/google/gcp-iap-auth.md
@@ -0,0 +1,125 @@
+---
+id: provider
+title: Google Identity-Aware Proxy Provider
+sidebar_label: Google IAP
+# prettier-ignore
+description: Adding Google Identity-Aware Proxy as an authentication provider in Backstage
+---
+
+Backstage allows offloading the responsibility of authenticating users to the
+Google HTTPS Load Balancer & [IAP](https://cloud.google.com/iap), leveraging the
+authentication support on the latter.
+
+This tutorial shows how to use authentication on an IAP sitting in front of
+Backstage.
+
+It is assumed an IAP is already serving traffic in front of a Backstage instance
+configured to serve the frontend app from the backend.
+
+## Configuration
+
+Let's start by adding the following `auth` configuration in your
+`app-config.yaml` or `app-config.production.yaml` or similar:
+
+```yaml
+auth:
+ providers:
+ gcp-iap:
+ audience:
+ '/projects//global/backendServices/'
+```
+
+You can find the project number and service ID in the Google Cloud Console.
+
+This config section must be in place for the provider to load at all. Now let's
+add the provider itself.
+
+## Backend Changes
+
+This provider is not enabled by default in the auth backend code, because
+besides the config section above, it also needs to be given one or more
+callbacks in actual code as well as described below.
+
+Add a `providerFactories` entry to the router in
+`packages/backend/plugin/auth.ts`.
+
+```ts
+import { createGcpIapProvider } from '@backstage/plugin-auth-backend';
+
+export default async function createPlugin({
+ logger,
+ database,
+ config,
+ discovery,
+}: PluginEnvironment): Promise {
+ return await createRouter({
+ logger,
+ config,
+ database,
+ discovery,
+ providerFactories: {
+ 'gcp-iap': createGcpIapProvider({
+ // Replace the auth handler if you want to customize the returned user
+ // profile info (can be left out; the default implementation is shown
+ // below which only returns the email). You may want to amend this code
+ // with something that loads additional user profile data out of e.g.
+ // GSuite or LDAP or similar.
+ async authHandler({ iapToken }) {
+ return { profile: { email: iapToken.email } };
+ },
+ signIn: {
+ // You need to supply an identity resolver, that takes the profile
+ // and the IAP token and produces the Backstage token with the
+ // relevant user info.
+ async resolver({ profile, result: { iapToken } }, ctx) {
+ // Somehow compute the Backstage token claims. Just some dummy code
+ // shown here, but you may want to query your LDAP server, or
+ // GSuite or similar, based on the IAP token sub/email claims
+ const id = `user:default/${iapToken.email.split('@')[0]}`;
+ const fullEnt = ['group:default/team-name'];
+ const token = await ctx.tokenIssuer.issueToken({
+ claims: { sub: id, ent: fullEnt },
+ });
+ return { id, token };
+ },
+ },
+ }),
+ },
+ });
+}
+```
+
+Now the backend is ready to serve auth requests on the
+`/api/auth/gcp-iap/refresh` endpoint. All that's left is to update the frontend
+sign-in mechanism to poll that endpoint through the IAP, on the user's behalf.
+
+## Frontend Changes
+
+All Backstage apps need a `SignInPage` to be configured. Its purpose is to
+establish who the user is and what their identifying credentials are, blocking
+rendering the rest of the UI until that's complete, and then keeping those
+credentials fresh.
+
+When using IAP Proxy authentication, the Backstage UI will only be loaded once
+the user has already successfully completely authenticated themselves with the
+IAP and has an active session, so we don't want to make the user have to go
+through a _second_ layer of authentication flows after that.
+
+As such, we want to not display a sign-in page visually at all. Instead, we will
+pick a `SignInPage` implementation component which knows how to silently make
+requests to the backend provider we configured above, and just trusting its
+output to properly represent the current user. Luckily, Backstage comes with a
+component for this purpose out of the box.
+
+Update your `createApp` call in `packages/app/src/App.tsx`, as follows.
+
+```diff
++import { ProxiedSignInPage } from '@backstage/core-components';
+
+ const app = createApp({
+ components: {
++ SignInPage: props => ,
+```
+
+After this, your app should be ready to leverage the Identity-Aware Proxy for
+authentication!
diff --git a/docs/auth/identity-resolver.md b/docs/auth/identity-resolver.md
index 2c36ddcd7f..a33351e938 100644
--- a/docs/auth/identity-resolver.md
+++ b/docs/auth/identity-resolver.md
@@ -96,7 +96,7 @@ It can be enabled like this
```tsx
// File: packages/backend/src/plugins/auth.ts
-import { googleEmailSignInResolver } from '@backstage/plugin-auth-backend';
+import { googleEmailSignInResolver, createGoogleProvider } from '@backstage/plugin-auth-backend';
export default async function createPlugin({
...
diff --git a/docs/features/software-catalog/descriptor-format.md b/docs/features/software-catalog/descriptor-format.md
index 57473ce4c7..ec4e13c1d4 100644
--- a/docs/features/software-catalog/descriptor-format.md
+++ b/docs/features/software-catalog/descriptor-format.md
@@ -1266,6 +1266,10 @@ shape, this kind has the following structure.
Exactly equal to `backstage.io/v1alpha1` and `Location`, respectively.
+### `spec` [required]
+
+The `spec` field is required. The minimal spec should be an empty object.
+
### `spec.type` [optional]
The single location type, that's common to the targets specified in the spec. If
diff --git a/docs/features/software-catalog/well-known-annotations.md b/docs/features/software-catalog/well-known-annotations.md
index c3af6caf2d..26a8710820 100644
--- a/docs/features/software-catalog/well-known-annotations.md
+++ b/docs/features/software-catalog/well-known-annotations.md
@@ -204,6 +204,24 @@ browser when viewing that user.
This annotation can be used on a [User entity](descriptor-format.md#kind-user)
to note that it originated from that user on GitHub.
+### gocd.org/pipelines
+
+```yaml
+# Example:
+metadata:
+ annotations:
+ gocd.org/pipelines: backstage,backstage-pr,backstage-builder
+```
+
+The value of this annotation is a comma-separated list of the GoCD pipeline
+names to fetch CI/CD information for.
+
+The pipeline name is usually defined in the `gocd.yml` file for the pipeline
+definition.
+
+Specifying this annotation will enable GoCD related features in Backstage for
+that entity.
+
### sentry.io/project-slug
```yaml
diff --git a/docs/getting-started/app-custom-theme.md b/docs/getting-started/app-custom-theme.md
index d05a14cc35..fc68008ae8 100644
--- a/docs/getting-started/app-custom-theme.md
+++ b/docs/getting-started/app-custom-theme.md
@@ -301,12 +301,11 @@ in storybook. If you don't find a component that suits your needs but want to
contribute, check the
[Contributing documentation](https://github.com/backstage/backstage/blob/master/plugins/home/README.md#contributing).
-!!! tip If you want to use one of the available homepage templates you can find
-the
-[templates](https://backstage.io/storybook/?path=/story/plugins-home-templates)
-in the storybook under the "Home" plugin. And if you would like to contribute a
-template, please see the
-[Contributing documentation](https://github.com/backstage/backstage/blob/master/plugins/home/README.md#contributing)
+> If you want to use one of the available homepage templates you can find the
+> [templates](https://backstage.io/storybook/?path=/story/plugins-home-templates)
+> in the storybook under the "Home" plugin. And if you would like to contribute
+> a template, please see the
+> [Contributing documentation](https://github.com/backstage/backstage/blob/master/plugins/home/README.md#contributing)
```tsx
import React from 'react';
diff --git a/docs/integrations/aws-s3/discovery.md b/docs/integrations/aws-s3/discovery.md
index d50aceacb8..545a578e63 100644
--- a/docs/integrations/aws-s3/discovery.md
+++ b/docs/integrations/aws-s3/discovery.md
@@ -26,3 +26,16 @@ catalog:
```
Note the `s3-discovery` type, as this is not a regular `url` processor.
+
+As this processor is not one of the default providers, you will also need to add
+the below to `packages/backend/src/plugins/catalog.ts`:
+
+```ts
+/* packages/backend/src/plugins/catalog.ts */
+
+import { AwsS3DiscoveryProcessor } from '@backstage/plugin-catalog-backend';
+
+const builder = await CatalogBuilder.create(env);
+/** ... other processors ... */
+builder.addProcessor(new AwsS3DiscoveryProcessor(env.reader));
+```
diff --git a/docs/integrations/ldap/org.md b/docs/integrations/ldap/org.md
index d1438aba8b..b9c09103b4 100644
--- a/docs/integrations/ldap/org.md
+++ b/docs/integrations/ldap/org.md
@@ -30,8 +30,8 @@ yarn add @backstage/plugin-catalog-backend-module-ldap
```typescript
// packages/backend/src/plugins/catalog.ts
builder.addProcessor(
- LdapOrgReaderProcessor.fromConfig(config, {
- logger,
+ LdapOrgReaderProcessor.fromConfig(env.config, {
+ logger: env.logger,
}),
);
```
diff --git a/docs/local-dev/cli-commands.md b/docs/local-dev/cli-commands.md
index caec60ed70..21b129e0c2 100644
--- a/docs/local-dev/cli-commands.md
+++ b/docs/local-dev/cli-commands.md
@@ -556,6 +556,7 @@ Options:
--package <name> 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: [])
-h, --help display help for command
```
diff --git a/docs/plugins/publishing.md b/docs/plugins/publishing.md
deleted file mode 100644
index 06fae0533e..0000000000
--- a/docs/plugins/publishing.md
+++ /dev/null
@@ -1,58 +0,0 @@
----
-id: publishing
-title: Publishing
-description: Documentation on Publishing npm packages
----
-
-## npm
-
-npm packages are published through CI/CD in the
-[`.github/workflows/master.yml`](https://github.com/backstage/backstage/blob/master/.github/workflows/master.yml)
-workflow. Every commit that is merged to master will be checked for new versions
-of all public packages, and any new versions will automatically be published to
-npm.
-
-### Creating a new release
-
-Version bumps are made through release PRs. To create a new release, checkout
-out a new branch that you will use for the release, e.g.
-
-```sh
-$ git checkout -b new-release
-```
-
-First bump the `CHANGELOG.md` in the root of the repo and commit. You bump it by
-adding a header for the new version just below the `## Next Release` one.
-
-Then, from the root of the repo, run
-
-```sh
-$ yarn release
-```
-
-This will bring up the lerna release CLI where you choose what type of version
-bump you want to make, (major/minor/patch/prerelease). The CLI will take you
-through choosing a version, previewing all changes, and then approving the
-release. Once the release is approved, a new commit is created that you can
-submit as a PR. Push the branch to GitHub:
-
-```sh
-$ git push origin -u new-release
-```
-
-And then create a PR. Once the PR is approved and merged into master, the master
-build will publish new versions of all bumped packages.
-
-### Include new changes in existing release PR
-
-If you want to include some last minute changes to an existing release PR,
-follow these instructions:
-
-```sh
-$ git checkout master
-$ git pull
-$ git checkout new-release
-$ git reset --hard master
-$ yarn release
-$ git push --force
-```
diff --git a/docs/publishing.md b/docs/publishing.md
new file mode 100644
index 0000000000..e5642a3467
--- /dev/null
+++ b/docs/publishing.md
@@ -0,0 +1,72 @@
+
+
+## npm
+
+npm packages are published through CI/CD in the
+[`.github/workflows/master.yml`](https://github.com/backstage/backstage/blob/master/.github/workflows/master.yml)
+workflow. Every commit that is merged to master will be checked for new versions
+of all public packages, and any new versions will automatically be published to
+npm.
+
+### Creating a new release
+
+Releases are handled by changesets and trigger whenever the "Version Packages"
+PR is merged. This is typically done every Thursday around noon CET.
+
+## Emergency Release Process
+
+**This emergency release process is intended only for the Backstage
+maintainers.**
+
+For this example we will be using the `@backstage/plugin-foo` package as an
+example and assume that it is currently version `1.5.0` in the master branch.
+
+In the event of a severe bug being introduced in version `1.5.0` of the
+`@backstage/plugin-foo` released in the `2048-01-01` release, the following
+process is used to release an emergency fix as `1.5.1`:
+
+- [ ] Identify the release that needs to be patched, in this case we're fixing a
+ broken release, so it would be the most recent one, `2048-01-01`. In the
+ event of a backported security fix, the release that has the last
+ published version of each major version of the package should be the one
+ patched.
+- [ ] Make sure a patch branch exists for the release that is being patched. If
+ a patch already exists, reuse the existing branch. The branch **must
+ always** be named exactly `release--patch`.
+
+ ```bash
+ git checkout release-2048-01-01
+ git checkout -b release-2048-01-01-patch
+ git push --set-upstream origin release-2048-01-01-patch
+ ```
+
+- [ ] With the `release-2048-01-01-patch` branch as a base, create a new branch
+ for your fix. This branch can be named anything, but the following naming
+ pattern may be suitable:
+
+ ```bash
+ git checkout -b ${USER}/release-2048-01-01-emergency-fix
+ ```
+
+- [ ] Apply fixes and create a new patch changeset for the affected package,
+ then commit these changes.
+- [ ] Run `yarn release` in the root of the repo in order to convert your
+ changeset into package version bumps and changelog entries. Commit these
+ changes as a second `"Generated release"` commit.
+- [ ] Create PR towards the base branch (`release-2048-01-01-patch`) containing
+ the two commits.
+- [ ] Review/Merge the PR into `release-2048-01-01-patch`. This will
+ automatically trigger a release.
+- [ ] Make sure the same fix is applied in master before the next release, and
+ create an appropriate changeset for that as well. In the changeset towards
+ master you should refer back to all patch releases that also received the
+ same fix. Also be sure to update `.changeset/patched.json` in the same PR
+ to make sure that future releases of the packages are bumped accordingly:
+
+ ```json
+ {
+ "currentReleaseVersion": {
+ "@backstage/plugin-foo": "1.5.1"
+ }
+ }
+ ```
diff --git a/microsite/data/plugins/bazaar.yaml b/microsite/data/plugins/bazaar.yaml
new file mode 100644
index 0000000000..6e27692d78
--- /dev/null
+++ b/microsite/data/plugins/bazaar.yaml
@@ -0,0 +1,8 @@
+title: Bazaar
+author: Axis Communications AB
+authorUrl: https://www.axis.com
+category: Discovery
+description: A marketplace where engineers can propose projects suitable for inner sourcing
+documentation: https://github.com/backstage/backstage/blob/master/plugins/bazaar/README.md
+iconUrl: img/bazaar.svg
+npmPackageName: '@backstage/plugin-bazaar'
diff --git a/microsite/data/plugins/gocd.yaml b/microsite/data/plugins/gocd.yaml
new file mode 100644
index 0000000000..7bf24d75fd
--- /dev/null
+++ b/microsite/data/plugins/gocd.yaml
@@ -0,0 +1,12 @@
+---
+title: GoCD
+author: SoundCloud
+authorUrl: https://github.com/soundcloud
+category: CI/CD
+description: GoCD is an open-source tool which is used in software development to help teams and organizations automate the continuous delivery of software.
+documentation: https://github.com/backstage/backstage/tree/master/plugins/gocd
+iconUrl: https://pics.freeicons.io/uploads/icons/png/13646383971540553613-512.png
+npmPackageName: '@backstage/plugin-gocd'
+tags:
+ - ci
+ - cd
diff --git a/microsite/sidebars.json b/microsite/sidebars.json
index 6c4c5261d9..c0a0b9b24f 100644
--- a/microsite/sidebars.json
+++ b/microsite/sidebars.json
@@ -202,7 +202,6 @@
"type": "subcategory",
"label": "Publishing",
"ids": [
- "plugins/publishing",
"plugins/publish-private",
"plugins/add-to-marketplace",
"plugins/observability"
diff --git a/microsite/static/img/bazaar.svg b/microsite/static/img/bazaar.svg
new file mode 100644
index 0000000000..1d180a1e03
--- /dev/null
+++ b/microsite/static/img/bazaar.svg
@@ -0,0 +1 @@
+
diff --git a/mkdocs.yml b/mkdocs.yml
index 81dad55b84..398863a3c0 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -126,7 +126,6 @@ nav:
- Testing:
- Testing with Jest: 'plugins/testing.md'
- Publishing:
- - Publishing: 'plugins/publishing.md'
- Publish private: 'plugins/publish-private.md'
- Add to Marketplace: 'plugins/add-to-marketplace.md'
- Observability: 'plugins/observability.md'
diff --git a/packages/app-defaults/CHANGELOG.md b/packages/app-defaults/CHANGELOG.md
index 751b758984..631a4726e1 100644
--- a/packages/app-defaults/CHANGELOG.md
+++ b/packages/app-defaults/CHANGELOG.md
@@ -1,5 +1,15 @@
# @backstage/app-defaults
+## 0.1.4
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/core-components@0.8.4
+ - @backstage/core-plugin-api@0.5.0
+ - @backstage/core-app-api@0.4.0
+ - @backstage/plugin-permission-react@0.2.2
+
## 0.1.3
### Patch Changes
diff --git a/packages/app-defaults/package.json b/packages/app-defaults/package.json
index 89d83ae91f..eb65583934 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": "0.1.3",
+ "version": "0.1.4",
"private": false,
"publishConfig": {
"access": "public",
@@ -29,10 +29,10 @@
"clean": "backstage-cli clean"
},
"dependencies": {
- "@backstage/core-components": "^0.8.2",
- "@backstage/core-app-api": "^0.3.0",
- "@backstage/core-plugin-api": "^0.4.0",
- "@backstage/plugin-permission-react": "^0.2.0",
+ "@backstage/core-components": "^0.8.4",
+ "@backstage/core-app-api": "^0.4.0",
+ "@backstage/core-plugin-api": "^0.5.0",
+ "@backstage/plugin-permission-react": "^0.2.2",
"@backstage/theme": "^0.2.14",
"@material-ui/core": "^4.12.2",
"@material-ui/icons": "^4.9.1",
@@ -42,8 +42,8 @@
"react": "^16.13.1 || ^17.0.0"
},
"devDependencies": {
- "@backstage/cli": "^0.10.3",
- "@backstage/test-utils": "^0.2.0",
+ "@backstage/cli": "^0.11.0",
+ "@backstage/test-utils": "^0.2.2",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^11.2.5",
"@types/jest": "^26.0.7",
diff --git a/packages/app/CHANGELOG.md b/packages/app/CHANGELOG.md
index c14db343bc..aa2fdc5ffa 100644
--- a/packages/app/CHANGELOG.md
+++ b/packages/app/CHANGELOG.md
@@ -1,5 +1,55 @@
# example-app
+## 0.2.60
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/core-components@0.8.4
+ - @backstage/cli@0.11.0
+ - @backstage/plugin-tech-insights@0.1.5
+ - @backstage/plugin-gocd@0.1.1
+ - @backstage/core-plugin-api@0.5.0
+ - @backstage/plugin-org@0.3.34
+ - @backstage/plugin-home@0.4.10
+ - @backstage/plugin-azure-devops@0.1.10
+ - @backstage/plugin-apache-airflow@0.1.3
+ - @backstage/plugin-catalog-import@0.7.9
+ - @backstage/plugin-catalog-react@0.6.11
+ - @backstage/plugin-code-coverage@0.1.22
+ - @backstage/plugin-cost-insights@0.11.17
+ - @backstage/plugin-jenkins@0.5.17
+ - @backstage/plugin-scaffolder@0.11.18
+ - @backstage/plugin-techdocs@0.12.14
+ - @backstage/plugin-kubernetes@0.5.4
+ - @backstage/plugin-pagerduty@0.3.22
+ - @backstage/plugin-api-docs@0.6.22
+ - @backstage/core-app-api@0.4.0
+ - @backstage/plugin-airbrake@0.1.0
+ - @backstage/app-defaults@0.1.4
+ - @backstage/catalog-model@0.9.9
+ - @backstage/integration-react@0.1.18
+ - @backstage/plugin-badges@0.2.19
+ - @backstage/plugin-catalog@0.7.8
+ - @backstage/plugin-catalog-graph@0.2.6
+ - @backstage/plugin-circleci@0.2.34
+ - @backstage/plugin-cloudbuild@0.2.32
+ - @backstage/plugin-explore@0.3.25
+ - @backstage/plugin-gcp-projects@0.3.13
+ - @backstage/plugin-github-actions@0.4.31
+ - @backstage/plugin-graphiql@0.2.27
+ - @backstage/plugin-kafka@0.2.25
+ - @backstage/plugin-lighthouse@0.2.34
+ - @backstage/plugin-newrelic@0.3.13
+ - @backstage/plugin-newrelic-dashboard@0.1.3
+ - @backstage/plugin-rollbar@0.3.23
+ - @backstage/plugin-search@0.5.5
+ - @backstage/plugin-sentry@0.3.33
+ - @backstage/plugin-shortcuts@0.1.19
+ - @backstage/plugin-tech-radar@0.5.2
+ - @backstage/plugin-todo@0.1.18
+ - @backstage/plugin-user-settings@0.3.16
+
## 0.2.59
### Patch Changes
diff --git a/packages/app/package.json b/packages/app/package.json
index bbfd903484..bc30713a94 100644
--- a/packages/app/package.json
+++ b/packages/app/package.json
@@ -1,53 +1,54 @@
{
"name": "example-app",
- "version": "0.2.59",
+ "version": "0.2.60",
"private": true,
"bundled": true,
"dependencies": {
- "@backstage/app-defaults": "^0.1.3",
- "@backstage/catalog-model": "^0.9.8",
- "@backstage/cli": "^0.10.5",
- "@backstage/core-app-api": "^0.3.1",
- "@backstage/core-components": "^0.8.3",
- "@backstage/core-plugin-api": "^0.4.1",
- "@backstage/integration-react": "^0.1.16",
- "@backstage/plugin-airbrake": "^0.0.0",
- "@backstage/plugin-api-docs": "^0.6.21",
- "@backstage/plugin-azure-devops": "^0.1.9",
- "@backstage/plugin-apache-airflow": "^0.1.2",
- "@backstage/plugin-badges": "^0.2.18",
- "@backstage/plugin-catalog": "^0.7.7",
- "@backstage/plugin-catalog-graph": "^0.2.5",
- "@backstage/plugin-catalog-import": "^0.7.8",
- "@backstage/plugin-catalog-react": "^0.6.10",
- "@backstage/plugin-circleci": "^0.2.33",
- "@backstage/plugin-cloudbuild": "^0.2.31",
- "@backstage/plugin-code-coverage": "^0.1.21",
- "@backstage/plugin-cost-insights": "^0.11.16",
- "@backstage/plugin-explore": "^0.3.24",
- "@backstage/plugin-gcp-projects": "^0.3.12",
- "@backstage/plugin-github-actions": "^0.4.30",
- "@backstage/plugin-graphiql": "^0.2.26",
- "@backstage/plugin-home": "^0.4.9",
- "@backstage/plugin-jenkins": "^0.5.16",
- "@backstage/plugin-kafka": "^0.2.24",
- "@backstage/plugin-kubernetes": "^0.5.3",
- "@backstage/plugin-lighthouse": "^0.2.33",
- "@backstage/plugin-newrelic": "^0.3.12",
- "@backstage/plugin-newrelic-dashboard": "^0.1.2",
- "@backstage/plugin-org": "^0.3.33",
- "@backstage/plugin-pagerduty": "0.3.21",
- "@backstage/plugin-rollbar": "^0.3.22",
- "@backstage/plugin-scaffolder": "^0.11.17",
- "@backstage/plugin-search": "^0.5.4",
- "@backstage/plugin-sentry": "^0.3.32",
- "@backstage/plugin-shortcuts": "^0.1.18",
- "@backstage/plugin-tech-radar": "^0.5.1",
- "@backstage/plugin-techdocs": "^0.12.13",
- "@backstage/plugin-todo": "^0.1.17",
- "@backstage/plugin-user-settings": "^0.3.15",
+ "@backstage/app-defaults": "^0.1.4",
+ "@backstage/catalog-model": "^0.9.9",
+ "@backstage/cli": "^0.11.0",
+ "@backstage/core-app-api": "^0.4.0",
+ "@backstage/core-components": "^0.8.4",
+ "@backstage/core-plugin-api": "^0.5.0",
+ "@backstage/integration-react": "^0.1.18",
+ "@backstage/plugin-airbrake": "^0.1.0",
+ "@backstage/plugin-api-docs": "^0.6.22",
+ "@backstage/plugin-azure-devops": "^0.1.10",
+ "@backstage/plugin-apache-airflow": "^0.1.3",
+ "@backstage/plugin-badges": "^0.2.19",
+ "@backstage/plugin-catalog": "^0.7.8",
+ "@backstage/plugin-catalog-graph": "^0.2.6",
+ "@backstage/plugin-catalog-import": "^0.7.9",
+ "@backstage/plugin-catalog-react": "^0.6.11",
+ "@backstage/plugin-circleci": "^0.2.34",
+ "@backstage/plugin-cloudbuild": "^0.2.32",
+ "@backstage/plugin-code-coverage": "^0.1.22",
+ "@backstage/plugin-cost-insights": "^0.11.17",
+ "@backstage/plugin-explore": "^0.3.25",
+ "@backstage/plugin-gcp-projects": "^0.3.13",
+ "@backstage/plugin-github-actions": "^0.4.31",
+ "@backstage/plugin-gocd": "^0.1.1",
+ "@backstage/plugin-graphiql": "^0.2.27",
+ "@backstage/plugin-home": "^0.4.10",
+ "@backstage/plugin-jenkins": "^0.5.17",
+ "@backstage/plugin-kafka": "^0.2.25",
+ "@backstage/plugin-kubernetes": "^0.5.4",
+ "@backstage/plugin-lighthouse": "^0.2.34",
+ "@backstage/plugin-newrelic": "^0.3.13",
+ "@backstage/plugin-newrelic-dashboard": "^0.1.3",
+ "@backstage/plugin-org": "^0.3.34",
+ "@backstage/plugin-pagerduty": "0.3.22",
+ "@backstage/plugin-rollbar": "^0.3.23",
+ "@backstage/plugin-scaffolder": "^0.11.18",
+ "@backstage/plugin-search": "^0.5.5",
+ "@backstage/plugin-sentry": "^0.3.33",
+ "@backstage/plugin-shortcuts": "^0.1.19",
+ "@backstage/plugin-tech-radar": "^0.5.2",
+ "@backstage/plugin-techdocs": "^0.12.14",
+ "@backstage/plugin-todo": "^0.1.18",
+ "@backstage/plugin-user-settings": "^0.3.16",
"@backstage/search-common": "^0.2.0",
- "@backstage/plugin-tech-insights": "^0.1.4",
+ "@backstage/plugin-tech-insights": "^0.1.5",
"@backstage/theme": "^0.2.14",
"@material-ui/core": "^4.12.2",
"@material-ui/icons": "^4.9.1",
@@ -67,7 +68,7 @@
"zen-observable": "^0.8.15"
},
"devDependencies": {
- "@backstage/test-utils": "^0.2.0",
+ "@backstage/test-utils": "^0.2.2",
"@rjsf/core": "^3.2.1",
"@testing-library/cypress": "^8.0.2",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/packages/app/src/components/catalog/EntityPage.tsx b/packages/app/src/components/catalog/EntityPage.tsx
index 455cd188fb..60dc0dc979 100644
--- a/packages/app/src/components/catalog/EntityPage.tsx
+++ b/packages/app/src/components/catalog/EntityPage.tsx
@@ -129,6 +129,7 @@ import {
EntityNewRelicDashboardContent,
EntityNewRelicDashboardCard,
} from '@backstage/plugin-newrelic-dashboard';
+import { EntityGoCdContent, isGoCdAvailable } from '@backstage/plugin-gocd';
import React, { ReactNode, useMemo, useState } from 'react';
@@ -185,6 +186,10 @@ export const cicdContent = (
+
+
+
+
diff --git a/packages/backend-common/CHANGELOG.md b/packages/backend-common/CHANGELOG.md
index 7edcbc7acf..ccba33dc34 100644
--- a/packages/backend-common/CHANGELOG.md
+++ b/packages/backend-common/CHANGELOG.md
@@ -1,5 +1,21 @@
# @backstage/backend-common
+## 0.10.3
+
+### Patch Changes
+
+- 5b406daabe: build(deps-dev): bump `http-errors` from 1.8.0 to 2.0.0
+- 5333451def: Cleaned up API exports
+- db5310e25e: bump `logform` to use fixed version of `color` dependency
+- 7946418729: Switched to using `@manypkg/get-packages` to list monorepo packages, which provides better support for different kind of monorepo setups.
+- 3b4d8caff6: The GithubUrlReader is switched to use the DefaultGithubCredentialsProvider
+- f77bd5c8ff: Clean up API reports
+- Updated dependencies
+ - @backstage/config@0.1.12
+ - @backstage/integration@0.7.1
+ - @backstage/errors@0.2.0
+ - @backstage/config-loader@0.9.2
+
## 0.10.2
### Patch Changes
diff --git a/packages/backend-common/package.json b/packages/backend-common/package.json
index 04a4971e00..a1e3533fb7 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.10.2",
+ "version": "0.10.3",
"main": "src/index.ts",
"types": "src/index.ts",
"private": false,
@@ -30,10 +30,10 @@
},
"dependencies": {
"@backstage/cli-common": "^0.1.6",
- "@backstage/config": "^0.1.11",
- "@backstage/config-loader": "^0.9.1",
- "@backstage/errors": "^0.1.5",
- "@backstage/integration": "^0.7.0",
+ "@backstage/config": "^0.1.12",
+ "@backstage/config-loader": "^0.9.2",
+ "@backstage/errors": "^0.2.0",
+ "@backstage/integration": "^0.7.1",
"@backstage/types": "^0.1.1",
"@google-cloud/storage": "^5.8.0",
"@manypkg/get-packages": "^1.1.3",
@@ -81,8 +81,8 @@
}
},
"devDependencies": {
- "@backstage/cli": "^0.10.5",
- "@backstage/test-utils": "^0.2.1",
+ "@backstage/cli": "^0.11.0",
+ "@backstage/test-utils": "^0.2.2",
"@types/archiver": "^5.1.0",
"@types/compression": "^1.7.0",
"@types/concat-stream": "^1.6.0",
@@ -99,7 +99,7 @@
"@types/webpack-env": "^1.15.2",
"aws-sdk-mock": "^5.2.1",
"get-port": "^5.1.1",
- "http-errors": "^1.7.3",
+ "http-errors": "^2.0.0",
"jest": "^26.0.1",
"mock-fs": "^5.1.0",
"msw": "^0.35.0",
diff --git a/packages/backend-common/src/config.ts b/packages/backend-common/src/config.ts
index 12cc2e3a9d..9081b99284 100644
--- a/packages/backend-common/src/config.ts
+++ b/packages/backend-common/src/config.ts
@@ -39,7 +39,10 @@ const updateRedactionList = (
configs: AppConfig[],
logger: Logger,
) => {
- const secretAppConfigs = schema.process(configs, { visibility: ['secret'] });
+ const secretAppConfigs = schema.process(configs, {
+ visibility: ['secret'],
+ withDeprecatedKeys: true,
+ });
const secretConfig = ConfigReader.fromConfigs(secretAppConfigs);
const values = new Set();
const data = secretConfig.get();
diff --git a/packages/backend-tasks/CHANGELOG.md b/packages/backend-tasks/CHANGELOG.md
index acaa41c131..4042074ebe 100644
--- a/packages/backend-tasks/CHANGELOG.md
+++ b/packages/backend-tasks/CHANGELOG.md
@@ -1,5 +1,14 @@
# @backstage/backend-tasks
+## 0.1.3
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/config@0.1.12
+ - @backstage/backend-common@0.10.3
+ - @backstage/errors@0.2.0
+
## 0.1.2
### Patch Changes
diff --git a/packages/backend-tasks/package.json b/packages/backend-tasks/package.json
index e7af82ce95..5ffb689be9 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.1.2",
+ "version": "0.1.3",
"main": "src/index.ts",
"types": "src/index.ts",
"private": false,
@@ -29,9 +29,9 @@
"clean": "backstage-cli clean"
},
"dependencies": {
- "@backstage/backend-common": "^0.10.2",
- "@backstage/config": "^0.1.11",
- "@backstage/errors": "^0.1.4",
+ "@backstage/backend-common": "^0.10.3",
+ "@backstage/config": "^0.1.12",
+ "@backstage/errors": "^0.2.0",
"@backstage/types": "^0.1.1",
"@types/luxon": "^2.0.4",
"knex": "^0.95.1",
@@ -43,8 +43,8 @@
"zod": "^3.9.5"
},
"devDependencies": {
- "@backstage/backend-test-utils": "^0.1.11",
- "@backstage/cli": "^0.10.5",
+ "@backstage/backend-test-utils": "^0.1.13",
+ "@backstage/cli": "^0.11.0",
"jest": "^26.0.1",
"wait-for-expect": "^3.0.2"
},
diff --git a/packages/backend-test-utils/CHANGELOG.md b/packages/backend-test-utils/CHANGELOG.md
index f484a0fb8f..5701ed8933 100644
--- a/packages/backend-test-utils/CHANGELOG.md
+++ b/packages/backend-test-utils/CHANGELOG.md
@@ -1,5 +1,15 @@
# @backstage/backend-test-utils
+## 0.1.13
+
+### Patch Changes
+
+- b1bc55405e: Bump `testcontainers` dependency to version `8.1.2`
+- Updated dependencies
+ - @backstage/config@0.1.12
+ - @backstage/backend-common@0.10.3
+ - @backstage/cli@0.11.0
+
## 0.1.12
### Patch Changes
diff --git a/packages/backend-test-utils/package.json b/packages/backend-test-utils/package.json
index 78daeb4efe..b3abbfca18 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.12",
+ "version": "0.1.13",
"main": "src/index.ts",
"types": "src/index.ts",
"private": false,
@@ -30,9 +30,9 @@
"clean": "backstage-cli clean"
},
"dependencies": {
- "@backstage/backend-common": "^0.10.1",
- "@backstage/cli": "^0.10.4",
- "@backstage/config": "^0.1.9",
+ "@backstage/backend-common": "^0.10.3",
+ "@backstage/cli": "^0.11.0",
+ "@backstage/config": "^0.1.12",
"knex": "^0.95.1",
"mysql2": "^2.2.5",
"pg": "^8.3.0",
@@ -41,7 +41,7 @@
"uuid": "^8.0.0"
},
"devDependencies": {
- "@backstage/cli": "^0.10.4",
+ "@backstage/cli": "^0.11.0",
"jest": "^26.0.1"
},
"files": [
diff --git a/packages/backend/CHANGELOG.md b/packages/backend/CHANGELOG.md
index f3c2d4f861..bd9c1f3649 100644
--- a/packages/backend/CHANGELOG.md
+++ b/packages/backend/CHANGELOG.md
@@ -1,5 +1,35 @@
# example-backend
+## 0.2.60
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/config@0.1.12
+ - @backstage/plugin-scaffolder-backend@0.15.20
+ - @backstage/integration@0.7.1
+ - @backstage/backend-common@0.10.3
+ - @backstage/plugin-todo-backend@0.1.18
+ - @backstage/plugin-catalog-backend@0.20.0
+ - @backstage/plugin-tech-insights-backend@0.1.5
+ - @backstage/plugin-permission-node@0.3.0
+ - @backstage/plugin-auth-backend@0.6.2
+ - @backstage/plugin-code-coverage-backend@0.1.19
+ - @backstage/plugin-search-backend-node@0.4.4
+ - @backstage/plugin-techdocs-backend@0.12.3
+ - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.5
+ - @backstage/plugin-permission-backend@0.3.0
+ - @backstage/plugin-graphql-backend@0.1.11
+ - @backstage/plugin-kubernetes-backend@0.4.3
+ - example-app@0.2.60
+ - @backstage/backend-tasks@0.1.3
+ - @backstage/catalog-client@0.5.4
+ - @backstage/catalog-model@0.9.9
+ - @backstage/plugin-badges-backend@0.1.15
+ - @backstage/plugin-kafka-backend@0.2.14
+ - @backstage/plugin-permission-common@0.3.1
+ - @backstage/plugin-scaffolder-backend-module-rails@0.2.3
+
## 0.2.59
### Patch Changes
diff --git a/packages/backend/package.json b/packages/backend/package.json
index f204659789..29f9059593 100644
--- a/packages/backend/package.json
+++ b/packages/backend/package.json
@@ -1,6 +1,6 @@
{
"name": "example-backend",
- "version": "0.2.59",
+ "version": "0.2.60",
"main": "dist/index.cjs.js",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -24,43 +24,42 @@
"migrate:create": "knex migrate:make -x ts"
},
"dependencies": {
- "@backstage/backend-common": "^0.10.1",
- "@backstage/backend-tasks": "^0.1.0",
- "@backstage/catalog-client": "^0.5.3",
- "@backstage/catalog-model": "^0.9.8",
- "@backstage/config": "^0.1.10",
- "@backstage/integration": "^0.7.0",
+ "@backstage/backend-common": "^0.10.3",
+ "@backstage/backend-tasks": "^0.1.3",
+ "@backstage/catalog-client": "^0.5.4",
+ "@backstage/catalog-model": "^0.9.9",
+ "@backstage/config": "^0.1.12",
+ "@backstage/integration": "^0.7.1",
"@backstage/plugin-app-backend": "^0.3.21",
- "@backstage/plugin-auth-backend": "^0.6.0",
- "@backstage/plugin-azure-devops-backend": "^0.2.6",
- "@backstage/plugin-badges-backend": "^0.1.14",
- "@backstage/plugin-catalog-backend": "^0.19.4",
- "@backstage/plugin-code-coverage-backend": "^0.1.18",
- "@backstage/plugin-graphql-backend": "^0.1.10",
+ "@backstage/plugin-auth-backend": "^0.6.2",
+ "@backstage/plugin-badges-backend": "^0.1.15",
+ "@backstage/plugin-catalog-backend": "^0.20.0",
+ "@backstage/plugin-code-coverage-backend": "^0.1.19",
+ "@backstage/plugin-graphql-backend": "^0.1.11",
"@backstage/plugin-jenkins-backend": "^0.1.10",
- "@backstage/plugin-kubernetes-backend": "^0.4.1",
- "@backstage/plugin-kafka-backend": "^0.2.13",
- "@backstage/plugin-permission-backend": "^0.2.3",
- "@backstage/plugin-permission-common": "^0.3.0",
- "@backstage/plugin-permission-node": "^0.2.3",
+ "@backstage/plugin-kubernetes-backend": "^0.4.3",
+ "@backstage/plugin-kafka-backend": "^0.2.14",
+ "@backstage/plugin-permission-backend": "^0.3.0",
+ "@backstage/plugin-permission-common": "^0.3.1",
+ "@backstage/plugin-permission-node": "^0.3.0",
"@backstage/plugin-proxy-backend": "^0.2.15",
"@backstage/plugin-rollbar-backend": "^0.1.18",
- "@backstage/plugin-scaffolder-backend": "^0.15.19",
- "@backstage/plugin-scaffolder-backend-module-rails": "^0.2.2",
+ "@backstage/plugin-scaffolder-backend": "^0.15.20",
+ "@backstage/plugin-scaffolder-backend-module-rails": "^0.2.3",
"@backstage/plugin-search-backend": "^0.3.0",
- "@backstage/plugin-search-backend-node": "^0.4.2",
+ "@backstage/plugin-search-backend-node": "^0.4.4",
"@backstage/plugin-search-backend-module-elasticsearch": "^0.0.7",
"@backstage/plugin-search-backend-module-pg": "^0.2.3",
- "@backstage/plugin-techdocs-backend": "^0.12.2",
- "@backstage/plugin-tech-insights-backend": "^0.1.4",
+ "@backstage/plugin-techdocs-backend": "^0.12.3",
+ "@backstage/plugin-tech-insights-backend": "^0.1.5",
"@backstage/plugin-tech-insights-node": "^0.1.2",
- "@backstage/plugin-tech-insights-backend-module-jsonfc": "^0.1.4",
- "@backstage/plugin-todo-backend": "^0.1.17",
+ "@backstage/plugin-tech-insights-backend-module-jsonfc": "^0.1.5",
+ "@backstage/plugin-todo-backend": "^0.1.18",
"@gitbeaker/node": "^34.6.0",
"@octokit/rest": "^18.5.3",
"azure-devops-node-api": "^11.0.1",
"dockerode": "^3.3.1",
- "example-app": "^0.2.58",
+ "example-app": "^0.2.60",
"express": "^4.17.1",
"express-promise-router": "^4.1.0",
"express-prom-bundle": "^6.3.6",
@@ -72,7 +71,7 @@
"winston": "^3.2.1"
},
"devDependencies": {
- "@backstage/cli": "^0.10.4",
+ "@backstage/cli": "^0.11.0",
"@types/dockerode": "^3.3.0",
"@types/express": "^4.17.6",
"@types/express-serve-static-core": "^4.17.5"
diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts
index 1942c36ad1..b765df38f6 100644
--- a/packages/backend/src/index.ts
+++ b/packages/backend/src/index.ts
@@ -40,7 +40,6 @@ import { Config } from '@backstage/config';
import healthcheck from './plugins/healthcheck';
import { metricsInit, metricsHandler } from './metrics';
import auth from './plugins/auth';
-import azureDevOps from './plugins/azure-devops';
import catalog from './plugins/catalog';
import codeCoverage from './plugins/codecoverage';
import kubernetes from './plugins/kubernetes';
@@ -117,7 +116,6 @@ async function main() {
);
const scaffolderEnv = useHotMemoize(module, () => createEnv('scaffolder'));
const authEnv = useHotMemoize(module, () => createEnv('auth'));
- const azureDevOpsEnv = useHotMemoize(module, () => createEnv('azure-devops'));
const proxyEnv = useHotMemoize(module, () => createEnv('proxy'));
const rollbarEnv = useHotMemoize(module, () => createEnv('rollbar'));
const searchEnv = useHotMemoize(module, () => createEnv('search'));
@@ -141,7 +139,6 @@ async function main() {
apiRouter.use('/scaffolder', await scaffolder(scaffolderEnv));
apiRouter.use('/tech-insights', await techInsights(techInsightsEnv));
apiRouter.use('/auth', await auth(authEnv));
- apiRouter.use('/azure-devops', await azureDevOps(azureDevOpsEnv));
apiRouter.use('/search', await search(searchEnv));
apiRouter.use('/techdocs', await techdocs(techdocsEnv));
apiRouter.use('/todo', await todo(todoEnv));
diff --git a/packages/catalog-client/CHANGELOG.md b/packages/catalog-client/CHANGELOG.md
index 6d5c3d4a94..691cdac37c 100644
--- a/packages/catalog-client/CHANGELOG.md
+++ b/packages/catalog-client/CHANGELOG.md
@@ -1,5 +1,13 @@
# @backstage/catalog-client
+## 0.5.4
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/errors@0.2.0
+ - @backstage/catalog-model@0.9.9
+
## 0.5.3
### Patch Changes
diff --git a/packages/catalog-client/package.json b/packages/catalog-client/package.json
index 5ccb600e0c..97c500e4c3 100644
--- a/packages/catalog-client/package.json
+++ b/packages/catalog-client/package.json
@@ -1,7 +1,7 @@
{
"name": "@backstage/catalog-client",
"description": "An isomorphic client for the catalog backend",
- "version": "0.5.3",
+ "version": "0.5.4",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -30,12 +30,12 @@
"clean": "backstage-cli clean"
},
"dependencies": {
- "@backstage/catalog-model": "^0.9.7",
- "@backstage/errors": "^0.1.4",
+ "@backstage/catalog-model": "^0.9.9",
+ "@backstage/errors": "^0.2.0",
"cross-fetch": "^3.0.6"
},
"devDependencies": {
- "@backstage/cli": "^0.10.3",
+ "@backstage/cli": "^0.11.0",
"@types/jest": "^26.0.7",
"msw": "^0.35.0"
},
diff --git a/packages/catalog-model/CHANGELOG.md b/packages/catalog-model/CHANGELOG.md
index 8c0a65c20a..a669ef6dce 100644
--- a/packages/catalog-model/CHANGELOG.md
+++ b/packages/catalog-model/CHANGELOG.md
@@ -1,5 +1,13 @@
# @backstage/catalog-model
+## 0.9.9
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/config@0.1.12
+ - @backstage/errors@0.2.0
+
## 0.9.8
### Patch Changes
diff --git a/packages/catalog-model/package.json b/packages/catalog-model/package.json
index 6fdc89bdfb..c1a13d00f2 100644
--- a/packages/catalog-model/package.json
+++ b/packages/catalog-model/package.json
@@ -1,7 +1,7 @@
{
"name": "@backstage/catalog-model",
"description": "Types and validators that help describe the model of a Backstage Catalog",
- "version": "0.9.8",
+ "version": "0.9.9",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -30,8 +30,8 @@
"clean": "backstage-cli clean"
},
"dependencies": {
- "@backstage/config": "^0.1.11",
- "@backstage/errors": "^0.1.4",
+ "@backstage/config": "^0.1.12",
+ "@backstage/errors": "^0.2.0",
"@backstage/types": "^0.1.1",
"@types/json-schema": "^7.0.5",
"@types/yup": "^0.29.13",
@@ -42,7 +42,7 @@
"yup": "^0.32.9"
},
"devDependencies": {
- "@backstage/cli": "^0.10.2",
+ "@backstage/cli": "^0.11.0",
"@types/jest": "^26.0.7",
"@types/lodash": "^4.14.151",
"yaml": "^1.9.2"
diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md
index b412c1b079..f65caf08d4 100644
--- a/packages/cli/CHANGELOG.md
+++ b/packages/cli/CHANGELOG.md
@@ -1,5 +1,44 @@
# @backstage/cli
+## 0.11.0
+
+### Minor Changes
+
+- 14e980acee: ESLint upgraded to version 8 and all it's plugins updated to newest version.
+
+ If you use any custom plugins for ESLint please check compatibility.
+
+ ```diff
+ - "@typescript-eslint/eslint-plugin": "^v4.33.0",
+ - "@typescript-eslint/parser": "^v4.28.3",
+ + "@typescript-eslint/eslint-plugin": "^5.9.0",
+ + "@typescript-eslint/parser": "^5.9.0",
+ - "eslint": "^7.30.0",
+ + "eslint": "^8.6.0",
+ - "eslint-plugin-import": "^2.20.2",
+ - "eslint-plugin-jest": "^24.1.0",
+ - "eslint-plugin-jsx-a11y": "^6.2.1",
+ + "eslint-plugin-import": "^2.25.4",
+ + "eslint-plugin-jest": "^25.3.4",
+ + "eslint-plugin-jsx-a11y": "^6.5.1",
+ - "eslint-plugin-react": "^7.12.4",
+ - "eslint-plugin-react-hooks": "^4.0.0",
+ + "eslint-plugin-react": "^7.28.0",
+ + "eslint-plugin-react-hooks": "^4.3.0",
+ ```
+
+ Please consult changelogs from packages if you find any problems.
+
+### Patch Changes
+
+- f302d24d34: Switch Webpack minification to use `esbuild` instead of `terser`.
+- bee7082094: Update `config/eslint.js` to forbid imports of `@material-ui/icons/` as well.
+- 7946418729: Switched to using `@manypkg/get-packages` to list monorepo packages, which provides better support for different kind of monorepo setups.
+- Updated dependencies
+ - @backstage/config@0.1.12
+ - @backstage/errors@0.2.0
+ - @backstage/config-loader@0.9.2
+
## 0.10.5
### Patch Changes
diff --git a/packages/cli/package.json b/packages/cli/package.json
index be09563796..edb2cfb3ce 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.10.5",
+ "version": "0.11.0",
"private": false,
"publishConfig": {
"access": "public"
@@ -29,9 +29,9 @@
},
"dependencies": {
"@backstage/cli-common": "^0.1.6",
- "@backstage/config": "^0.1.11",
- "@backstage/config-loader": "^0.9.1",
- "@backstage/errors": "^0.1.5",
+ "@backstage/config": "^0.1.12",
+ "@backstage/config-loader": "^0.9.2",
+ "@backstage/errors": "^0.2.0",
"@backstage/types": "^0.1.1",
"@hot-loader/react-dom": "^16.13.0",
"@manypkg/get-packages": "^1.1.3",
@@ -115,13 +115,13 @@
"yn": "^4.0.0"
},
"devDependencies": {
- "@backstage/backend-common": "^0.10.2",
- "@backstage/config": "^0.1.11",
- "@backstage/core-components": "^0.8.3",
- "@backstage/core-plugin-api": "^0.4.1",
- "@backstage/core-app-api": "^0.3.1",
- "@backstage/dev-utils": "^0.2.16",
- "@backstage/test-utils": "^0.2.1",
+ "@backstage/backend-common": "^0.10.3",
+ "@backstage/config": "^0.1.12",
+ "@backstage/core-components": "^0.8.4",
+ "@backstage/core-plugin-api": "^0.5.0",
+ "@backstage/core-app-api": "^0.4.0",
+ "@backstage/dev-utils": "^0.2.17",
+ "@backstage/test-utils": "^0.2.2",
"@backstage/theme": "^0.2.14",
"@types/diff": "^5.0.0",
"@types/express": "^4.17.6",
diff --git a/packages/cli/src/commands/config/validate.ts b/packages/cli/src/commands/config/validate.ts
index 2d3ce60366..8d528b8300 100644
--- a/packages/cli/src/commands/config/validate.ts
+++ b/packages/cli/src/commands/config/validate.ts
@@ -23,5 +23,6 @@ export default async (cmd: Command) => {
fromPackage: cmd.package,
mockEnv: cmd.lax,
fullVisibility: !cmd.frontend,
+ withDeprecatedKeys: cmd.deprecated,
});
};
diff --git a/packages/cli/src/commands/index.ts b/packages/cli/src/commands/index.ts
index fa00bf4073..dfe427b27b 100644
--- a/packages/cli/src/commands/index.ts
+++ b/packages/cli/src/commands/index.ts
@@ -193,6 +193,7 @@ export function registerCommands(program: CommanderStatic) {
)
.option('--lax', 'Do not require environment variables to be set')
.option('--frontend', 'Only validate the frontend configuration')
+ .option('--deprecated', 'Output deprecated configuration settings')
.option(...configOption)
.description(
'Validate that the given configuration loads and matches schema',
diff --git a/packages/cli/src/lib/config.ts b/packages/cli/src/lib/config.ts
index b43e4798b4..e7ceeadf08 100644
--- a/packages/cli/src/lib/config.ts
+++ b/packages/cli/src/lib/config.ts
@@ -30,6 +30,7 @@ type Options = {
fromPackage?: string;
mockEnv?: boolean;
withFilteredKeys?: boolean;
+ withDeprecatedKeys?: boolean;
fullVisibility?: boolean;
};
@@ -91,6 +92,7 @@ export async function loadCliConfig(options: Options) {
? ['frontend', 'backend', 'secret']
: ['frontend'],
withFilteredKeys: options.withFilteredKeys,
+ withDeprecatedKeys: options.withDeprecatedKeys,
});
const frontendConfig = ConfigReader.fromConfigs(frontendAppConfigs);
diff --git a/packages/codemods/CHANGELOG.md b/packages/codemods/CHANGELOG.md
index 7c6ccaf9fe..c7a70212e6 100644
--- a/packages/codemods/CHANGELOG.md
+++ b/packages/codemods/CHANGELOG.md
@@ -1,5 +1,14 @@
# @backstage/codemods
+## 0.1.29
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/core-components@0.8.4
+ - @backstage/core-plugin-api@0.5.0
+ - @backstage/core-app-api@0.4.0
+
## 0.1.28
### Patch Changes
diff --git a/packages/codemods/package.json b/packages/codemods/package.json
index 88ed029f00..9a3cb370b9 100644
--- a/packages/codemods/package.json
+++ b/packages/codemods/package.json
@@ -1,7 +1,7 @@
{
"name": "@backstage/codemods",
"description": "A collection of codemods for Backstage projects",
- "version": "0.1.28",
+ "version": "0.1.29",
"private": false,
"publishConfig": {
"access": "public",
diff --git a/packages/config-loader/CHANGELOG.md b/packages/config-loader/CHANGELOG.md
index 36aae32e8b..d91ac57ab2 100644
--- a/packages/config-loader/CHANGELOG.md
+++ b/packages/config-loader/CHANGELOG.md
@@ -1,5 +1,13 @@
# @backstage/config-loader
+## 0.9.2
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/config@0.1.12
+ - @backstage/errors@0.2.0
+
## 0.9.1
### Patch Changes
diff --git a/packages/config-loader/api-report.md b/packages/config-loader/api-report.md
index 106c744d7b..06868e0f47 100644
--- a/packages/config-loader/api-report.md
+++ b/packages/config-loader/api-report.md
@@ -21,6 +21,7 @@ export type ConfigSchemaProcessingOptions = {
visibility?: ConfigVisibility[];
valueTransform?: TransformFunc;
withFilteredKeys?: boolean;
+ withDeprecatedKeys?: boolean;
};
// @public (undocumented)
diff --git a/packages/config-loader/package.json b/packages/config-loader/package.json
index d909cde58c..6e6364c9b0 100644
--- a/packages/config-loader/package.json
+++ b/packages/config-loader/package.json
@@ -1,7 +1,7 @@
{
"name": "@backstage/config-loader",
"description": "Config loading functionality used by Backstage backend, and CLI",
- "version": "0.9.1",
+ "version": "0.9.2",
"private": false,
"publishConfig": {
"access": "public",
@@ -31,8 +31,8 @@
},
"dependencies": {
"@backstage/cli-common": "^0.1.6",
- "@backstage/config": "^0.1.11",
- "@backstage/errors": "^0.1.4",
+ "@backstage/config": "^0.1.12",
+ "@backstage/errors": "^0.2.0",
"@backstage/types": "^0.1.1",
"@types/json-schema": "^7.0.6",
"ajv": "^7.0.3",
diff --git a/packages/config-loader/src/lib/schema/collect.ts b/packages/config-loader/src/lib/schema/collect.ts
index 8e7f582e44..a05796139b 100644
--- a/packages/config-loader/src/lib/schema/collect.ts
+++ b/packages/config-loader/src/lib/schema/collect.ts
@@ -182,10 +182,10 @@ function compileTsSchemas(paths: string[]) {
program,
// All schemas should export a `Config` symbol
'Config',
- // This enables usage of @visibility is doc comments
+ // This enables usage of @visibility and @deprecated in doc comments
{
required: true,
- validationKeywords: ['visibility'],
+ validationKeywords: ['visibility', 'deprecated'],
},
[path.split(sep).join('/')], // Unix paths are expected for all OSes here
) as JsonObject | null;
diff --git a/packages/config-loader/src/lib/schema/compile.test.ts b/packages/config-loader/src/lib/schema/compile.test.ts
index 1e63f3cbf8..7b7db87c8f 100644
--- a/packages/config-loader/src/lib/schema/compile.test.ts
+++ b/packages/config-loader/src/lib/schema/compile.test.ts
@@ -40,6 +40,7 @@ describe('compileConfigSchemas', () => {
],
visibilityByDataPath: new Map(),
visibilityBySchemaPath: new Map(),
+ deprecationByDataPath: new Map(),
});
expect(validate([{ data: { b: 'b' }, context: 'test' }])).toEqual({
errors: [
@@ -53,6 +54,7 @@ describe('compileConfigSchemas', () => {
],
visibilityByDataPath: new Map(),
visibilityBySchemaPath: new Map(),
+ deprecationByDataPath: new Map(),
});
});
@@ -112,6 +114,7 @@ describe('compileConfigSchemas', () => {
'/properties/d/items': 'frontend',
}),
),
+ deprecationByDataPath: new Map(),
});
});
@@ -137,4 +140,34 @@ describe('compileConfigSchemas', () => {
"Config schema visibility is both 'frontend' and 'secret' for properties/a/visibility",
);
});
+
+ it('should discover deprecations', () => {
+ const validate = compileConfigSchemas([
+ {
+ path: 'a1',
+ value: {
+ type: 'object',
+ properties: {
+ a: { type: 'string', deprecated: 'deprecation reason for a' },
+ b: { type: 'string', deprecated: 'deprecation reason for b' },
+ c: { type: 'string' },
+ },
+ },
+ },
+ ]);
+ expect(
+ validate([
+ { data: { a: 'a', b: 'b', c: 'c', d: ['d'] }, context: 'test' },
+ ]),
+ ).toEqual({
+ deprecationByDataPath: new Map(
+ Object.entries({
+ '/a': 'deprecation reason for a',
+ '/b': 'deprecation reason for b',
+ }),
+ ),
+ visibilityByDataPath: new Map(),
+ visibilityBySchemaPath: new Map(),
+ });
+ });
});
diff --git a/packages/config-loader/src/lib/schema/compile.ts b/packages/config-loader/src/lib/schema/compile.ts
index 1cbf5a404d..b7f705751e 100644
--- a/packages/config-loader/src/lib/schema/compile.ts
+++ b/packages/config-loader/src/lib/schema/compile.ts
@@ -40,6 +40,7 @@ export function compileConfigSchemas(
// output during validation. We work around this by having this extra piece
// of state that we reset before each validation.
const visibilityByDataPath = new Map();
+ const deprecationByDataPath = new Map();
const ajv = new Ajv({
allErrors: true,
@@ -47,28 +48,48 @@ export function compileConfigSchemas(
schemas: {
'https://backstage.io/schema/config-v1': true,
},
- }).addKeyword({
- keyword: 'visibility',
- metaSchema: {
- type: 'string',
- enum: CONFIG_VISIBILITIES,
- },
- compile(visibility: ConfigVisibility) {
- return (_data, context) => {
- if (context?.dataPath === undefined) {
- return false;
- }
- if (visibility && visibility !== 'backend') {
+ })
+ .addKeyword({
+ keyword: 'visibility',
+ metaSchema: {
+ type: 'string',
+ enum: CONFIG_VISIBILITIES,
+ },
+ compile(visibility: ConfigVisibility) {
+ return (_data, context) => {
+ if (context?.dataPath === undefined) {
+ return false;
+ }
+ if (visibility && visibility !== 'backend') {
+ const normalizedPath = context.dataPath.replace(
+ /\['?(.*?)'?\]/g,
+ (_, segment) => `/${segment}`,
+ );
+ visibilityByDataPath.set(normalizedPath, visibility);
+ }
+ return true;
+ };
+ },
+ })
+ .removeKeyword('deprecated') // remove `deprecated` keyword so that we can implement our own compiler
+ .addKeyword({
+ keyword: 'deprecated',
+ metaSchema: { type: 'string' },
+ compile(deprecationDescription: string) {
+ return (_data, context) => {
+ if (context?.dataPath === undefined) {
+ return false;
+ }
const normalizedPath = context.dataPath.replace(
/\['?(.*?)'?\]/g,
(_, segment) => `/${segment}`,
);
- visibilityByDataPath.set(normalizedPath, visibility);
- }
- return true;
- };
- },
- });
+ // create mapping of deprecation description and data path of property
+ deprecationByDataPath.set(normalizedPath, deprecationDescription);
+ return true;
+ };
+ },
+ });
for (const schema of schemas) {
try {
@@ -79,6 +100,7 @@ export function compileConfigSchemas(
}
const merged = mergeConfigSchemas(schemas.map(_ => _.value));
+
const validate = ajv.compile(merged);
const visibilityBySchemaPath = new Map();
@@ -94,17 +116,20 @@ export function compileConfigSchemas(
visibilityByDataPath.clear();
const valid = validate(config);
+
if (!valid) {
return {
errors: validate.errors ?? [],
visibilityByDataPath: new Map(visibilityByDataPath),
visibilityBySchemaPath,
+ deprecationByDataPath,
};
}
return {
visibilityByDataPath: new Map(visibilityByDataPath),
visibilityBySchemaPath,
+ deprecationByDataPath,
};
};
}
diff --git a/packages/config-loader/src/lib/schema/filtering.test.ts b/packages/config-loader/src/lib/schema/filtering.test.ts
index be07b915ed..df06975c9f 100644
--- a/packages/config-loader/src/lib/schema/filtering.test.ts
+++ b/packages/config-loader/src/lib/schema/filtering.test.ts
@@ -64,6 +64,13 @@ const visibility = new Map(
}),
);
+const deprecations = new Map(
+ Object.entries({
+ '/arr': 'deprecated array',
+ '/objB/never': 'deprecated nested property',
+ }),
+);
+
describe('filterByVisibility', () => {
test.each<[ConfigVisibility[], JsonObject]>([
[
@@ -185,9 +192,34 @@ describe('filterByVisibility', () => {
[['frontend', 'backend', 'secret'], { data, filteredKeys: [] }],
])('should filter correctly with %p', (filter, expected) => {
expect(
- filterByVisibility(data, filter, visibility, undefined, true),
+ filterByVisibility(
+ data,
+ filter,
+ visibility,
+ deprecations,
+ undefined,
+ true,
+ false,
+ ),
).toEqual(expected);
});
+
+ it('should include deprecated keys regardless of visibility', () => {
+ expect(
+ filterByVisibility(
+ data,
+ [],
+ visibility,
+ deprecations,
+ undefined,
+ true,
+ true,
+ ).deprecatedKeys,
+ ).toEqual([
+ { key: 'arr', description: 'deprecated array' },
+ { key: 'objB.never', description: 'deprecated nested property' },
+ ]);
+ });
});
describe('filterErrorsByVisibility', () => {
diff --git a/packages/config-loader/src/lib/schema/filtering.ts b/packages/config-loader/src/lib/schema/filtering.ts
index b2f39d3cc4..2855979b1f 100644
--- a/packages/config-loader/src/lib/schema/filtering.ts
+++ b/packages/config-loader/src/lib/schema/filtering.ts
@@ -30,10 +30,17 @@ export function filterByVisibility(
data: JsonObject,
includeVisibilities: ConfigVisibility[],
visibilityByDataPath: Map,
+ deprecationByDataPath: Map,
transformFunc?: TransformFunc,
withFilteredKeys?: boolean,
-): { data: JsonObject; filteredKeys?: string[] } {
+ withDeprecatedKeys?: boolean,
+): {
+ data: JsonObject;
+ filteredKeys?: string[];
+ deprecatedKeys?: { key: string; description: string }[];
+} {
const filteredKeys = new Array();
+ const deprecatedKeys = new Array<{ key: string; description: string }>();
function transform(
jsonVal: JsonValue,
@@ -44,6 +51,12 @@ export function filterByVisibility(
visibilityByDataPath.get(visibilityPath) ?? DEFAULT_CONFIG_VISIBILITY;
const isVisible = includeVisibilities.includes(visibility);
+ // deprecated keys are added regardless of visibility indicator
+ const deprecation = deprecationByDataPath.get(visibilityPath);
+ if (deprecation) {
+ deprecatedKeys.push({ key: filterPath, description: deprecation });
+ }
+
if (typeof jsonVal !== 'object') {
if (isVisible) {
if (transformFunc) {
@@ -109,6 +122,7 @@ export function filterByVisibility(
return {
filteredKeys: withFilteredKeys ? filteredKeys : undefined,
+ deprecatedKeys: withDeprecatedKeys ? deprecatedKeys : undefined,
data: (transform(data, '', '') as JsonObject) ?? {},
};
}
diff --git a/packages/config-loader/src/lib/schema/load.test.ts b/packages/config-loader/src/lib/schema/load.test.ts
index e2ae3cc2c7..8510ccb1d8 100644
--- a/packages/config-loader/src/lib/schema/load.test.ts
+++ b/packages/config-loader/src/lib/schema/load.test.ts
@@ -62,7 +62,10 @@ describe('loadConfigSchema', () => {
expect(schema.process(configs)).toEqual(configs);
expect(schema.process(configs, { visibility: ['frontend'] })).toEqual([
- { data: { key1: 'a' }, context: 'test' },
+ {
+ data: { key1: 'a' },
+ context: 'test',
+ },
]);
expect(
schema.process(configs, {
@@ -71,7 +74,11 @@ describe('loadConfigSchema', () => {
withFilteredKeys: true,
}),
).toEqual([
- { data: { key1: 'X' }, context: 'test', filteredKeys: ['key2'] },
+ {
+ data: { key1: 'X' },
+ context: 'test',
+ filteredKeys: ['key2'],
+ },
]);
expect(
schema.process(configs, {
@@ -79,14 +86,21 @@ describe('loadConfigSchema', () => {
withFilteredKeys: true,
}),
).toEqual([
- { data: { key1: 'X', key2: 'X' }, context: 'test', filteredKeys: [] },
+ {
+ data: { key1: 'X', key2: 'X' },
+ context: 'test',
+ filteredKeys: [],
+ },
]);
const serialized = schema.serialize();
const schema2 = await loadConfigSchema({ serialized });
expect(schema2.process(configs, { visibility: ['frontend'] })).toEqual([
- { data: { key1: 'a' }, context: 'test' },
+ {
+ data: { key1: 'a' },
+ context: 'test',
+ },
]);
expect(() =>
schema2.process([...configs, { data: { key1: 3 }, context: 'test2' }]),
@@ -131,7 +145,10 @@ describe('loadConfigSchema', () => {
'Config validation failed, Config should be number { type=number } at /key2',
);
expect(schema.process(configs, { visibility: ['frontend'] })).toEqual([
- { data: { key1: 'a' }, context: 'test' },
+ {
+ data: { key1: 'a' },
+ context: 'test',
+ },
]);
expect(() => schema.process(configs, { visibility: ['secret'] })).toThrow(
'Config validation failed, Config should be number { type=number } at /key2',
@@ -179,7 +196,12 @@ describe('loadConfigSchema', () => {
];
expect(
schema.process(mkConfig({ x: 1 }), { visibility: ['frontend'] }),
- ).toEqual([{ data: { nested: [{}] }, context: 'test' }]);
+ ).toEqual([
+ {
+ data: { nested: [{}] },
+ context: 'test',
+ },
+ ]);
expect(() => schema.process(mkConfig({ y: 1 }))).toThrow(
'Config validation failed, Config should be string { type=string } at /nested/0/y',
);
@@ -190,10 +212,20 @@ describe('loadConfigSchema', () => {
);
expect(
schema.process(mkConfig({ x: 'a' }), { visibility: ['frontend'] }),
- ).toEqual([{ data: { nested: [{}] }, context: 'test' }]);
+ ).toEqual([
+ {
+ data: { nested: [{}] },
+ context: 'test',
+ },
+ ]);
expect(
schema.process(mkConfig({ y: 'aaa' }), { visibility: ['frontend'] }),
- ).toEqual([{ data: { nested: [{ y: 'aaa' }] }, context: 'test' }]);
+ ).toEqual([
+ {
+ data: { nested: [{ y: 'aaa' }] },
+ context: 'test',
+ },
+ ]);
expect(() =>
schema.process(mkConfig({ y: 'aaaa' }), { visibility: ['frontend'] }),
).toThrow(
diff --git a/packages/config-loader/src/lib/schema/load.ts b/packages/config-loader/src/lib/schema/load.ts
index 2d78785304..aa7ed06305 100644
--- a/packages/config-loader/src/lib/schema/load.ts
+++ b/packages/config-loader/src/lib/schema/load.ts
@@ -82,7 +82,7 @@ export async function loadConfigSchema(
return {
process(
configs: AppConfig[],
- { visibility, valueTransform, withFilteredKeys } = {},
+ { visibility, valueTransform, withFilteredKeys, withDeprecatedKeys } = {},
): AppConfig[] {
const result = validate(configs);
@@ -105,8 +105,10 @@ export async function loadConfigSchema(
data,
visibility,
result.visibilityByDataPath,
+ result.deprecationByDataPath,
valueTransform,
withFilteredKeys,
+ withDeprecatedKeys,
),
}));
} else if (valueTransform) {
@@ -116,8 +118,10 @@ export async function loadConfigSchema(
data,
Array.from(CONFIG_VISIBILITIES),
result.visibilityByDataPath,
+ result.deprecationByDataPath,
valueTransform,
withFilteredKeys,
+ withDeprecatedKeys,
),
}));
}
diff --git a/packages/config-loader/src/lib/schema/types.ts b/packages/config-loader/src/lib/schema/types.ts
index 53f4dec88e..75993b3c78 100644
--- a/packages/config-loader/src/lib/schema/types.ts
+++ b/packages/config-loader/src/lib/schema/types.ts
@@ -81,6 +81,13 @@ type ValidationResult = {
* The path in the key uses the form `/properties//items/additionalProperties/`
*/
visibilityBySchemaPath: Map;
+
+ /**
+ * The deprecated options that were discovered during validation.
+ *
+ * The path in the key uses the form `////`
+ */
+ deprecationByDataPath: Map;
};
/**
@@ -124,6 +131,13 @@ export type ConfigSchemaProcessingOptions = {
* Default: `false`.
*/
withFilteredKeys?: boolean;
+
+ /**
+ * Whether or not to include the `deprecatedKeys` property in the output `AppConfig`s.
+ *
+ * Default: `true`.
+ */
+ withDeprecatedKeys?: boolean;
};
/**
diff --git a/packages/config/CHANGELOG.md b/packages/config/CHANGELOG.md
index de62de5466..05377ffff3 100644
--- a/packages/config/CHANGELOG.md
+++ b/packages/config/CHANGELOG.md
@@ -1,5 +1,11 @@
# @backstage/config
+## 0.1.12
+
+### Patch Changes
+
+- f5343e7c1a: The `ConfigReader#get` method now always returns a deep clone of the configuration data.
+
## 0.1.11
### Patch Changes
diff --git a/packages/config/api-report.md b/packages/config/api-report.md
index efa6b85559..df9baeb4cd 100644
--- a/packages/config/api-report.md
+++ b/packages/config/api-report.md
@@ -13,6 +13,10 @@ export type AppConfig = {
context: string;
data: JsonObject_2;
filteredKeys?: string[];
+ deprecatedKeys?: {
+ key: string;
+ description: string;
+ }[];
};
// @public
diff --git a/packages/config/package.json b/packages/config/package.json
index 86e1f5d79c..29d09a5cf8 100644
--- a/packages/config/package.json
+++ b/packages/config/package.json
@@ -1,7 +1,7 @@
{
"name": "@backstage/config",
"description": "Config API used by Backstage core, backend, and CLI",
- "version": "0.1.11",
+ "version": "0.1.12",
"private": false,
"publishConfig": {
"access": "public",
@@ -34,7 +34,7 @@
"lodash": "^4.17.21"
},
"devDependencies": {
- "@backstage/test-utils": "^0.2.0",
+ "@backstage/test-utils": "^0.2.2",
"@types/jest": "^26.0.7",
"@types/node": "^14.14.32"
},
diff --git a/packages/config/src/reader.ts b/packages/config/src/reader.ts
index 129a703784..1ce54590b5 100644
--- a/packages/config/src/reader.ts
+++ b/packages/config/src/reader.ts
@@ -83,9 +83,21 @@ export class ConfigReader implements Config {
// Merge together all configs into a single config with recursive fallback
// readers, giving the first config object in the array the lowest priority.
return configs.reduce(
- (previousReader, { data, context, filteredKeys }) => {
+ (previousReader, { data, context, filteredKeys, deprecatedKeys }) => {
const reader = new ConfigReader(data, context, previousReader);
reader.filteredKeys = filteredKeys;
+
+ if (deprecatedKeys) {
+ for (const { key, description } of deprecatedKeys) {
+ // eslint-disable-next-line no-console
+ console.warn(
+ `The configuration key '${key}' of ${context} is deprecated and may be removed soon. ${
+ description || ''
+ }`,
+ );
+ }
+ }
+
return reader;
},
undefined!,
diff --git a/packages/config/src/types.ts b/packages/config/src/types.ts
index a543233277..37c9595565 100644
--- a/packages/config/src/types.ts
+++ b/packages/config/src/types.ts
@@ -36,6 +36,12 @@ export type AppConfig = {
* This can be used to warn the user if they try to read any of these keys.
*/
filteredKeys?: string[];
+ /**
+ * A list of deprecated keys that were found in the configuration when it was loaded.
+ *
+ * This can be used to warn the user if they are using deprecated properties.
+ */
+ deprecatedKeys?: { key: string; description: string }[];
};
/**
diff --git a/packages/core-app-api/CHANGELOG.md b/packages/core-app-api/CHANGELOG.md
index bdd3129235..b18ec0685f 100644
--- a/packages/core-app-api/CHANGELOG.md
+++ b/packages/core-app-api/CHANGELOG.md
@@ -1,5 +1,22 @@
# @backstage/core-app-api
+## 0.4.0
+
+### Minor Changes
+
+- e2eb92c109: Removed previously deprecated `ApiRegistry` export.
+
+### Patch Changes
+
+- 34442cd5cf: Fixed an issue where valid SAML and GitHub sessions would be considered invalid and not be stored.
+
+ Deprecated the `SamlSession` and `GithubSession` types.
+
+- 784d8078ab: Removed direct and transitive MUI dependencies.
+- Updated dependencies
+ - @backstage/config@0.1.12
+ - @backstage/core-plugin-api@0.5.0
+
## 0.3.1
### Patch Changes
diff --git a/packages/core-app-api/package.json b/packages/core-app-api/package.json
index de7477771f..dbce1e62cc 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": "0.3.1",
+ "version": "0.4.0",
"private": false,
"publishConfig": {
"access": "public",
@@ -29,8 +29,8 @@
"clean": "backstage-cli clean"
},
"dependencies": {
- "@backstage/config": "^0.1.11",
- "@backstage/core-plugin-api": "^0.4.1",
+ "@backstage/config": "^0.1.12",
+ "@backstage/core-plugin-api": "^0.5.0",
"@backstage/types": "^0.1.1",
"@backstage/version-bridge": "^0.1.1",
"@types/prop-types": "^15.7.3",
@@ -45,8 +45,8 @@
"react": "^16.13.1 || ^17.0.0"
},
"devDependencies": {
- "@backstage/cli": "^0.10.5",
- "@backstage/test-utils": "^0.2.0",
+ "@backstage/cli": "^0.11.0",
+ "@backstage/test-utils": "^0.2.2",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^11.2.5",
"@testing-library/react-hooks": "^7.0.2",
diff --git a/packages/core-components/CHANGELOG.md b/packages/core-components/CHANGELOG.md
index 9f306bb10f..5f2e20f0a3 100644
--- a/packages/core-components/CHANGELOG.md
+++ b/packages/core-components/CHANGELOG.md
@@ -1,5 +1,18 @@
# @backstage/core-components
+## 0.8.4
+
+### Patch Changes
+
+- 6415189d99: Add a `ProxiedSignInPage` that can be used e.g. for GCP IAP and AWS ALB
+- de2396da24: Create a short delay when `` is opened
+- 5333451def: Cleaned up API exports
+- e2eb92c109: Updated `ResponseErrorPanel` to not use the deprecated `data` property of `ResponseError`.
+- Updated dependencies
+ - @backstage/config@0.1.12
+ - @backstage/core-plugin-api@0.5.0
+ - @backstage/errors@0.2.0
+
## 0.8.3
### Patch Changes
diff --git a/packages/core-components/api-report.md b/packages/core-components/api-report.md
index 87a9186d5b..29847b079e 100644
--- a/packages/core-components/api-report.md
+++ b/packages/core-components/api-report.md
@@ -752,6 +752,16 @@ export function Progress(
props: PropsWithChildren,
): JSX.Element;
+// @public
+export const ProxiedSignInPage: (
+ props: ProxiedSignInPageProps,
+) => JSX.Element | null;
+
+// @public
+export type ProxiedSignInPageProps = SignInPageProps & {
+ provider: string;
+};
+
// Warning: (ae-missing-release-tag) "Ranker" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public
diff --git a/packages/core-components/package.json b/packages/core-components/package.json
index 337a759da8..83415ace48 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.8.3",
+ "version": "0.8.4",
"private": false,
"publishConfig": {
"access": "public",
@@ -29,9 +29,9 @@
"clean": "backstage-cli clean"
},
"dependencies": {
- "@backstage/config": "^0.1.11",
- "@backstage/core-plugin-api": "^0.4.1",
- "@backstage/errors": "^0.1.5",
+ "@backstage/config": "^0.1.12",
+ "@backstage/core-plugin-api": "^0.5.0",
+ "@backstage/errors": "^0.2.0",
"@backstage/theme": "^0.2.14",
"@material-table/core": "^3.1.0",
"@material-ui/core": "^4.12.2",
@@ -58,13 +58,14 @@
"react-router": "6.0.0-beta.0",
"react-router-dom": "6.0.0-beta.0",
"react-sparklines": "^1.7.0",
- "react-syntax-highlighter": "^15.4.3",
+ "react-syntax-highlighter": "^15.4.5",
"react-text-truncate": "^0.16.0",
"react-use": "^17.2.4",
"react-virtualized-auto-sizer": "^1.0.6",
"react-window": "^1.8.6",
"remark-gfm": "^2.0.0",
- "zen-observable": "^0.8.15"
+ "zen-observable": "^0.8.15",
+ "zod": "^3.11.6"
},
"peerDependencies": {
"@types/react": "^16.13.1 || ^17.0.0",
@@ -72,9 +73,9 @@
"react-dom": "^16.13.1 || ^17.0.0"
},
"devDependencies": {
- "@backstage/core-app-api": "^0.3.1",
- "@backstage/cli": "^0.10.5",
- "@backstage/test-utils": "^0.2.0",
+ "@backstage/core-app-api": "^0.4.0",
+ "@backstage/cli": "^0.11.0",
+ "@backstage/test-utils": "^0.2.2",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^11.2.5",
"@testing-library/react-hooks": "^7.0.2",
@@ -92,7 +93,9 @@
"@types/react-syntax-highlighter": "^13.5.2",
"@types/react-virtualized-auto-sizer": "^1.0.1",
"@types/react-window": "^1.8.5",
- "@types/zen-observable": "^0.8.0"
+ "@types/zen-observable": "^0.8.0",
+ "cross-fetch": "^3.0.6",
+ "msw": "^0.35.0"
},
"files": [
"dist"
diff --git a/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInIdentity.test.ts b/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInIdentity.test.ts
new file mode 100644
index 0000000000..00e0c02373
--- /dev/null
+++ b/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInIdentity.test.ts
@@ -0,0 +1,166 @@
+/*
+ * 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 { setupRequestMockHandlers } from '@backstage/test-utils';
+import { rest } from 'msw';
+import { setupServer } from 'msw/node';
+import {
+ DEFAULTS,
+ ProxiedSignInIdentity,
+ tokenToExpiry,
+} from './ProxiedSignInIdentity';
+
+const validBackstageTokenExpClaim = 1641216199;
+const validBackstageToken =
+ 'eyJhbGciOiJFUzI1NiIsImtpZCI6ImMxNTMzNDRiLWZjYzktNGIwOS1iN2ZhLTU3ZmM5MDhjMjBiNiJ9.eyJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjcwMDcvYXBpL2F1dGgiLCJzdWIiOiJmcmViZW4iLCJhdWQiOiJiYWNrc3RhZ2UiLCJpYXQiOjE2NDEyMTI1OTksImV4cCI6MTY0MTIxNjE5OSwiZW50IjpbInVzZXI6ZGVmYXVsdC9mcmViZW4iXX0.4nOTmPHPwhzaKTzikgUsHcszfcP-JamcojMnRfyfsKhyHCCEywe6uLFlvvmK5NbaX5Z7IIji-kg7bxKU58kwoQ';
+
+describe('ProxiedSignInIdentity', () => {
+ describe('tokenToExpiry', () => {
+ beforeEach(() => jest.useFakeTimers('modern'));
+ afterEach(() => jest.useRealTimers());
+
+ it('handles undefined', async () => {
+ expect(tokenToExpiry(undefined)).toEqual(
+ new Date(Date.now() + DEFAULTS.defaultTokenExpiryMillis),
+ );
+ });
+
+ it('handles a valid token', async () => {
+ expect(tokenToExpiry(validBackstageToken)).toEqual(
+ new Date(
+ validBackstageTokenExpClaim * 1000 - DEFAULTS.tokenExpiryMarginMillis,
+ ),
+ );
+ });
+
+ it('handles a token that has no exp', async () => {
+ const [a, _b, c] = validBackstageToken.split('.');
+ const botched = `${a}.${btoa(JSON.stringify({}))}.${c}`;
+ expect(tokenToExpiry(botched)).toEqual(
+ new Date(new Date(Date.now() + DEFAULTS.defaultTokenExpiryMillis)),
+ );
+ });
+ });
+
+ describe('ProxiedSignInIdentity', () => {
+ beforeEach(() => jest.useFakeTimers('modern'));
+ afterEach(() => jest.useRealTimers());
+
+ const worker = setupServer();
+ setupRequestMockHandlers(worker);
+
+ it('runs the happy path', async () => {
+ const getBaseUrl = jest.fn();
+ const serverCalled = jest.fn();
+
+ function makeToken() {
+ const iat = Math.floor(Date.now() / 1000);
+ const exp = iat + 3600;
+ return {
+ providerInfo: {
+ stuff: 1,
+ },
+ profile: {
+ email: 'e',
+ displayName: 'd',
+ picture: 'p',
+ },
+ backstageIdentity: {
+ token: [
+ 'eyJhbGciOiJFUzI1NiIsImtpZCI6ImMxNTMzNDRiLWZjYzktNGIwOS1iN2ZhLTU3ZmM5MDhjMjBiNiJ9',
+ btoa(
+ JSON.stringify({
+ iss: 'http://localhost:7007/api/auth',
+ sub: 'user:default/freben',
+ aud: 'backstage',
+ iat,
+ exp,
+ ent: ['group:default/my-team'],
+ }),
+ ).replace(/=/g, ''),
+ '4nOTmPHPwhzaKTzikgUsHcszfcP-JamcojMnRfyfsKhyHCCEywe6uLFlvvmK5NbaX5Z7IIji-kg7bxKU58kwoQ',
+ ].join('.'),
+ identity: {
+ type: 'user',
+ userEntityRef: 'k:ns/ue',
+ ownershipEntityRefs: ['k:ns/oe'],
+ },
+ },
+ };
+ }
+
+ worker.events.on('request:match', serverCalled);
+ worker.use(
+ rest.get('http://example.com/api/auth/foo/refresh', (_, res, ctx) =>
+ res(
+ ctx.status(200),
+ ctx.set('Content-Type', 'application/json'),
+ ctx.json(makeToken()),
+ ),
+ ),
+ );
+
+ const identity = new ProxiedSignInIdentity({
+ provider: 'foo',
+ discoveryApi: { getBaseUrl },
+ });
+
+ getBaseUrl.mockResolvedValue('http://example.com/api/auth');
+
+ await identity.start(); // should not throw
+ expect(getBaseUrl).toBeCalledTimes(1);
+ expect(getBaseUrl).lastCalledWith('auth');
+ expect(serverCalled).toBeCalledTimes(1);
+
+ // All information should now be available
+ await expect(identity.getBackstageIdentity()).resolves.toEqual({
+ type: 'user',
+ userEntityRef: 'k:ns/ue',
+ ownershipEntityRefs: ['k:ns/oe'],
+ });
+ await expect(identity.getIdToken()).resolves.toEqual(expect.any(String));
+ await expect(identity.getCredentials()).resolves.toEqual({
+ token: expect.any(String),
+ });
+ await expect(identity.getProfileInfo()).resolves.toEqual({
+ email: 'e',
+ displayName: 'd',
+ picture: 'p',
+ });
+ expect(identity.getUserId()).toBe('ue');
+ expect(identity.getProfile()).toEqual({
+ email: 'e',
+ displayName: 'd',
+ picture: 'p',
+ });
+
+ await identity.getSessionAsync(); // no need to fetch again just yet
+ expect(serverCalled).toBeCalledTimes(1);
+
+ // Use a fairly large margin (1000) since the iat and exp are clamped to
+ // full seconds, but the "local current time" isn't
+ jest.advanceTimersByTime(
+ 3600 * 1000 - DEFAULTS.tokenExpiryMarginMillis - 1000,
+ );
+ await identity.getSessionAsync(); // still no need to fetch again
+ expect(serverCalled).toBeCalledTimes(1);
+
+ jest.advanceTimersByTime(1001);
+ await identity.getSessionAsync(); // now the expiry has passed
+ expect(serverCalled).toBeCalledTimes(2);
+ });
+ });
+});
diff --git a/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInIdentity.ts b/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInIdentity.ts
new file mode 100644
index 0000000000..2247d17d82
--- /dev/null
+++ b/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInIdentity.ts
@@ -0,0 +1,214 @@
+/*
+ * 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 {
+ BackstageUserIdentity,
+ discoveryApiRef,
+ IdentityApi,
+ ProfileInfo,
+} from '@backstage/core-plugin-api';
+import { ResponseError } from '@backstage/errors';
+import { ProxiedSession, proxiedSessionSchema } from './types';
+
+export const DEFAULTS = {
+ // The amount of time between token refreshes, if we fail to get an actual
+ // value out of the exp claim
+ defaultTokenExpiryMillis: 5 * 60 * 1000,
+ // The amount of time before the actual expiry of the Backstage token, that we
+ // shall start trying to get a new one
+ tokenExpiryMarginMillis: 5 * 60 * 1000,
+} as const;
+
+// When the token expires, with some margin
+export function tokenToExpiry(jwtToken: string | undefined): Date {
+ const fallback = new Date(Date.now() + DEFAULTS.defaultTokenExpiryMillis);
+ if (!jwtToken) {
+ return fallback;
+ }
+
+ const [_header, rawPayload, _signature] = jwtToken.split('.');
+ const payload = JSON.parse(atob(rawPayload));
+ if (typeof payload.exp !== 'number') {
+ return fallback;
+ }
+
+ return new Date(payload.exp * 1000 - DEFAULTS.tokenExpiryMarginMillis);
+}
+
+type ProxiedSignInIdentityOptions = {
+ provider: string;
+ discoveryApi: typeof discoveryApiRef.T;
+};
+
+type State =
+ | {
+ type: 'empty';
+ }
+ | {
+ type: 'fetching';
+ promise: Promise;
+ previous: ProxiedSession | undefined;
+ }
+ | {
+ type: 'active';
+ session: ProxiedSession;
+ expiresAt: Date;
+ }
+ | {
+ type: 'failed';
+ error: Error;
+ };
+
+/**
+ * An identity API that gets the user auth information solely based on a
+ * provider's `/refresh` endpoint.
+ */
+export class ProxiedSignInIdentity implements IdentityApi {
+ private readonly options: ProxiedSignInIdentityOptions;
+ private readonly abortController: AbortController;
+ private state: State;
+
+ constructor(options: ProxiedSignInIdentityOptions) {
+ this.options = options;
+ this.abortController = new AbortController();
+ this.state = { type: 'empty' };
+ }
+
+ async start() {
+ // Try to make a first fetch, bubble up any errors to the caller
+ await this.getSessionAsync();
+ }
+
+ /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getUserId} */
+ getUserId(): string {
+ const { backstageIdentity } = this.getSessionSync();
+ const ref = backstageIdentity.identity.userEntityRef;
+ const match = /^([^:/]+:)?([^:/]+\/)?([^:/]+)$/.exec(ref);
+ if (!match) {
+ throw new TypeError(`Invalid user entity reference "${ref}"`);
+ }
+
+ return match[3];
+ }
+
+ /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getIdToken} */
+ async getIdToken(): Promise {
+ const session = await this.getSessionAsync();
+ return session.backstageIdentity.token;
+ }
+
+ /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getProfile} */
+ getProfile(): ProfileInfo {
+ const session = this.getSessionSync();
+ return session.profile;
+ }
+
+ /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getProfileInfo} */
+ async getProfileInfo(): Promise {
+ const session = await this.getSessionAsync();
+ return session.profile;
+ }
+
+ /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getBackstageIdentity} */
+ async getBackstageIdentity(): Promise {
+ const session = await this.getSessionAsync();
+ return session.backstageIdentity.identity;
+ }
+
+ /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getCredentials} */
+ async getCredentials(): Promise<{ token?: string | undefined }> {
+ const session = await this.getSessionAsync();
+ return {
+ token: session.backstageIdentity.token,
+ };
+ }
+
+ /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.signOut} */
+ async signOut(): Promise {
+ this.abortController.abort();
+ }
+
+ getSessionSync(): ProxiedSession {
+ if (this.state.type === 'active') {
+ return this.state.session;
+ } else if (this.state.type === 'fetching' && this.state.previous) {
+ return this.state.previous;
+ }
+ throw new Error('No session available. Try reloading your browser page.');
+ }
+
+ async getSessionAsync(): Promise {
+ if (this.state.type === 'fetching') {
+ return this.state.promise;
+ } else if (
+ this.state.type === 'active' &&
+ new Date() < this.state.expiresAt
+ ) {
+ return this.state.session;
+ }
+
+ const previous =
+ this.state.type === 'active' ? this.state.session : undefined;
+
+ const promise = this.fetchSession().then(
+ session => {
+ this.state = {
+ type: 'active',
+ session,
+ expiresAt: tokenToExpiry(session.backstageIdentity.token),
+ };
+ return session;
+ },
+ error => {
+ this.state = {
+ type: 'failed',
+ error,
+ };
+ throw error;
+ },
+ );
+
+ this.state = {
+ type: 'fetching',
+ promise,
+ previous,
+ };
+
+ return promise;
+ }
+
+ async fetchSession(): Promise {
+ const baseUrl = await this.options.discoveryApi.getBaseUrl('auth');
+
+ // Note that we do not use the fetchApi here, since this all happens before
+ // sign-in completes so there can be no automatic token injection and
+ // similar.
+ const response = await fetch(
+ `${baseUrl}/${this.options.provider}/refresh`,
+ {
+ signal: this.abortController.signal,
+ headers: { 'x-requested-with': 'XMLHttpRequest' },
+ credentials: 'include',
+ },
+ );
+
+ if (!response.ok) {
+ throw await ResponseError.fromResponse(response);
+ }
+
+ return proxiedSessionSchema.parse(await response.json());
+ }
+}
diff --git a/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInPage.tsx b/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInPage.tsx
new file mode 100644
index 0000000000..adcd6ced8f
--- /dev/null
+++ b/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInPage.tsx
@@ -0,0 +1,82 @@
+/*
+ * 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 {
+ discoveryApiRef,
+ SignInPageProps,
+ useApi,
+} from '@backstage/core-plugin-api';
+import React from 'react';
+import useAsync from 'react-use/lib/useAsync';
+import { ErrorPanel } from '../../components/ErrorPanel';
+import { Progress } from '../../components/Progress';
+import { ProxiedSignInIdentity } from './ProxiedSignInIdentity';
+
+/**
+ * Props for {@link ProxiedSignInPage}.
+ *
+ * @public
+ */
+export type ProxiedSignInPageProps = SignInPageProps & {
+ /**
+ * The provider to use, e.g. "gcp-iap" or "aws-alb". This must correspond to
+ * a properly configured auth provider ID in the auth backend.
+ */
+ provider: string;
+};
+
+/**
+ * A sign-in page that has no user interface of its own. Instead, it relies on
+ * sign-in being performed by a reverse authenticating proxy that Backstage is
+ * deployed behind, and leverages its session handling.
+ *
+ * @remarks
+ *
+ * This sign-in page is useful when you are using products such as Google
+ * Identity-Aware Proxy or AWS Application Load Balancer or similar, to front
+ * your Backstage installation. This sign-in page implementation will silently
+ * and regularly punch through the proxy to the auth backend to refresh your
+ * frontend session information, without requiring user interaction.
+ *
+ * @public
+ */
+export const ProxiedSignInPage = (props: ProxiedSignInPageProps) => {
+ const discoveryApi = useApi(discoveryApiRef);
+
+ const { loading, error } = useAsync(async () => {
+ const identity = new ProxiedSignInIdentity({
+ provider: props.provider,
+ discoveryApi,
+ });
+
+ await identity.start();
+
+ props.onSignInSuccess(identity);
+ }, []);
+
+ if (loading) {
+ return ;
+ } else if (error) {
+ return (
+
+ );
+ }
+
+ return null;
+};
diff --git a/packages/core-components/src/layout/ProxiedSignInPage/index.ts b/packages/core-components/src/layout/ProxiedSignInPage/index.ts
new file mode 100644
index 0000000000..f7bab5f46c
--- /dev/null
+++ b/packages/core-components/src/layout/ProxiedSignInPage/index.ts
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2021 The Backstage Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export { ProxiedSignInPage } from './ProxiedSignInPage';
+export type { ProxiedSignInPageProps } from './ProxiedSignInPage';
diff --git a/packages/core-components/src/layout/ProxiedSignInPage/types.test.ts b/packages/core-components/src/layout/ProxiedSignInPage/types.test.ts
new file mode 100644
index 0000000000..178714ecf9
--- /dev/null
+++ b/packages/core-components/src/layout/ProxiedSignInPage/types.test.ts
@@ -0,0 +1,45 @@
+/*
+ * 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 { TypeOf } from 'zod';
+import { ProxiedSession, proxiedSessionSchema } from './types';
+
+describe('types', () => {
+ const responseData: ProxiedSession = {
+ providerInfo: {
+ stuff: 1,
+ },
+ profile: {
+ email: 'e',
+ displayName: 'd',
+ picture: 'p',
+ },
+ backstageIdentity: {
+ token: 't',
+ identity: {
+ type: 'user',
+ userEntityRef: 'k:ns/ue',
+ ownershipEntityRefs: ['k:ns/oe'],
+ },
+ },
+ };
+
+ it('has a compatible schema type', () => {
+ function f(_b: TypeOf) {}
+ f(responseData); // no tsc errors
+ expect(proxiedSessionSchema.parse(responseData)).toEqual(responseData);
+ });
+});
diff --git a/packages/core-components/src/layout/ProxiedSignInPage/types.ts b/packages/core-components/src/layout/ProxiedSignInPage/types.ts
new file mode 100644
index 0000000000..dd4230cd8b
--- /dev/null
+++ b/packages/core-components/src/layout/ProxiedSignInPage/types.ts
@@ -0,0 +1,50 @@
+/*
+ * 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 {
+ BackstageIdentityResponse,
+ ProfileInfo,
+} from '@backstage/core-plugin-api';
+import { z } from 'zod';
+
+export const proxiedSessionSchema = z.object({
+ providerInfo: z.object({}).catchall(z.unknown()).optional(),
+ profile: z.object({
+ email: z.string().optional(),
+ displayName: z.string().optional(),
+ picture: z.string().optional(),
+ }),
+ backstageIdentity: z.object({
+ token: z.string(),
+ identity: z.object({
+ type: z.literal('user'),
+ userEntityRef: z.string(),
+ ownershipEntityRefs: z.array(z.string()),
+ }),
+ }),
+});
+
+/**
+ * Generic session information for proxied sign-in providers, e.g. common
+ * reverse authenticating proxy implementations.
+ *
+ * @public
+ */
+export type ProxiedSession = {
+ providerInfo?: { [key: string]: unknown };
+ profile: ProfileInfo;
+ backstageIdentity: Omit;
+};
diff --git a/packages/core-components/src/layout/index.ts b/packages/core-components/src/layout/index.ts
index 19cd6dfb78..9bb7fbaa26 100644
--- a/packages/core-components/src/layout/index.ts
+++ b/packages/core-components/src/layout/index.ts
@@ -26,6 +26,7 @@ export * from './HomepageTimer';
export * from './InfoCard';
export * from './ItemCard';
export * from './Page';
+export * from './ProxiedSignInPage';
export * from './Sidebar';
export * from './SignInPage';
export * from './TabbedCard';
diff --git a/packages/core-components/src/setupTests.ts b/packages/core-components/src/setupTests.ts
index 963c0f188b..c1d649f2ad 100644
--- a/packages/core-components/src/setupTests.ts
+++ b/packages/core-components/src/setupTests.ts
@@ -15,3 +15,4 @@
*/
import '@testing-library/jest-dom';
+import 'cross-fetch/polyfill';
diff --git a/packages/core-plugin-api/CHANGELOG.md b/packages/core-plugin-api/CHANGELOG.md
index 535be6aef6..7f081e8b45 100644
--- a/packages/core-plugin-api/CHANGELOG.md
+++ b/packages/core-plugin-api/CHANGELOG.md
@@ -1,5 +1,20 @@
# @backstage/core-plugin-api
+## 0.5.0
+
+### Minor Changes
+
+- 784d8078ab: Removed the deprecated `OldIconComponent` type.
+- e2eb92c109: Removed previously deprecated exports: `PluginHooks`, `PluginOutput`, and `FeatureFlagOutput`.
+
+ The deprecated `register` method of `PluginConfig` has been removed, as well as the deprecated `output` method of `BackstagePlugin`.
+
+### Patch Changes
+
+- 784d8078ab: Removed direct and transitive MUI dependencies.
+- Updated dependencies
+ - @backstage/config@0.1.12
+
## 0.4.1
### Patch Changes
diff --git a/packages/core-plugin-api/package.json b/packages/core-plugin-api/package.json
index d284d60c6b..55ac56083b 100644
--- a/packages/core-plugin-api/package.json
+++ b/packages/core-plugin-api/package.json
@@ -1,7 +1,7 @@
{
"name": "@backstage/core-plugin-api",
"description": "Core API used by Backstage plugins",
- "version": "0.4.1",
+ "version": "0.5.0",
"private": false,
"publishConfig": {
"access": "public",
@@ -29,7 +29,7 @@
"clean": "backstage-cli clean"
},
"dependencies": {
- "@backstage/config": "^0.1.11",
+ "@backstage/config": "^0.1.12",
"@backstage/types": "^0.1.1",
"@backstage/version-bridge": "^0.1.1",
"history": "^5.0.0",
@@ -43,9 +43,9 @@
"react": "^16.13.1 || ^17.0.0"
},
"devDependencies": {
- "@backstage/cli": "^0.10.5",
- "@backstage/core-app-api": "^0.3.1",
- "@backstage/test-utils": "^0.2.0",
+ "@backstage/cli": "^0.11.0",
+ "@backstage/core-app-api": "^0.4.0",
+ "@backstage/test-utils": "^0.2.2",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^11.2.5",
"@testing-library/react-hooks": "^7.0.2",
diff --git a/packages/create-app/CHANGELOG.md b/packages/create-app/CHANGELOG.md
index f72e76b9c0..8d19c65e54 100644
--- a/packages/create-app/CHANGELOG.md
+++ b/packages/create-app/CHANGELOG.md
@@ -1,5 +1,67 @@
# @backstage/create-app
+## 0.4.12
+
+### Patch Changes
+
+- 5333451def: Cleaned up API exports
+- cd529c4094: Add permissions to create-app's PluginEnvironment
+
+ `CatalogEnvironment` now has a `permissions` field, which means that a permission client must now be provided as part of `PluginEnvironment`. To apply these changes to an existing app, add the following to the `makeCreateEnv` function in `packages/backend/src/index.ts`:
+
+ ```diff
+ // packages/backend/src/index.ts
+
+ + import { ServerPermissionClient } from '@backstage/plugin-permission-node';
+
+ function makeCreateEnv(config: Config) {
+ ...
+ + const permissions = ServerPerimssionClient.fromConfig(config, {
+ + discovery,
+ + tokenManager,
+ + });
+
+ root.info(`Created UrlReader ${reader}`);
+
+ return (plugin: string): PluginEnvironment => {
+ ...
+ return {
+ logger,
+ cache,
+ database,
+ config,
+ reader,
+ discovery,
+ tokenManager,
+ scheduler,
+ + permissions,
+ };
+ }
+ }
+ ```
+
+ And add a permissions field to the `PluginEnvironment` type in `packages/backend/src/types.ts`:
+
+ ```diff
+ // packages/backend/src/types.ts
+
+ + import { PermissionAuthorizer } from '@backstage/plugin-permission-common';
+
+ export type PluginEnvironment = {
+ ...
+ + permissions: PermissionAuthorizer;
+ };
+ ```
+
+ [`@backstage/plugin-permission-common`](https://www.npmjs.com/package/@backstage/plugin-permission-common) and [`@backstage/plugin-permission-node`](https://www.npmjs.com/package/@backstage/plugin-permission-node) will need to be installed as dependencies:
+
+ ```diff
+ // packages/backend/package.json
+
+ + "@backstage/plugin-permission-common": "...",
+ + "@backstage/plugin-permission-node": "...",
+ ```
+
## 0.4.11
## 0.4.10
diff --git a/packages/create-app/package.json b/packages/create-app/package.json
index 639e0370d7..041616f90a 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.11",
+ "version": "0.4.12",
"private": false,
"publishConfig": {
"access": "public"
diff --git a/packages/dev-utils/CHANGELOG.md b/packages/dev-utils/CHANGELOG.md
index c08bbc61fd..7e17d1a2cf 100644
--- a/packages/dev-utils/CHANGELOG.md
+++ b/packages/dev-utils/CHANGELOG.md
@@ -1,5 +1,19 @@
# @backstage/dev-utils
+## 0.2.17
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/test-utils@0.2.2
+ - @backstage/core-components@0.8.4
+ - @backstage/core-plugin-api@0.5.0
+ - @backstage/plugin-catalog-react@0.6.11
+ - @backstage/core-app-api@0.4.0
+ - @backstage/app-defaults@0.1.4
+ - @backstage/catalog-model@0.9.9
+ - @backstage/integration-react@0.1.18
+
## 0.2.16
### Patch Changes
diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json
index 75b34baf32..afd405cbbd 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": "0.2.16",
+ "version": "0.2.17",
"private": false,
"publishConfig": {
"access": "public",
@@ -29,14 +29,14 @@
"clean": "backstage-cli clean"
},
"dependencies": {
- "@backstage/app-defaults": "^0.1.3",
- "@backstage/core-app-api": "^0.3.1",
- "@backstage/core-components": "^0.8.3",
- "@backstage/core-plugin-api": "^0.4.1",
- "@backstage/catalog-model": "^0.9.7",
- "@backstage/integration-react": "^0.1.16",
- "@backstage/plugin-catalog-react": "^0.6.10",
- "@backstage/test-utils": "^0.2.0",
+ "@backstage/app-defaults": "^0.1.4",
+ "@backstage/core-app-api": "^0.4.0",
+ "@backstage/core-components": "^0.8.4",
+ "@backstage/core-plugin-api": "^0.5.0",
+ "@backstage/catalog-model": "^0.9.9",
+ "@backstage/integration-react": "^0.1.18",
+ "@backstage/plugin-catalog-react": "^0.6.11",
+ "@backstage/test-utils": "^0.2.2",
"@backstage/theme": "^0.2.14",
"@material-ui/core": "^4.12.2",
"@material-ui/icons": "^4.9.1",
@@ -55,7 +55,7 @@
"react-dom": "^16.13.1 || ^17.0.0"
},
"devDependencies": {
- "@backstage/cli": "^0.10.5",
+ "@backstage/cli": "^0.11.0",
"@types/jest": "^26.0.7",
"@types/node": "^14.14.32"
},
diff --git a/packages/e2e-test/package.json b/packages/e2e-test/package.json
index 6c941cda58..56f0865db2 100644
--- a/packages/e2e-test/package.json
+++ b/packages/e2e-test/package.json
@@ -25,7 +25,7 @@
},
"devDependencies": {
"@backstage/cli-common": "^0.1.1",
- "@backstage/errors": "^0.1.4",
+ "@backstage/errors": "^0.2.0",
"@types/fs-extra": "^9.0.1",
"@types/node": "^14.14.32",
"@types/puppeteer": "^5.4.4",
diff --git a/packages/embedded-techdocs-app/CHANGELOG.md b/packages/embedded-techdocs-app/CHANGELOG.md
index aa0e9ce955..29774b165f 100644
--- a/packages/embedded-techdocs-app/CHANGELOG.md
+++ b/packages/embedded-techdocs-app/CHANGELOG.md
@@ -1,5 +1,22 @@
# embedded-techdocs-app
+## 0.2.59
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/test-utils@0.2.2
+ - @backstage/config@0.1.12
+ - @backstage/core-components@0.8.4
+ - @backstage/cli@0.11.0
+ - @backstage/core-plugin-api@0.5.0
+ - @backstage/plugin-techdocs@0.12.14
+ - @backstage/core-app-api@0.4.0
+ - @backstage/app-defaults@0.1.4
+ - @backstage/catalog-model@0.9.9
+ - @backstage/integration-react@0.1.18
+ - @backstage/plugin-catalog@0.7.8
+
## 0.2.58
### Patch Changes
diff --git a/packages/embedded-techdocs-app/package.json b/packages/embedded-techdocs-app/package.json
index a1ffd9f858..a830336879 100644
--- a/packages/embedded-techdocs-app/package.json
+++ b/packages/embedded-techdocs-app/package.json
@@ -1,20 +1,20 @@
{
"name": "embedded-techdocs-app",
- "version": "0.2.58",
+ "version": "0.2.59",
"private": true,
"bundled": true,
"dependencies": {
- "@backstage/app-defaults": "^0.1.3",
- "@backstage/catalog-model": "^0.9.7",
- "@backstage/cli": "^0.10.3",
- "@backstage/config": "^0.1.10",
- "@backstage/core-app-api": "^0.3.0",
- "@backstage/core-components": "^0.8.2",
- "@backstage/core-plugin-api": "^0.4.0",
- "@backstage/integration-react": "^0.1.16",
- "@backstage/plugin-catalog": "^0.7.5",
- "@backstage/plugin-techdocs": "^0.12.11",
- "@backstage/test-utils": "^0.2.0",
+ "@backstage/app-defaults": "^0.1.4",
+ "@backstage/catalog-model": "^0.9.9",
+ "@backstage/cli": "^0.11.0",
+ "@backstage/config": "^0.1.12",
+ "@backstage/core-app-api": "^0.4.0",
+ "@backstage/core-components": "^0.8.4",
+ "@backstage/core-plugin-api": "^0.5.0",
+ "@backstage/integration-react": "^0.1.18",
+ "@backstage/plugin-catalog": "^0.7.8",
+ "@backstage/plugin-techdocs": "^0.12.14",
+ "@backstage/test-utils": "^0.2.2",
"@backstage/theme": "^0.2.14",
"@material-ui/core": "^4.11.0",
"@material-ui/icons": "^4.9.1",
@@ -26,7 +26,7 @@
"react-use": "^17.2.4"
},
"devDependencies": {
- "@backstage/cli": "^0.10.3",
+ "@backstage/cli": "^0.11.0",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^11.2.5",
"@testing-library/user-event": "^13.1.8",
diff --git a/packages/errors/CHANGELOG.md b/packages/errors/CHANGELOG.md
index 02b28cdf1d..110863d347 100644
--- a/packages/errors/CHANGELOG.md
+++ b/packages/errors/CHANGELOG.md
@@ -1,5 +1,13 @@
# @backstage/errors
+## 0.2.0
+
+### Minor Changes
+
+- e2eb92c109: Removed the deprecated exports `ErrorResponse` and `parseErrorResponse`.
+
+ Removed the deprecated `constructor` and the deprecated `data` property of `ResponseError`.
+
## 0.1.5
### Patch Changes
diff --git a/packages/errors/package.json b/packages/errors/package.json
index d0d59ffd6a..d9ab7e1e6c 100644
--- a/packages/errors/package.json
+++ b/packages/errors/package.json
@@ -1,7 +1,7 @@
{
"name": "@backstage/errors",
"description": "Common utilities for error handling within Backstage",
- "version": "0.1.5",
+ "version": "0.2.0",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -35,7 +35,7 @@
"serialize-error": "^8.0.1"
},
"devDependencies": {
- "@backstage/cli": "^0.10.0",
+ "@backstage/cli": "^0.11.0",
"@types/jest": "^26.0.7"
},
"files": [
diff --git a/packages/integration-react/CHANGELOG.md b/packages/integration-react/CHANGELOG.md
index 121b778143..fb5445c2d9 100644
--- a/packages/integration-react/CHANGELOG.md
+++ b/packages/integration-react/CHANGELOG.md
@@ -1,5 +1,15 @@
# @backstage/integration-react
+## 0.1.18
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/config@0.1.12
+ - @backstage/integration@0.7.1
+ - @backstage/core-components@0.8.4
+ - @backstage/core-plugin-api@0.5.0
+
## 0.1.17
### Patch Changes
diff --git a/packages/integration-react/package.json b/packages/integration-react/package.json
index 62f9e8d593..b1bc8e4eb3 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": "0.1.17",
+ "version": "0.1.18",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -21,10 +21,10 @@
"clean": "backstage-cli clean"
},
"dependencies": {
- "@backstage/config": "^0.1.11",
- "@backstage/core-components": "^0.8.2",
- "@backstage/core-plugin-api": "^0.4.0",
- "@backstage/integration": "^0.7.0",
+ "@backstage/config": "^0.1.12",
+ "@backstage/core-components": "^0.8.4",
+ "@backstage/core-plugin-api": "^0.5.0",
+ "@backstage/integration": "^0.7.1",
"@backstage/theme": "^0.2.14",
"@material-ui/core": "^4.12.2",
"@material-ui/icons": "^4.9.1",
@@ -35,9 +35,9 @@
"react": "^16.13.1 || ^17.0.0"
},
"devDependencies": {
- "@backstage/cli": "^0.10.4",
- "@backstage/dev-utils": "^0.2.15",
- "@backstage/test-utils": "^0.2.1",
+ "@backstage/cli": "^0.11.0",
+ "@backstage/dev-utils": "^0.2.17",
+ "@backstage/test-utils": "^0.2.2",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^11.2.5",
"@testing-library/user-event": "^13.1.8",
diff --git a/packages/integration/CHANGELOG.md b/packages/integration/CHANGELOG.md
index 359d2dd11e..e2d535ada1 100644
--- a/packages/integration/CHANGELOG.md
+++ b/packages/integration/CHANGELOG.md
@@ -1,5 +1,14 @@
# @backstage/integration
+## 0.7.1
+
+### Patch Changes
+
+- 3b4d8caff6: Adds a new GitHub credentials provider (DefaultGithubCredentialsProvider). It handles multiple app configurations. It looks up the app configuration based on the url.
+- 5333451def: Cleaned up API exports
+- Updated dependencies
+ - @backstage/config@0.1.12
+
## 0.7.0
### Minor Changes
diff --git a/packages/integration/package.json b/packages/integration/package.json
index ae674d2cf1..336ed1535f 100644
--- a/packages/integration/package.json
+++ b/packages/integration/package.json
@@ -1,7 +1,7 @@
{
"name": "@backstage/integration",
"description": "Helpers for managing integrations towards external systems",
- "version": "0.7.0",
+ "version": "0.7.1",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -30,7 +30,7 @@
"clean": "backstage-cli clean"
},
"dependencies": {
- "@backstage/config": "^0.1.11",
+ "@backstage/config": "^0.1.12",
"cross-fetch": "^3.0.6",
"git-url-parse": "^11.6.0",
"@octokit/rest": "^18.5.3",
@@ -39,9 +39,9 @@
"lodash": "^4.17.21"
},
"devDependencies": {
- "@backstage/cli": "^0.10.4",
- "@backstage/config-loader": "^0.9.1",
- "@backstage/test-utils": "^0.2.1",
+ "@backstage/cli": "^0.11.0",
+ "@backstage/config-loader": "^0.9.2",
+ "@backstage/test-utils": "^0.2.2",
"@types/jest": "^26.0.7",
"@types/luxon": "^2.0.4",
"msw": "^0.35.0"
diff --git a/packages/search-common/package.json b/packages/search-common/package.json
index 51cea5a28e..87660e7ee3 100644
--- a/packages/search-common/package.json
+++ b/packages/search-common/package.json
@@ -39,7 +39,7 @@
"@backstage/types": "^0.1.1"
},
"devDependencies": {
- "@backstage/cli": "^0.10.0"
+ "@backstage/cli": "^0.11.0"
},
"jest": {
"roots": [
diff --git a/packages/storybook/CHANGELOG.md b/packages/storybook/CHANGELOG.md
index f5e44f780c..c1e756bb12 100644
--- a/packages/storybook/CHANGELOG.md
+++ b/packages/storybook/CHANGELOG.md
@@ -1,5 +1,14 @@
# storybook
+## 0.2.1
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/test-utils@0.2.2
+ - @backstage/core-plugin-api@0.5.0
+ - @backstage/core-app-api@0.4.0
+
## 0.2.0
### Patch Changes
diff --git a/packages/storybook/package.json b/packages/storybook/package.json
index a0e9b25d76..5c4b440264 100644
--- a/packages/storybook/package.json
+++ b/packages/storybook/package.json
@@ -1,6 +1,6 @@
{
"name": "storybook",
- "version": "0.2.0",
+ "version": "0.2.1",
"description": "Storybook build for components package",
"private": true,
"scripts": {
@@ -9,9 +9,9 @@
},
"dependencies": {
"@backstage/theme": "^0.2.0",
- "@backstage/test-utils": "^0.2.1",
- "@backstage/core-app-api": "^0.3.1",
- "@backstage/core-plugin-api": "^0.4.1",
+ "@backstage/test-utils": "^0.2.2",
+ "@backstage/core-app-api": "^0.4.0",
+ "@backstage/core-plugin-api": "^0.5.0",
"react": "^16.13.1",
"react-dom": "^16.13.1"
},
diff --git a/packages/techdocs-cli/package.json b/packages/techdocs-cli/package.json
index b4c4ade6a3..c971a4d1df 100644
--- a/packages/techdocs-cli/package.json
+++ b/packages/techdocs-cli/package.json
@@ -32,7 +32,7 @@
"techdocs-cli": "bin/techdocs-cli"
},
"devDependencies": {
- "@backstage/cli": "^0.10.4",
+ "@backstage/cli": "^0.11.0",
"@types/commander": "^2.12.2",
"@types/fs-extra": "^9.0.6",
"@types/http-proxy": "^1.17.4",
@@ -41,7 +41,7 @@
"@types/react-dev-utils": "^9.0.4",
"@types/serve-handler": "^6.1.0",
"@types/webpack-env": "^1.15.3",
- "embedded-techdocs-app": "0.2.58",
+ "embedded-techdocs-app": "0.2.59",
"find-process": "^1.4.5",
"nodemon": "^2.0.2",
"ts-node": "^10.0.0"
@@ -56,10 +56,10 @@
"ext": "ts"
},
"dependencies": {
- "@backstage/backend-common": "^0.10.1",
- "@backstage/catalog-model": "^0.9.7",
- "@backstage/config": "^0.1.10",
- "@backstage/techdocs-common": "^0.11.2",
+ "@backstage/backend-common": "^0.10.3",
+ "@backstage/catalog-model": "^0.9.9",
+ "@backstage/config": "^0.1.12",
+ "@backstage/techdocs-common": "^0.11.3",
"@types/dockerode": "^3.3.0",
"commander": "^6.1.0",
"dockerode": "^3.3.1",
diff --git a/packages/techdocs-common/CHANGELOG.md b/packages/techdocs-common/CHANGELOG.md
index 96281958b6..5a9c2f79e8 100644
--- a/packages/techdocs-common/CHANGELOG.md
+++ b/packages/techdocs-common/CHANGELOG.md
@@ -1,5 +1,17 @@
# @backstage/techdocs-common
+## 0.11.3
+
+### Patch Changes
+
+- 5333451def: Cleaned up API exports
+- Updated dependencies
+ - @backstage/config@0.1.12
+ - @backstage/integration@0.7.1
+ - @backstage/backend-common@0.10.3
+ - @backstage/errors@0.2.0
+ - @backstage/catalog-model@0.9.9
+
## 0.11.2
### Patch Changes
diff --git a/packages/techdocs-common/package.json b/packages/techdocs-common/package.json
index f3e0f2d0d4..0b9ae3a831 100644
--- a/packages/techdocs-common/package.json
+++ b/packages/techdocs-common/package.json
@@ -1,7 +1,7 @@
{
"name": "@backstage/techdocs-common",
"description": "Common functionalities for TechDocs, to be shared between techdocs-backend plugin and techdocs-cli",
- "version": "0.11.2",
+ "version": "0.11.3",
"main": "src/index.ts",
"types": "src/index.ts",
"private": false,
@@ -38,12 +38,12 @@
"dependencies": {
"@azure/identity": "^2.0.1",
"@azure/storage-blob": "^12.5.0",
- "@backstage/backend-common": "^0.10.1",
- "@backstage/catalog-model": "^0.9.7",
- "@backstage/config": "^0.1.11",
- "@backstage/errors": "^0.1.5",
+ "@backstage/backend-common": "^0.10.3",
+ "@backstage/catalog-model": "^0.9.9",
+ "@backstage/config": "^0.1.12",
+ "@backstage/errors": "^0.2.0",
"@backstage/search-common": "^0.2.1",
- "@backstage/integration": "^0.7.0",
+ "@backstage/integration": "^0.7.1",
"@google-cloud/storage": "^5.6.0",
"@trendyol-js/openstack-swift-sdk": "^0.0.5",
"@types/express": "^4.17.6",
@@ -60,7 +60,7 @@
"winston": "^3.2.1"
},
"devDependencies": {
- "@backstage/cli": "^0.10.4",
+ "@backstage/cli": "^0.11.0",
"@types/fs-extra": "^9.0.5",
"@types/js-yaml": "^4.0.0",
"@types/mime-types": "^2.1.0",
diff --git a/packages/test-utils/CHANGELOG.md b/packages/test-utils/CHANGELOG.md
index fa747f84d1..bdd7562652 100644
--- a/packages/test-utils/CHANGELOG.md
+++ b/packages/test-utils/CHANGELOG.md
@@ -1,5 +1,15 @@
# @backstage/test-utils
+## 0.2.2
+
+### Patch Changes
+
+- 2d3fd91e33: Add new `MockConfigApi` as a more discoverable and leaner method for mocking configuration.
+- Updated dependencies
+ - @backstage/config@0.1.12
+ - @backstage/core-plugin-api@0.5.0
+ - @backstage/core-app-api@0.4.0
+
## 0.2.1
### Patch Changes
diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json
index 48745f7068..d1382ada4a 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": "0.2.1",
+ "version": "0.2.2",
"private": false,
"publishConfig": {
"access": "public",
@@ -29,9 +29,9 @@
"clean": "backstage-cli clean"
},
"dependencies": {
- "@backstage/config": "^0.1.11",
- "@backstage/core-app-api": "^0.3.0",
- "@backstage/core-plugin-api": "^0.4.0",
+ "@backstage/config": "^0.1.12",
+ "@backstage/core-app-api": "^0.4.0",
+ "@backstage/core-plugin-api": "^0.5.0",
"@backstage/theme": "^0.2.14",
"@backstage/types": "^0.1.1",
"@material-ui/core": "^4.12.2",
@@ -48,7 +48,7 @@
"react": "^16.13.1 || ^17.0.0"
},
"devDependencies": {
- "@backstage/cli": "^0.10.4",
+ "@backstage/cli": "^0.11.0",
"@types/jest": "^26.0.7",
"@types/node": "^14.14.32"
},
diff --git a/packages/theme/package.json b/packages/theme/package.json
index 08477dccd0..33ec467940 100644
--- a/packages/theme/package.json
+++ b/packages/theme/package.json
@@ -31,7 +31,7 @@
"@material-ui/core": "^4.12.2"
},
"devDependencies": {
- "@backstage/cli": "^0.10.0"
+ "@backstage/cli": "^0.11.0"
},
"files": [
"dist"
diff --git a/packages/types/package.json b/packages/types/package.json
index 822b2d678e..fc17471869 100644
--- a/packages/types/package.json
+++ b/packages/types/package.json
@@ -31,7 +31,7 @@
},
"dependencies": {},
"devDependencies": {
- "@backstage/cli": "^0.10.0",
+ "@backstage/cli": "^0.11.0",
"@types/zen-observable": "^0.8.0",
"zen-observable": "^0.8.15"
},
diff --git a/packages/version-bridge/package.json b/packages/version-bridge/package.json
index 0291cdc208..8164aacfae 100644
--- a/packages/version-bridge/package.json
+++ b/packages/version-bridge/package.json
@@ -33,7 +33,7 @@
"react": "^16.13.1 || ^17.0.0"
},
"devDependencies": {
- "@backstage/cli": "^0.10.1",
+ "@backstage/cli": "^0.11.0",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^11.2.5",
"@testing-library/react-hooks": "^7.0.2"
diff --git a/plugins/airbrake/CHANGELOG.md b/plugins/airbrake/CHANGELOG.md
new file mode 100644
index 0000000000..42c2b4603d
--- /dev/null
+++ b/plugins/airbrake/CHANGELOG.md
@@ -0,0 +1,13 @@
+# @backstage/plugin-airbrake
+
+## 0.1.0
+
+### Minor Changes
+
+- 04c86e5a10: A plugin for Airbrake (https://airbrake.io/) has been created
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/core-components@0.8.4
+ - @backstage/core-plugin-api@0.5.0
diff --git a/plugins/airbrake/package.json b/plugins/airbrake/package.json
index 7294c97413..d343876fb5 100644
--- a/plugins/airbrake/package.json
+++ b/plugins/airbrake/package.json
@@ -1,6 +1,6 @@
{
"name": "@backstage/plugin-airbrake",
- "version": "0.0.0",
+ "version": "0.1.0",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -20,8 +20,8 @@
"clean": "backstage-cli clean"
},
"dependencies": {
- "@backstage/core-components": "^0.8.3",
- "@backstage/core-plugin-api": "^0.4.1",
+ "@backstage/core-components": "^0.8.4",
+ "@backstage/core-plugin-api": "^0.5.0",
"@backstage/theme": "^0.2.14",
"@material-ui/core": "^4.12.2",
"@material-ui/icons": "^4.9.1",
@@ -34,11 +34,11 @@
},
"devDependencies": {
"@types/object-hash": "^2.2.1",
- "@backstage/app-defaults": "^0.1.2",
- "@backstage/cli": "^0.10.5",
- "@backstage/core-app-api": "^0.3.1",
- "@backstage/dev-utils": "^0.2.16",
- "@backstage/test-utils": "^0.2.1",
+ "@backstage/app-defaults": "^0.1.4",
+ "@backstage/cli": "^0.11.0",
+ "@backstage/core-app-api": "^0.4.0",
+ "@backstage/dev-utils": "^0.2.17",
+ "@backstage/test-utils": "^0.2.2",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^11.2.5",
"@testing-library/user-event": "^13.1.8",
diff --git a/plugins/allure/CHANGELOG.md b/plugins/allure/CHANGELOG.md
index 4f3771d348..1802258402 100644
--- a/plugins/allure/CHANGELOG.md
+++ b/plugins/allure/CHANGELOG.md
@@ -1,5 +1,15 @@
# @backstage/plugin-allure
+## 0.1.11
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/core-components@0.8.4
+ - @backstage/core-plugin-api@0.5.0
+ - @backstage/plugin-catalog-react@0.6.11
+ - @backstage/catalog-model@0.9.9
+
## 0.1.10
### Patch Changes
diff --git a/plugins/allure/package.json b/plugins/allure/package.json
index 54ac6ea659..79b381c319 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.10",
+ "version": "0.1.11",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -22,10 +22,10 @@
"clean": "backstage-cli clean"
},
"dependencies": {
- "@backstage/catalog-model": "^0.9.7",
- "@backstage/core-components": "^0.8.3",
- "@backstage/core-plugin-api": "^0.4.1",
- "@backstage/plugin-catalog-react": "^0.6.10",
+ "@backstage/catalog-model": "^0.9.9",
+ "@backstage/core-components": "^0.8.4",
+ "@backstage/core-plugin-api": "^0.5.0",
+ "@backstage/plugin-catalog-react": "^0.6.11",
"@backstage/theme": "^0.2.14",
"@material-ui/core": "^4.12.2",
"@material-ui/icons": "^4.9.1",
@@ -37,10 +37,10 @@
"react": "^16.13.1 || ^17.0.0"
},
"devDependencies": {
- "@backstage/cli": "^0.10.5",
- "@backstage/core-app-api": "^0.3.1",
- "@backstage/dev-utils": "^0.2.16",
- "@backstage/test-utils": "^0.2.1",
+ "@backstage/cli": "^0.11.0",
+ "@backstage/core-app-api": "^0.4.0",
+ "@backstage/dev-utils": "^0.2.17",
+ "@backstage/test-utils": "^0.2.2",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^11.2.5",
"@testing-library/user-event": "^13.1.8",
diff --git a/plugins/analytics-module-ga/CHANGELOG.md b/plugins/analytics-module-ga/CHANGELOG.md
index 3721035996..75dd925060 100644
--- a/plugins/analytics-module-ga/CHANGELOG.md
+++ b/plugins/analytics-module-ga/CHANGELOG.md
@@ -1,5 +1,14 @@
# @backstage/plugin-analytics-module-ga
+## 0.1.6
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/config@0.1.12
+ - @backstage/core-components@0.8.4
+ - @backstage/core-plugin-api@0.5.0
+
## 0.1.5
### Patch Changes
diff --git a/plugins/analytics-module-ga/package.json b/plugins/analytics-module-ga/package.json
index a17f915b16..ad4b322a7c 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.5",
+ "version": "0.1.6",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -21,9 +21,9 @@
"clean": "backstage-cli clean"
},
"dependencies": {
- "@backstage/config": "^0.1.5",
- "@backstage/core-components": "^0.8.3",
- "@backstage/core-plugin-api": "^0.4.1",
+ "@backstage/config": "^0.1.12",
+ "@backstage/core-components": "^0.8.4",
+ "@backstage/core-plugin-api": "^0.5.0",
"@backstage/theme": "^0.2.14",
"@material-ui/core": "^4.12.2",
"@material-ui/icons": "^4.9.1",
@@ -35,10 +35,10 @@
"react": "^16.13.1 || ^17.0.0"
},
"devDependencies": {
- "@backstage/cli": "^0.10.5",
- "@backstage/core-app-api": "^0.3.1",
- "@backstage/dev-utils": "^0.2.16",
- "@backstage/test-utils": "^0.2.1",
+ "@backstage/cli": "^0.11.0",
+ "@backstage/core-app-api": "^0.4.0",
+ "@backstage/dev-utils": "^0.2.17",
+ "@backstage/test-utils": "^0.2.2",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^11.2.5",
"@testing-library/user-event": "^13.1.8",
diff --git a/plugins/apache-airflow/CHANGELOG.md b/plugins/apache-airflow/CHANGELOG.md
index bb8a010fda..2a2ff1a873 100644
--- a/plugins/apache-airflow/CHANGELOG.md
+++ b/plugins/apache-airflow/CHANGELOG.md
@@ -1,5 +1,14 @@
# @backstage/plugin-apache-airflow
+## 0.1.3
+
+### Patch Changes
+
+- 5333451def: Cleaned up API exports
+- Updated dependencies
+ - @backstage/core-components@0.8.4
+ - @backstage/core-plugin-api@0.5.0
+
## 0.1.2
### Patch Changes
diff --git a/plugins/apache-airflow/package.json b/plugins/apache-airflow/package.json
index d203c8de9e..c4cc9c3e23 100644
--- a/plugins/apache-airflow/package.json
+++ b/plugins/apache-airflow/package.json
@@ -1,6 +1,6 @@
{
"name": "@backstage/plugin-apache-airflow",
- "version": "0.1.2",
+ "version": "0.1.3",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -20,8 +20,8 @@
"clean": "backstage-cli clean"
},
"dependencies": {
- "@backstage/core-components": "^0.8.3",
- "@backstage/core-plugin-api": "^0.4.1",
+ "@backstage/core-components": "^0.8.4",
+ "@backstage/core-plugin-api": "^0.5.0",
"@material-ui/core": "^4.12.2",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "4.0.0-alpha.57",
@@ -33,10 +33,10 @@
"react": "^16.13.1 || ^17.0.0"
},
"devDependencies": {
- "@backstage/cli": "^0.10.5",
- "@backstage/core-app-api": "^0.3.1",
- "@backstage/dev-utils": "^0.2.16",
- "@backstage/test-utils": "^0.2.1",
+ "@backstage/cli": "^0.11.0",
+ "@backstage/core-app-api": "^0.4.0",
+ "@backstage/dev-utils": "^0.2.17",
+ "@backstage/test-utils": "^0.2.2",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^11.2.5",
"@testing-library/user-event": "^13.1.8",
diff --git a/plugins/api-docs/CHANGELOG.md b/plugins/api-docs/CHANGELOG.md
index 31611f5b2c..b7f4fbc29e 100644
--- a/plugins/api-docs/CHANGELOG.md
+++ b/plugins/api-docs/CHANGELOG.md
@@ -1,5 +1,25 @@
# @backstage/plugin-api-docs
+## 0.6.22
+
+### Patch Changes
+
+- faf844e269: Update @asyncapi/react-component to 1.0.0-next.26, which will fix the
+ `ResizeObserver loop limit exceeded` errors which we encountered in several E2E
+ tests.
+
+ For more details check the following links:
+
+ - https://github.com/backstage/backstage/pull/8088#issuecomment-991183968
+ - https://github.com/asyncapi/asyncapi-react/issues/498
+
+- Updated dependencies
+ - @backstage/core-components@0.8.4
+ - @backstage/core-plugin-api@0.5.0
+ - @backstage/plugin-catalog-react@0.6.11
+ - @backstage/catalog-model@0.9.9
+ - @backstage/plugin-catalog@0.7.8
+
## 0.6.21
### Patch Changes
diff --git a/plugins/api-docs/package.json b/plugins/api-docs/package.json
index 8d190dae92..10f1a74a8a 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.6.21",
+ "version": "0.6.22",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -31,11 +31,11 @@
},
"dependencies": {
"@asyncapi/react-component": "1.0.0-next.26",
- "@backstage/catalog-model": "^0.9.7",
- "@backstage/core-components": "^0.8.3",
- "@backstage/core-plugin-api": "^0.4.1",
- "@backstage/plugin-catalog": "^0.7.7",
- "@backstage/plugin-catalog-react": "^0.6.10",
+ "@backstage/catalog-model": "^0.9.9",
+ "@backstage/core-components": "^0.8.4",
+ "@backstage/core-plugin-api": "^0.5.0",
+ "@backstage/plugin-catalog": "^0.7.8",
+ "@backstage/plugin-catalog-react": "^0.6.11",
"@backstage/theme": "^0.2.14",
"@material-ui/core": "^4.12.2",
"@material-ui/icons": "^4.9.1",
@@ -46,24 +46,23 @@
"react-router": "6.0.0-beta.0",
"react-router-dom": "6.0.0-beta.0",
"react-use": "^17.2.4",
- "swagger-client": "3.16.1",
- "swagger-ui-react": "^4.0.0-rc.3"
+ "swagger-ui-react": "^4.1.3"
},
"peerDependencies": {
"@types/react": "^16.13.1 || ^17.0.0",
"react": "^16.13.1 || ^17.0.0"
},
"devDependencies": {
- "@backstage/cli": "^0.10.5",
- "@backstage/core-app-api": "^0.3.1",
- "@backstage/dev-utils": "^0.2.16",
- "@backstage/test-utils": "^0.2.1",
+ "@backstage/cli": "^0.11.0",
+ "@backstage/core-app-api": "^0.4.0",
+ "@backstage/dev-utils": "^0.2.17",
+ "@backstage/test-utils": "^0.2.2",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^11.2.5",
"@testing-library/user-event": "^13.1.8",
"@types/jest": "^26.0.7",
"@types/node": "^14.14.32",
- "@types/swagger-ui-react": "^3.23.3",
+ "@types/swagger-ui-react": "^4.1.1",
"cross-fetch": "^3.0.6",
"msw": "^0.35.0"
},
diff --git a/plugins/app-backend/package.json b/plugins/app-backend/package.json
index b1a01a8345..d5cbe9c07d 100644
--- a/plugins/app-backend/package.json
+++ b/plugins/app-backend/package.json
@@ -30,9 +30,9 @@
"clean": "backstage-cli clean"
},
"dependencies": {
- "@backstage/backend-common": "^0.10.1",
- "@backstage/config-loader": "^0.9.1",
- "@backstage/config": "^0.1.11",
+ "@backstage/backend-common": "^0.10.3",
+ "@backstage/config-loader": "^0.9.2",
+ "@backstage/config": "^0.1.12",
"@backstage/types": "^0.1.1",
"@types/express": "^4.17.6",
"express": "^4.17.1",
@@ -43,7 +43,7 @@
"yn": "^4.0.0"
},
"devDependencies": {
- "@backstage/cli": "^0.10.4",
+ "@backstage/cli": "^0.11.0",
"@backstage/types": "^0.1.1",
"@types/supertest": "^2.0.8",
"msw": "^0.35.0",
diff --git a/plugins/app-backend/src/lib/config.ts b/plugins/app-backend/src/lib/config.ts
index c37dc34dcc..6959253336 100644
--- a/plugins/app-backend/src/lib/config.ts
+++ b/plugins/app-backend/src/lib/config.ts
@@ -91,7 +91,7 @@ export async function readConfigs(options: ReadOptions): Promise {
const frontendConfigs = await schema.process(
[{ data: config.get() as JsonObject, context: 'app' }],
- { visibility: ['frontend'] },
+ { visibility: ['frontend'], withDeprecatedKeys: true },
);
appConfigs.push(...frontendConfigs);
} catch (error) {
diff --git a/plugins/auth-backend/CHANGELOG.md b/plugins/auth-backend/CHANGELOG.md
index 14e56b060e..533bf10166 100644
--- a/plugins/auth-backend/CHANGELOG.md
+++ b/plugins/auth-backend/CHANGELOG.md
@@ -1,5 +1,22 @@
# @backstage/plugin-auth-backend
+## 0.6.2
+
+### Patch Changes
+
+- 5333451def: Cleaned up API exports
+- da9c59d6e0: Removed `@backstage/test-utils` dependency.
+- 20ca7cfa5f: Switched the secure cookie mode set on the `express-session` to use `'auto'` rather than `true`. This works around an issue where cookies would not be set if TLS termination was handled in a proxy rather than having the backend served directly with HTTPS.
+
+ The downside of this change is that secure cookies won't be used unless the backend is directly served with HTTPS. This will be remedied in a future update that allows the backend to configured for trusted proxy mode.
+
+- Updated dependencies
+ - @backstage/config@0.1.12
+ - @backstage/backend-common@0.10.3
+ - @backstage/errors@0.2.0
+ - @backstage/catalog-client@0.5.4
+ - @backstage/catalog-model@0.9.9
+
## 0.6.1
### Patch Changes
diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json
index 3afd6cefe3..69dd53987f 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.6.1",
+ "version": "0.6.2",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -30,11 +30,11 @@
"clean": "backstage-cli clean"
},
"dependencies": {
- "@backstage/backend-common": "^0.10.2",
- "@backstage/catalog-client": "^0.5.3",
- "@backstage/catalog-model": "^0.9.8",
- "@backstage/config": "^0.1.11",
- "@backstage/errors": "^0.1.5",
+ "@backstage/backend-common": "^0.10.3",
+ "@backstage/catalog-client": "^0.5.4",
+ "@backstage/catalog-model": "^0.9.9",
+ "@backstage/config": "^0.1.12",
+ "@backstage/errors": "^0.2.0",
"@backstage/types": "^0.1.1",
"@google-cloud/firestore": "^4.15.1",
"@types/express": "^4.17.6",
@@ -73,8 +73,8 @@
"yn": "^4.0.0"
},
"devDependencies": {
- "@backstage/cli": "^0.10.5",
- "@backstage/test-utils": "^0.2.1",
+ "@backstage/cli": "^0.11.0",
+ "@backstage/test-utils": "^0.2.2",
"@types/body-parser": "^1.19.0",
"@types/cookie-parser": "^1.4.2",
"@types/express-session": "^1.17.2",
diff --git a/plugins/azure-devops-backend/CHANGELOG.md b/plugins/azure-devops-backend/CHANGELOG.md
index 080a4e0367..e61ccf4b72 100644
--- a/plugins/azure-devops-backend/CHANGELOG.md
+++ b/plugins/azure-devops-backend/CHANGELOG.md
@@ -1,5 +1,21 @@
# @backstage/plugin-azure-devops-backend
+## 0.3.0
+
+### Minor Changes
+
+- a2ed2c2d69: - feat: Created PullRequestsDashboardProvider for resolving team and team member relations
+ - feat: Created useUserTeamIds hook.
+ - feat: Updated useFilterProcessor to provide teamIds for `AssignedToCurrentUsersTeams` and `CreatedByCurrentUsersTeams` filters.
+
+### Patch Changes
+
+- 9f9596f9ef: Only warn if teams fail to load at startup.
+- Updated dependencies
+ - @backstage/config@0.1.12
+ - @backstage/backend-common@0.10.3
+ - @backstage/plugin-azure-devops-common@0.2.0
+
## 0.2.6
### Patch Changes
diff --git a/plugins/azure-devops-backend/api-report.md b/plugins/azure-devops-backend/api-report.md
index 9574215e3e..579367e2dd 100644
--- a/plugins/azure-devops-backend/api-report.md
+++ b/plugins/azure-devops-backend/api-report.md
@@ -15,6 +15,7 @@ import { PullRequest } from '@backstage/plugin-azure-devops-common';
import { PullRequestOptions } from '@backstage/plugin-azure-devops-common';
import { RepoBuild } from '@backstage/plugin-azure-devops-common';
import { Team } from '@backstage/plugin-azure-devops-common';
+import { TeamMember } from '@backstage/plugin-azure-devops-common';
import { WebApi } from 'azure-devops-node-api';
// Warning: (ae-missing-release-tag) "AzureDevOpsApi" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
@@ -71,6 +72,14 @@ export class AzureDevOpsApi {
repoName: string,
top: number,
): Promise;
+ // (undocumented)
+ getTeamMembers({
+ projectId,
+ teamId,
+ }: {
+ projectId: string;
+ teamId: string;
+ }): Promise;
}
// Warning: (ae-missing-release-tag) "createRouter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
diff --git a/plugins/azure-devops-backend/package.json b/plugins/azure-devops-backend/package.json
index 044a1acb95..61f89ccf56 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.2.6",
+ "version": "0.3.0",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -20,18 +20,19 @@
"clean": "backstage-cli clean"
},
"dependencies": {
- "@backstage/backend-common": "^0.10.0",
- "@backstage/config": "^0.1.11",
- "@backstage/plugin-azure-devops-common": "^0.1.3",
+ "@backstage/backend-common": "^0.10.3",
+ "@backstage/config": "^0.1.12",
+ "@backstage/plugin-azure-devops-common": "^0.2.0",
"@types/express": "^4.17.6",
"azure-devops-node-api": "^11.0.1",
"express": "^4.17.1",
"express-promise-router": "^4.1.0",
+ "p-limit": "^3.1.0",
"winston": "^3.2.1",
"yn": "^4.0.0"
},
"devDependencies": {
- "@backstage/cli": "^0.10.3",
+ "@backstage/cli": "^0.11.0",
"@types/supertest": "^2.0.8",
"supertest": "^6.1.6",
"msw": "^0.35.0"
diff --git a/plugins/azure-devops-backend/src/api/AzureDevOpsApi.ts b/plugins/azure-devops-backend/src/api/AzureDevOpsApi.ts
index 6e45a5f4e5..ff63af183e 100644
--- a/plugins/azure-devops-backend/src/api/AzureDevOpsApi.ts
+++ b/plugins/azure-devops-backend/src/api/AzureDevOpsApi.ts
@@ -28,6 +28,7 @@ import {
PullRequestOptions,
RepoBuild,
Team,
+ TeamMember,
} from '@backstage/plugin-azure-devops-common';
import {
GitPullRequest,
@@ -40,9 +41,9 @@ import {
getArtifactId,
} from '../utils';
+import { TeamMember as AdoTeamMember } from 'azure-devops-node-api/interfaces/common/VSSInterfaces';
import { Logger } from 'winston';
import { PolicyEvaluationRecord } from 'azure-devops-node-api/interfaces/PolicyInterfaces';
-import { TeamMember } from 'azure-devops-node-api/interfaces/common/VSSInterfaces';
import { WebApi } from 'azure-devops-node-api';
import { WebApiTeam } from 'azure-devops-node-api/interfaces/CoreInterfaces';
@@ -228,39 +229,37 @@ export class AzureDevOpsApi {
const client = await this.webApi.getCoreApi();
const webApiTeams: WebApiTeam[] = await client.getAllTeams();
- const teams: Team[] = await Promise.all(
- webApiTeams.map(async team => ({
- id: team.id,
- name: team.name,
- memberIds: await this.getTeamMemberIds(team),
- })),
- );
+ const teams: Team[] = webApiTeams.map(team => ({
+ id: team.id,
+ name: team.name,
+ projectId: team.projectId,
+ projectName: team.projectName,
+ }));
return teams.sort((a, b) =>
a.name && b.name ? a.name.localeCompare(b.name) : 0,
);
}
- private async getTeamMemberIds(
- team: WebApiTeam,
- ): Promise {
- this.logger?.debug(`Getting team member ids for team '${team.name}'.`);
-
- if (!team.projectId || !team.id) {
- return undefined;
- }
+ public async getTeamMembers({
+ projectId,
+ teamId,
+ }: {
+ projectId: string;
+ teamId: string;
+ }): Promise {
+ this.logger?.debug(`Getting team member ids for team '${teamId}'.`);
const client = await this.webApi.getCoreApi();
- const teamMembers: TeamMember[] =
- await client.getTeamMembersWithExtendedProperties(
- team.projectId,
- team.id,
- );
+ const teamMembers: AdoTeamMember[] =
+ await client.getTeamMembersWithExtendedProperties(projectId, teamId);
- return teamMembers
- .map(teamMember => teamMember.identity?.id)
- .filter((id): id is string => Boolean(id));
+ return teamMembers.map(teamMember => ({
+ id: teamMember.identity?.id,
+ displayName: teamMember.identity?.displayName,
+ uniqueName: teamMember.identity?.uniqueName,
+ }));
}
public async getBuildDefinitions(
diff --git a/plugins/azure-devops-backend/src/api/PullRequestsDashboardProvider.ts b/plugins/azure-devops-backend/src/api/PullRequestsDashboardProvider.ts
new file mode 100644
index 0000000000..0f6dbe5b04
--- /dev/null
+++ b/plugins/azure-devops-backend/src/api/PullRequestsDashboardProvider.ts
@@ -0,0 +1,147 @@
+/*
+ * 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 {
+ DashboardPullRequest,
+ PullRequestOptions,
+ Team,
+ TeamMember,
+} from '@backstage/plugin-azure-devops-common';
+
+import { AzureDevOpsApi } from './AzureDevOpsApi';
+import { Logger } from 'winston';
+import limiterFactory from 'p-limit';
+
+export class PullRequestsDashboardProvider {
+ private teams = new Map();
+
+ private teamMembers = new Map();
+
+ private constructor(
+ private readonly logger: Logger,
+ private readonly azureDevOpsApi: AzureDevOpsApi,
+ ) {}
+
+ public static async create(
+ logger: Logger,
+ azureDevOpsApi: AzureDevOpsApi,
+ ): Promise {
+ const provider = new PullRequestsDashboardProvider(logger, azureDevOpsApi);
+ try {
+ await provider.readTeams();
+ } catch (error) {
+ logger.warn(`Failed to load azure team information, ${error}`);
+ }
+ return provider;
+ }
+
+ public async readTeams(): Promise {
+ this.logger.info('Reading teams.');
+
+ let teams = await this.azureDevOpsApi.getAllTeams();
+
+ // This is used to filter out the default Azure Devops project teams.
+ teams = teams.filter(team =>
+ team.name && team.projectName
+ ? team.name !== `${team.projectName} Team`
+ : true,
+ );
+
+ this.teams = new Map();
+ this.teamMembers = new Map();
+
+ const limiter = limiterFactory(5);
+
+ await Promise.all(
+ teams.map(team =>
+ limiter(async () => {
+ const teamId = team.id;
+ const projectId = team.projectId;
+
+ if (teamId) {
+ let teamMembers: TeamMember[] | undefined;
+
+ if (projectId) {
+ teamMembers = await this.azureDevOpsApi.getTeamMembers({
+ projectId,
+ teamId,
+ });
+ }
+
+ if (teamMembers) {
+ team.members = teamMembers.reduce((arr, teamMember) => {
+ const teamMemberId = teamMember.id;
+
+ if (teamMemberId) {
+ arr.push(teamMemberId);
+ const memberOf = [
+ ...(this.teamMembers.get(teamMemberId)?.memberOf ?? []),
+ teamId,
+ ];
+ this.teamMembers.set(teamMemberId, {
+ ...teamMember,
+ memberOf,
+ });
+ }
+
+ return arr;
+ }, [] as string[]);
+
+ this.teams.set(teamId, team);
+ }
+ }
+ }),
+ ),
+ );
+ }
+
+ public async getDashboardPullRequests(
+ projectName: string,
+ options: PullRequestOptions,
+ ): Promise {
+ const dashboardPullRequests =
+ await this.azureDevOpsApi.getDashboardPullRequests(projectName, options);
+
+ return dashboardPullRequests.map(pr => {
+ if (pr.createdBy?.id) {
+ const teamIds = this.teamMembers.get(pr.createdBy.id)?.memberOf;
+ pr.createdBy.teamIds = teamIds;
+ pr.createdBy.teamNames = teamIds?.map(
+ teamId => this.teams.get(teamId)?.name ?? '',
+ );
+ }
+
+ return pr;
+ });
+ }
+
+ public async getUserTeamIds(email: string): Promise {
+ await this.getAllTeams(); // Make sure team members are loaded
+ return (
+ Array.from(this.teamMembers.values()).find(
+ teamMember => teamMember.uniqueName === email,
+ )?.memberOf ?? []
+ );
+ }
+
+ public async getAllTeams(): Promise {
+ if (!this.teams.size) {
+ await this.readTeams();
+ }
+
+ return Array.from(this.teams.values());
+ }
+}
diff --git a/plugins/azure-devops-backend/src/service/router.test.ts b/plugins/azure-devops-backend/src/service/router.test.ts
index 87135781e6..e6cd856c0a 100644
--- a/plugins/azure-devops-backend/src/service/router.test.ts
+++ b/plugins/azure-devops-backend/src/service/router.test.ts
@@ -49,6 +49,8 @@ describe('createRouter', () => {
getPullRequests: jest.fn(),
getBuilds: jest.fn(),
getBuildRuns: jest.fn(),
+ getAllTeams: jest.fn(),
+ getTeamMembers: jest.fn(),
} as any;
const router = await createRouter({
azureDevOpsApi,
@@ -406,4 +408,12 @@ describe('createRouter', () => {
});
});
});
+
+ describe('GET /users/:userId/team-ids', () => {
+ it('fetches a a list of teams', async () => {
+ azureDevOpsApi.getAllTeams.mockResolvedValue([]);
+ const response = await request(app).get('/users/user1/team-ids');
+ expect(response.status).toEqual(200);
+ });
+ });
});
diff --git a/plugins/azure-devops-backend/src/service/router.ts b/plugins/azure-devops-backend/src/service/router.ts
index 99c140a424..f41209e4ff 100644
--- a/plugins/azure-devops-backend/src/service/router.ts
+++ b/plugins/azure-devops-backend/src/service/router.ts
@@ -24,6 +24,7 @@ import { WebApi, getPersonalAccessTokenHandler } from 'azure-devops-node-api';
import { AzureDevOpsApi } from '../api';
import { Config } from '@backstage/config';
import { Logger } from 'winston';
+import { PullRequestsDashboardProvider } from '../api/PullRequestsDashboardProvider';
import Router from 'express-promise-router';
import { errorHandler } from '@backstage/backend-common';
import express from 'express';
@@ -52,6 +53,9 @@ export async function createRouter(
const azureDevOpsApi =
options.azureDevOpsApi || new AzureDevOpsApi(logger, webApi);
+ const pullRequestsDashboardProvider =
+ await PullRequestsDashboardProvider.create(logger, azureDevOpsApi);
+
const router = Router();
router.use(express.json());
@@ -131,7 +135,7 @@ export async function createRouter(
};
const pullRequests: DashboardPullRequest[] =
- await azureDevOpsApi.getDashboardPullRequests(
+ await pullRequestsDashboardProvider.getDashboardPullRequests(
projectName,
pullRequestOptions,
);
@@ -140,7 +144,7 @@ export async function createRouter(
});
router.get('/all-teams', async (_req, res) => {
- const allTeams = await azureDevOpsApi.getAllTeams();
+ const allTeams = await pullRequestsDashboardProvider.getAllTeams();
res.status(200).json(allTeams);
});
@@ -170,6 +174,12 @@ export async function createRouter(
res.status(200).json(builds);
});
+ router.get('/users/:userId/team-ids', async (req, res) => {
+ const { userId } = req.params;
+ const teamIds = await pullRequestsDashboardProvider.getUserTeamIds(userId);
+ res.status(200).json(teamIds);
+ });
+
router.use(errorHandler());
return router;
}
diff --git a/plugins/azure-devops-common/CHANGELOG.md b/plugins/azure-devops-common/CHANGELOG.md
index 84c2cae9a5..74129ea19e 100644
--- a/plugins/azure-devops-common/CHANGELOG.md
+++ b/plugins/azure-devops-common/CHANGELOG.md
@@ -1,5 +1,13 @@
# @backstage/plugin-azure-devops-common
+## 0.2.0
+
+### Minor Changes
+
+- a2ed2c2d69: - feat: Created PullRequestsDashboardProvider for resolving team and team member relations
+ - feat: Created useUserTeamIds hook.
+ - feat: Updated useFilterProcessor to provide teamIds for `AssignedToCurrentUsersTeams` and `CreatedByCurrentUsersTeams` filters.
+
## 0.1.3
### Patch Changes
diff --git a/plugins/azure-devops-common/api-report.md b/plugins/azure-devops-common/api-report.md
index 85a9e54847..308fd54c61 100644
--- a/plugins/azure-devops-common/api-report.md
+++ b/plugins/azure-devops-common/api-report.md
@@ -270,9 +270,27 @@ export interface Team {
// (undocumented)
id?: string;
// (undocumented)
- memberIds?: string[];
+ members?: string[];
// (undocumented)
name?: string;
+ // (undocumented)
+ projectId?: string;
+ // (undocumented)
+ projectName?: string;
+}
+
+// Warning: (ae-missing-release-tag) "TeamMember" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
+//
+// @public (undocumented)
+export interface TeamMember {
+ // (undocumented)
+ displayName?: string;
+ // (undocumented)
+ id?: string;
+ // (undocumented)
+ memberOf?: string[];
+ // (undocumented)
+ uniqueName?: string;
}
// (No @packageDocumentation comment for this package)
diff --git a/plugins/azure-devops-common/package.json b/plugins/azure-devops-common/package.json
index f8a9622bff..d8dfce0ab6 100644
--- a/plugins/azure-devops-common/package.json
+++ b/plugins/azure-devops-common/package.json
@@ -1,6 +1,6 @@
{
"name": "@backstage/plugin-azure-devops-common",
- "version": "0.1.3",
+ "version": "0.2.0",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -29,7 +29,7 @@
"clean": "backstage-cli clean"
},
"devDependencies": {
- "@backstage/cli": "^0.10.2"
+ "@backstage/cli": "^0.11.0"
},
"files": [
"dist"
diff --git a/plugins/azure-devops-common/src/types.ts b/plugins/azure-devops-common/src/types.ts
index 0befcf0b60..7978e3326a 100644
--- a/plugins/azure-devops-common/src/types.ts
+++ b/plugins/azure-devops-common/src/types.ts
@@ -178,7 +178,16 @@ export interface Repository {
export interface Team {
id?: string;
name?: string;
- memberIds?: string[];
+ projectId?: string;
+ projectName?: string;
+ members?: string[];
+}
+
+export interface TeamMember {
+ id?: string;
+ displayName?: string;
+ uniqueName?: string;
+ memberOf?: string[];
}
/**
diff --git a/plugins/azure-devops/CHANGELOG.md b/plugins/azure-devops/CHANGELOG.md
index 838130d4ae..b56f391976 100644
--- a/plugins/azure-devops/CHANGELOG.md
+++ b/plugins/azure-devops/CHANGELOG.md
@@ -1,5 +1,21 @@
# @backstage/plugin-azure-devops
+## 0.1.10
+
+### Patch Changes
+
+- a2ed2c2d69: - feat: Created PullRequestsDashboardProvider for resolving team and team member relations
+ - feat: Created useUserTeamIds hook.
+ - feat: Updated useFilterProcessor to provide teamIds for `AssignedToCurrentUsersTeams` and `CreatedByCurrentUsersTeams` filters.
+- 5333451def: Cleaned up API exports
+- Updated dependencies
+ - @backstage/core-components@0.8.4
+ - @backstage/core-plugin-api@0.5.0
+ - @backstage/plugin-azure-devops-common@0.2.0
+ - @backstage/plugin-catalog-react@0.6.11
+ - @backstage/errors@0.2.0
+ - @backstage/catalog-model@0.9.9
+
## 0.1.9
### Patch Changes
diff --git a/plugins/azure-devops/package.json b/plugins/azure-devops/package.json
index f8cbcc430a..8e40ed60fe 100644
--- a/plugins/azure-devops/package.json
+++ b/plugins/azure-devops/package.json
@@ -1,6 +1,6 @@
{
"name": "@backstage/plugin-azure-devops",
- "version": "0.1.9",
+ "version": "0.1.10",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -27,12 +27,12 @@
"clean": "backstage-cli clean"
},
"dependencies": {
- "@backstage/catalog-model": "^0.9.8",
- "@backstage/core-components": "^0.8.3",
- "@backstage/core-plugin-api": "^0.4.1",
- "@backstage/errors": "^0.1.4",
- "@backstage/plugin-azure-devops-common": "^0.1.3",
- "@backstage/plugin-catalog-react": "^0.6.10",
+ "@backstage/catalog-model": "^0.9.9",
+ "@backstage/core-components": "^0.8.4",
+ "@backstage/core-plugin-api": "^0.5.0",
+ "@backstage/errors": "^0.2.0",
+ "@backstage/plugin-azure-devops-common": "^0.2.0",
+ "@backstage/plugin-catalog-react": "^0.6.11",
"@backstage/theme": "^0.2.14",
"@material-ui/core": "^4.12.2",
"@material-ui/icons": "^4.9.1",
@@ -46,10 +46,10 @@
"react": "^16.13.1 || ^17.0.0"
},
"devDependencies": {
- "@backstage/cli": "^0.10.5",
- "@backstage/core-app-api": "^0.3.1",
- "@backstage/dev-utils": "^0.2.16",
- "@backstage/test-utils": "^0.2.1",
+ "@backstage/cli": "^0.11.0",
+ "@backstage/core-app-api": "^0.4.0",
+ "@backstage/dev-utils": "^0.2.17",
+ "@backstage/test-utils": "^0.2.2",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^11.2.5",
"@testing-library/user-event": "^13.1.8",
diff --git a/plugins/azure-devops/src/api/AzureDevOpsApi.ts b/plugins/azure-devops/src/api/AzureDevOpsApi.ts
index d6e926b9a5..89eec1bbbc 100644
--- a/plugins/azure-devops/src/api/AzureDevOpsApi.ts
+++ b/plugins/azure-devops/src/api/AzureDevOpsApi.ts
@@ -47,4 +47,6 @@ export interface AzureDevOpsApi {
): Promise;
getAllTeams(): Promise;
+
+ getUserTeamIds(userId: string): Promise;
}
diff --git a/plugins/azure-devops/src/api/AzureDevOpsClient.ts b/plugins/azure-devops/src/api/AzureDevOpsClient.ts
index 28d7e19cff..42c5ac3f6c 100644
--- a/plugins/azure-devops/src/api/AzureDevOpsClient.ts
+++ b/plugins/azure-devops/src/api/AzureDevOpsClient.ts
@@ -88,6 +88,10 @@ export class AzureDevOpsClient implements AzureDevOpsApi {
return this.get('all-teams');
}
+ public getUserTeamIds(userId: string): Promise {
+ return this.get(`users/${userId}/team-ids`);
+ }
+
private async get(path: string): Promise {
const baseUrl = `${await this.discoveryApi.getBaseUrl('azure-devops')}/`;
const url = new URL(path, baseUrl);
diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/hooks/useFilterProcessor.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/hooks/useFilterProcessor.ts
index 546b23430d..1e31b3b3ce 100644
--- a/plugins/azure-devops/src/components/PullRequestsPage/lib/hooks/useFilterProcessor.ts
+++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/hooks/useFilterProcessor.ts
@@ -15,11 +15,11 @@
*/
import { Filter, FilterType } from '../filters';
-
-import { useUserEmail } from '../../../../hooks';
+import { useUserEmail, useUserTeamIds } from '../../../../hooks';
export function useFilterProcessor(): (filters: Filter[]) => Filter[] {
const userEmail = useUserEmail();
+ const { teamIds } = useUserTeamIds(userEmail);
return (filters: Filter[]): Filter[] => {
for (const filter of filters) {
@@ -29,6 +29,11 @@ export function useFilterProcessor(): (filters: Filter[]) => Filter[] {
filter.email = userEmail;
break;
+ case FilterType.AssignedToCurrentUsersTeams:
+ case FilterType.CreatedByCurrentUsersTeams:
+ filter.teamIds = teamIds;
+ break;
+
default:
break;
}
diff --git a/plugins/azure-devops/src/hooks/index.ts b/plugins/azure-devops/src/hooks/index.ts
index 44b94f3f4b..a3864c21f7 100644
--- a/plugins/azure-devops/src/hooks/index.ts
+++ b/plugins/azure-devops/src/hooks/index.ts
@@ -20,3 +20,4 @@ export * from './useProjectRepoFromEntity';
export * from './usePullRequests';
export * from './useRepoBuilds';
export * from './useUserEmail';
+export * from './useUserTeamIds';
diff --git a/plugins/azure-devops/src/hooks/useUserTeamIds.ts b/plugins/azure-devops/src/hooks/useUserTeamIds.ts
new file mode 100644
index 0000000000..878dbebdfe
--- /dev/null
+++ b/plugins/azure-devops/src/hooks/useUserTeamIds.ts
@@ -0,0 +1,41 @@
+/*
+ * 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 { azureDevOpsApiRef } from '../api';
+import { useApi } from '@backstage/core-plugin-api';
+import { useAsync } from 'react-use';
+
+export function useUserTeamIds(userId: string | undefined): {
+ teamIds?: string[];
+ loading: boolean;
+ error?: Error;
+} {
+ const api = useApi(azureDevOpsApiRef);
+
+ const {
+ value: teamIds,
+ loading,
+ error,
+ } = useAsync(() => {
+ return userId ? api.getUserTeamIds(userId) : Promise.resolve(undefined);
+ }, [api]);
+
+ return {
+ teamIds,
+ loading,
+ error,
+ };
+}
diff --git a/plugins/badges-backend/CHANGELOG.md b/plugins/badges-backend/CHANGELOG.md
index 5b37003d36..d3ebf60a3d 100644
--- a/plugins/badges-backend/CHANGELOG.md
+++ b/plugins/badges-backend/CHANGELOG.md
@@ -1,5 +1,16 @@
# @backstage/plugin-badges-backend
+## 0.1.15
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/config@0.1.12
+ - @backstage/backend-common@0.10.3
+ - @backstage/errors@0.2.0
+ - @backstage/catalog-client@0.5.4
+ - @backstage/catalog-model@0.9.9
+
## 0.1.14
### Patch Changes
diff --git a/plugins/badges-backend/package.json b/plugins/badges-backend/package.json
index fbd7b2c266..dd2a8af930 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.14",
+ "version": "0.1.15",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -31,11 +31,11 @@
"clean": "backstage-cli clean"
},
"dependencies": {
- "@backstage/backend-common": "^0.10.0",
- "@backstage/catalog-client": "^0.5.3",
- "@backstage/catalog-model": "^0.9.7",
- "@backstage/config": "^0.1.10",
- "@backstage/errors": "^0.1.5",
+ "@backstage/backend-common": "^0.10.3",
+ "@backstage/catalog-client": "^0.5.4",
+ "@backstage/catalog-model": "^0.9.9",
+ "@backstage/config": "^0.1.12",
+ "@backstage/errors": "^0.2.0",
"@types/express": "^4.17.6",
"badge-maker": "^3.3.0",
"cors": "^2.8.5",
@@ -45,7 +45,7 @@
"yn": "^4.0.0"
},
"devDependencies": {
- "@backstage/cli": "^0.10.3",
+ "@backstage/cli": "^0.11.0",
"@types/supertest": "^2.0.8",
"supertest": "^6.1.3"
},
diff --git a/plugins/badges/CHANGELOG.md b/plugins/badges/CHANGELOG.md
index 67d54623bf..9c51905691 100644
--- a/plugins/badges/CHANGELOG.md
+++ b/plugins/badges/CHANGELOG.md
@@ -1,5 +1,16 @@
# @backstage/plugin-badges
+## 0.2.19
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/core-components@0.8.4
+ - @backstage/core-plugin-api@0.5.0
+ - @backstage/plugin-catalog-react@0.6.11
+ - @backstage/errors@0.2.0
+ - @backstage/catalog-model@0.9.9
+
## 0.2.18
### Patch Changes
diff --git a/plugins/badges/package.json b/plugins/badges/package.json
index f9e24f27bf..26580d63c7 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.18",
+ "version": "0.2.19",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -27,11 +27,11 @@
"clean": "backstage-cli clean"
},
"dependencies": {
- "@backstage/catalog-model": "^0.9.7",
- "@backstage/core-components": "^0.8.3",
- "@backstage/core-plugin-api": "^0.4.1",
- "@backstage/errors": "^0.1.5",
- "@backstage/plugin-catalog-react": "^0.6.10",
+ "@backstage/catalog-model": "^0.9.9",
+ "@backstage/core-components": "^0.8.4",
+ "@backstage/core-plugin-api": "^0.5.0",
+ "@backstage/errors": "^0.2.0",
+ "@backstage/plugin-catalog-react": "^0.6.11",
"@backstage/theme": "^0.2.14",
"@material-ui/core": "^4.12.2",
"@material-ui/icons": "^4.9.1",
@@ -43,10 +43,10 @@
"react": "^16.13.1 || ^17.0.0"
},
"devDependencies": {
- "@backstage/cli": "^0.10.5",
- "@backstage/core-app-api": "^0.3.1",
- "@backstage/dev-utils": "^0.2.16",
- "@backstage/test-utils": "^0.2.1",
+ "@backstage/cli": "^0.11.0",
+ "@backstage/core-app-api": "^0.4.0",
+ "@backstage/dev-utils": "^0.2.17",
+ "@backstage/test-utils": "^0.2.2",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^11.2.5",
"@testing-library/user-event": "^13.1.8",
diff --git a/plugins/bazaar-backend/CHANGELOG.md b/plugins/bazaar-backend/CHANGELOG.md
index 1a08a36b9d..eceb35eb1b 100644
--- a/plugins/bazaar-backend/CHANGELOG.md
+++ b/plugins/bazaar-backend/CHANGELOG.md
@@ -1,5 +1,15 @@
# @backstage/plugin-bazaar-backend
+## 0.1.6
+
+### Patch Changes
+
+- 6eb6e2dc31: Add Bazaar plugin to marketplace and some minor refactoring
+- Updated dependencies
+ - @backstage/config@0.1.12
+ - @backstage/backend-common@0.10.3
+ - @backstage/backend-test-utils@0.1.13
+
## 0.1.5
### Patch Changes
diff --git a/plugins/bazaar-backend/package.json b/plugins/bazaar-backend/package.json
index a7c59735ff..9c6cf17407 100644
--- a/plugins/bazaar-backend/package.json
+++ b/plugins/bazaar-backend/package.json
@@ -1,6 +1,6 @@
{
"name": "@backstage/plugin-bazaar-backend",
- "version": "0.1.5",
+ "version": "0.1.6",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -20,9 +20,9 @@
"clean": "backstage-cli clean"
},
"dependencies": {
- "@backstage/backend-common": "^0.10.0",
- "@backstage/backend-test-utils": "^0.1.11",
- "@backstage/config": "^0.1.5",
+ "@backstage/backend-common": "^0.10.3",
+ "@backstage/backend-test-utils": "^0.1.13",
+ "@backstage/config": "^0.1.12",
"@types/express": "^4.17.6",
"express": "^4.17.1",
"express-promise-router": "^4.1.0",
@@ -31,7 +31,7 @@
"yn": "^4.0.0"
},
"devDependencies": {
- "@backstage/cli": "^0.10.3"
+ "@backstage/cli": "^0.11.0"
},
"files": [
"dist",
diff --git a/plugins/bazaar-backend/src/service/router.ts b/plugins/bazaar-backend/src/service/router.ts
index 730d958fcd..3915c8c609 100644
--- a/plugins/bazaar-backend/src/service/router.ts
+++ b/plugins/bazaar-backend/src/service/router.ts
@@ -69,21 +69,19 @@ export async function createRouter(
}
});
- router.get('/projects/id/:id', async (request, response) => {
- const id = decodeURIComponent(request.params.id);
+ router.get('/projects/:idOrRef', async (request, response) => {
+ const idOrRef = decodeURIComponent(request.params.idOrRef);
+ let data;
- const data = await dbHandler.getMetadataById(parseInt(id, 10));
+ if (/^-?\d+$/.test(idOrRef)) {
+ data = await dbHandler.getMetadataById(parseInt(idOrRef, 10));
+ } else {
+ data = await dbHandler.getMetadataByRef(idOrRef);
+ }
response.json({ status: 'ok', data: data });
});
- router.get('/projects/ref/:ref', async (request, response) => {
- const ref = decodeURIComponent(request.params.ref);
-
- const data = await dbHandler.getMetadataByRef(ref);
- response.json({ status: 'ok', data: data });
- });
-
router.get('/projects', async (_, response) => {
const data = await dbHandler.getProjects();
diff --git a/plugins/bazaar/CHANGELOG.md b/plugins/bazaar/CHANGELOG.md
index 09b1f64edf..01d6f5955d 100644
--- a/plugins/bazaar/CHANGELOG.md
+++ b/plugins/bazaar/CHANGELOG.md
@@ -1,5 +1,20 @@
# @backstage/plugin-bazaar
+## 0.1.9
+
+### Patch Changes
+
+- 6eb6e2dc31: Add Bazaar plugin to marketplace and some minor refactoring
+- b47965beec: build(deps): bump `@date-io/luxon` from 1.3.13 to 2.11.1
+- Updated dependencies
+ - @backstage/core-components@0.8.4
+ - @backstage/cli@0.11.0
+ - @backstage/core-plugin-api@0.5.0
+ - @backstage/plugin-catalog-react@0.6.11
+ - @backstage/catalog-client@0.5.4
+ - @backstage/catalog-model@0.9.9
+ - @backstage/plugin-catalog@0.7.8
+
## 0.1.8
### Patch Changes
diff --git a/plugins/bazaar/package.json b/plugins/bazaar/package.json
index 03d6090f01..6c2a344c19 100644
--- a/plugins/bazaar/package.json
+++ b/plugins/bazaar/package.json
@@ -1,6 +1,6 @@
{
"name": "@backstage/plugin-bazaar",
- "version": "0.1.8",
+ "version": "0.1.9",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -21,12 +21,13 @@
"clean": "backstage-cli clean"
},
"dependencies": {
- "@backstage/catalog-model": "^0.9.7",
- "@backstage/cli": "^0.10.5",
- "@backstage/core-components": "^0.8.3",
- "@backstage/core-plugin-api": "^0.4.1",
- "@backstage/plugin-catalog": "^0.7.7",
- "@backstage/plugin-catalog-react": "^0.6.10",
+ "@backstage/catalog-client": "^0.5.4",
+ "@backstage/catalog-model": "^0.9.9",
+ "@backstage/cli": "^0.11.0",
+ "@backstage/core-components": "^0.8.4",
+ "@backstage/core-plugin-api": "^0.5.0",
+ "@backstage/plugin-catalog": "^0.7.8",
+ "@backstage/plugin-catalog-react": "^0.6.11",
"@date-io/luxon": "2.x",
"@material-ui/core": "^4.12.2",
"@material-ui/icons": "^4.9.1",
@@ -43,8 +44,8 @@
"react": "^16.13.1 || ^17.0.0"
},
"devDependencies": {
- "@backstage/cli": "^0.10.5",
- "@backstage/dev-utils": "^0.2.16",
+ "@backstage/cli": "^0.11.0",
+ "@backstage/dev-utils": "^0.2.17",
"@testing-library/jest-dom": "^5.10.1",
"cross-fetch": "^3.0.6"
},
diff --git a/plugins/bazaar/src/api.ts b/plugins/bazaar/src/api.ts
index 9f5010ec43..cae890ea4a 100644
--- a/plugins/bazaar/src/api.ts
+++ b/plugins/bazaar/src/api.ts
@@ -85,9 +85,12 @@ export class BazaarClient implements BazaarApi {
async getProjectById(id: number): Promise {
const baseUrl = await this.discoveryApi.getBaseUrl('bazaar');
- const response = await fetch(`${baseUrl}/projects/id/${id}`, {
- method: 'GET',
- });
+ const response = await fetch(
+ `${baseUrl}/projects/${encodeURIComponent(id)}`,
+ {
+ method: 'GET',
+ },
+ );
return response.ok ? response : null;
}
@@ -96,7 +99,7 @@ export class BazaarClient implements BazaarApi {
const baseUrl = await this.discoveryApi.getBaseUrl('bazaar');
const response = await fetch(
- `${baseUrl}/projects/ref/${encodeURIComponent(entityRef)}`,
+ `${baseUrl}/projects/${encodeURIComponent(entityRef)}`,
{
method: 'GET',
},
@@ -108,32 +111,45 @@ export class BazaarClient implements BazaarApi {
async getMembers(id: number): Promise {
const baseUrl = await this.discoveryApi.getBaseUrl('bazaar');
- return await fetch(`${baseUrl}/projects/${id}/members`, {
- method: 'GET',
- }).then(resp => resp.json());
+ return await fetch(
+ `${baseUrl}/projects/${encodeURIComponent(id)}/members`,
+ {
+ method: 'GET',
+ },
+ ).then(resp => resp.json());
}
async addMember(id: number, userId: string): Promise {
const baseUrl = await this.discoveryApi.getBaseUrl('bazaar');
- await fetch(`${baseUrl}/projects/${id}/member/${userId}`, {
- method: 'PUT',
- headers: {
- Accept: 'application/json',
- 'Content-Type': 'application/json',
+ await fetch(
+ `${baseUrl}/projects/${encodeURIComponent(
+ id,
+ )}/member/${encodeURIComponent(userId)}`,
+ {
+ method: 'PUT',
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({
+ picture: (await this.identityApi.getProfileInfo()).picture,
+ }),
},
- body: JSON.stringify({
- picture: this.identityApi.getProfile()?.picture,
- }),
- });
+ );
}
async deleteMember(id: number, userId: string): Promise {
const baseUrl = await this.discoveryApi.getBaseUrl('bazaar');
- await fetch(`${baseUrl}/projects/${id}/member/${userId}`, {
- method: 'DELETE',
- });
+ await fetch(
+ `${baseUrl}/projects/${encodeURIComponent(
+ id,
+ )}/member/${encodeURIComponent(userId)}`,
+ {
+ method: 'DELETE',
+ },
+ );
}
async getProjects(): Promise {
@@ -147,7 +163,7 @@ export class BazaarClient implements BazaarApi {
async deleteProject(id: number): Promise {
const baseUrl = await this.discoveryApi.getBaseUrl('bazaar');
- await fetch(`${baseUrl}/projects/${id}`, {
+ await fetch(`${baseUrl}/projects/${encodeURIComponent(id)}`, {
method: 'DELETE',
});
}
diff --git a/plugins/bazaar/src/components/About/About.tsx b/plugins/bazaar/src/components/About/About.tsx
index d9c529a209..68525ab642 100644
--- a/plugins/bazaar/src/components/About/About.tsx
+++ b/plugins/bazaar/src/components/About/About.tsx
@@ -15,8 +15,8 @@
*/
import React from 'react';
-import { Grid, Typography, Link, makeStyles } from '@material-ui/core';
-import { InfoCard } from '@backstage/core-components';
+import { Grid, Typography, makeStyles } from '@material-ui/core';
+import { InfoCard, Link } from '@backstage/core-components';
const useStyles = makeStyles({
subheader: {
@@ -39,7 +39,7 @@ export const About = () => {
internal projects suitable for{' '}
Inner Sourcing
diff --git a/plugins/bazaar/src/components/AddProjectDialog/AddProjectDialog.tsx b/plugins/bazaar/src/components/AddProjectDialog/AddProjectDialog.tsx
index 4333ff11fd..749fcf3cff 100644
--- a/plugins/bazaar/src/components/AddProjectDialog/AddProjectDialog.tsx
+++ b/plugins/bazaar/src/components/AddProjectDialog/AddProjectDialog.tsx
@@ -57,7 +57,10 @@ export const AddProjectDialog = ({
setSelectedEntity(entity);
};
- const handleSubmit: any = async (
+ const handleSubmit: (
+ getValues: UseFormGetValues,
+ reset: UseFormReset,
+ ) => Promise = async (
getValues: UseFormGetValues,
reset: UseFormReset,
) => {
diff --git a/plugins/bazaar/src/components/CardContentFields/CardContentFields.tsx b/plugins/bazaar/src/components/CardContentFields/CardContentFields.tsx
index 5145dc54b8..6c6ce1bb3e 100644
--- a/plugins/bazaar/src/components/CardContentFields/CardContentFields.tsx
+++ b/plugins/bazaar/src/components/CardContentFields/CardContentFields.tsx
@@ -21,10 +21,9 @@ import {
Card,
CardContent,
Typography,
- Link,
GridSize,
} from '@material-ui/core';
-import { Avatar } from '@backstage/core-components';
+import { Avatar, Link } from '@backstage/core-components';
import { AboutField } from '@backstage/plugin-catalog';
import { StatusTag } from '../StatusTag';
import { Member, BazaarProject } from '../../types';
@@ -32,6 +31,7 @@ import { Member, BazaarProject } from '../../types';
const useStyles = makeStyles({
break: {
wordBreak: 'break-word',
+ textAlign: 'justify',
},
});
@@ -111,7 +111,7 @@ export const CardContentFields = ({
/>
{member?.userId}
diff --git a/plugins/bazaar/src/components/EditProjectDialog/EditProjectDialog.tsx b/plugins/bazaar/src/components/EditProjectDialog/EditProjectDialog.tsx
index 0b2a8ef391..5073bd0cd9 100644
--- a/plugins/bazaar/src/components/EditProjectDialog/EditProjectDialog.tsx
+++ b/plugins/bazaar/src/components/EditProjectDialog/EditProjectDialog.tsx
@@ -36,6 +36,11 @@ const useStyles = makeStyles({
marginLeft: '0',
marginRight: 'auto',
},
+ wordBreak: {
+ wordBreak: 'break-all',
+ whiteSpace: 'normal',
+ margin: '-0.25rem 0',
+ },
});
export const EditProjectDialog = ({
@@ -76,9 +81,9 @@ export const EditProjectDialog = ({
});
}, [bazaarProject]);
- const handleEditSubmit: any = async (
+ const handleEditSubmit: (
getValues: UseFormGetValues,
- ) => {
+ ) => Promise = async (getValues: UseFormGetValues) => {
const formValues = getValues();
const updateResponse = await bazaarApi.updateProject({
@@ -101,7 +106,9 @@ export const EditProjectDialog = ({
handleClose={handleDeleteClose}
message={[
'Are you sure you want to delete ',
- {bazaarProject.name},
+
+ {bazaarProject.name}
+ ,
' from the Bazaar?',
]}
type="delete"
diff --git a/plugins/bazaar/src/components/EntityBazaarInfoContent/EntityBazaarInfoContent.tsx b/plugins/bazaar/src/components/EntityBazaarInfoContent/EntityBazaarInfoContent.tsx
index 470dc824b6..0c9da1ed24 100644
--- a/plugins/bazaar/src/components/EntityBazaarInfoContent/EntityBazaarInfoContent.tsx
+++ b/plugins/bazaar/src/components/EntityBazaarInfoContent/EntityBazaarInfoContent.tsx
@@ -15,7 +15,7 @@
*/
import React, { useState, useEffect } from 'react';
-import { CardHeader, Divider, IconButton } from '@material-ui/core';
+import { CardHeader, Divider, IconButton, makeStyles } from '@material-ui/core';
import {
HeaderIconLinkRow,
IconLinkVerticalProps,
@@ -37,6 +37,14 @@ import { ConfirmationDialog } from '../ConfirmationDialog';
import { CardContentFields } from '../CardContentFields';
import { fetchProjectMembers } from '../../util/fetchMethods';
+const useStyles = makeStyles({
+ wordBreak: {
+ wordBreak: 'break-all',
+ whiteSpace: 'normal',
+ margin: '-0.25rem 0',
+ },
+});
+
type Props = {
bazaarProject: BazaarProject | null | undefined;
fetchBazaarProject: () => Promise;
@@ -46,6 +54,7 @@ export const EntityBazaarInfoContent = ({
bazaarProject,
fetchBazaarProject,
}: Props) => {
+ const classes = useStyles();
const bazaarApi = useApi(bazaarApiRef);
const identity = useApi(identityApiRef);
const [openEdit, setOpenEdit] = useState(false);
@@ -160,9 +169,11 @@ export const EntityBazaarInfoContent = ({
handleClose={handleUnlinkClose}
message={[
'Are you sure you want to unlink ',
- {parseEntityRef(bazaarProject.entityRef!).name},
+
+ {parseEntityRef(bazaarProject.entityRef!).name}
+ ,
' from ',
- {bazaarProject.name},
+ {bazaarProject.name},
' ?',
]}
type="unlink"
@@ -171,7 +182,7 @@ export const EntityBazaarInfoContent = ({
)}
{bazaarProject?.name!}}
action={
void;
@@ -70,6 +84,7 @@ export const HomePageBazaarInfoCard = ({
handleClose,
initEntity,
}: Props) => {
+ const classes = useStyles();
const catalogLink = useRouteRef(catalogRouteRef);
const bazaarApi = useApi(bazaarApiRef);
const identity = useApi(identityApiRef);
@@ -222,9 +237,11 @@ export const HomePageBazaarInfoCard = ({
handleClose={() => setOpenUnlink(false)}
message={[
'Are you sure you want to unlink ',
- {parseEntityRef(bazaarProject.value?.entityRef!).name},
+
+ {parseEntityRef(bazaarProject.value?.entityRef!).name}
+ ,
' from ',
- {bazaarProject.value?.name},
+ {bazaarProject.value?.name},
' ?',
]}
type="unlink"
@@ -242,7 +259,11 @@ export const HomePageBazaarInfoCard = ({
/>
+ {bazaarProject.value?.name || initProject.name}
+
+ }
action={
setOpenEdit(true)}>
diff --git a/plugins/bazaar/src/components/InputField/InputField.tsx b/plugins/bazaar/src/components/InputField/InputField.tsx
index 76eb28da6c..cae22a1313 100644
--- a/plugins/bazaar/src/components/InputField/InputField.tsx
+++ b/plugins/bazaar/src/components/InputField/InputField.tsx
@@ -15,13 +15,18 @@
*/
import React from 'react';
-import { Controller, Control, FieldError } from 'react-hook-form';
+import {
+ Controller,
+ Control,
+ FieldError,
+ ValidationRule,
+} from 'react-hook-form';
import { TextField } from '@material-ui/core';
import { FormValues } from '../../types';
type Rules = {
required: boolean;
- pattern?: any;
+ pattern?: ValidationRule | undefined;
};
type Props = {
diff --git a/plugins/bazaar/src/components/ProjectCard/ProjectCard.tsx b/plugins/bazaar/src/components/ProjectCard/ProjectCard.tsx
index a558d347a5..3aeba305a9 100644
--- a/plugins/bazaar/src/components/ProjectCard/ProjectCard.tsx
+++ b/plugins/bazaar/src/components/ProjectCard/ProjectCard.tsx
@@ -41,12 +41,19 @@ const useStyles = makeStyles({
WebkitLineClamp: 7,
WebkitBoxOrient: 'vertical',
overflow: 'hidden',
- backgroundColor: '',
+ textAlign: 'justify',
},
memberCount: {
float: 'right',
},
- content: { height: '13rem', marginBottom: '-0.5rem' },
+ content: {
+ height: '13rem',
+ },
+ header: {
+ whiteSpace: 'nowrap',
+ overflow: 'hidden',
+ textOverflow: 'ellipsis',
+ },
});
type Props = {
@@ -82,7 +89,12 @@ export const ProjectCard = ({
setOpenCard(true)}>
+ {name}
+
+ }
subtitle={`updated ${DateTime.fromISO(
new Date(updatedAt!).toISOString(),
).toRelative({
diff --git a/plugins/bazaar/src/components/ProjectDialog/ProjectDialog.tsx b/plugins/bazaar/src/components/ProjectDialog/ProjectDialog.tsx
index 08c43d1c2e..2f8b9e9cb9 100644
--- a/plugins/bazaar/src/components/ProjectDialog/ProjectDialog.tsx
+++ b/plugins/bazaar/src/components/ProjectDialog/ProjectDialog.tsx
@@ -16,12 +16,7 @@
import React from 'react';
import { Button, Dialog } from '@material-ui/core';
-import {
- useForm,
- SubmitHandler,
- UseFormReset,
- UseFormGetValues,
-} from 'react-hook-form';
+import { useForm, UseFormReset, UseFormGetValues } from 'react-hook-form';
import { InputField } from '../InputField/InputField';
import { InputSelector } from '../InputSelector/InputSelector';
import { FormValues } from '../../types';
@@ -36,7 +31,7 @@ type Props = {
handleSave: (
getValues: UseFormGetValues,
reset: UseFormReset,
- ) => SubmitHandler;
+ ) => Promise;
isAddForm: boolean;
title: string;
defaultValues: FormValues;
diff --git a/plugins/bazaar/src/components/SortMethodSelector/SortMethodSelector.tsx b/plugins/bazaar/src/components/SortMethodSelector/SortMethodSelector.tsx
index 93d5649a14..d29211dc44 100644
--- a/plugins/bazaar/src/components/SortMethodSelector/SortMethodSelector.tsx
+++ b/plugins/bazaar/src/components/SortMethodSelector/SortMethodSelector.tsx
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-import React from 'react';
+import React, { ChangeEvent, ReactNode } from 'react';
import { FormControl, MenuItem, Select, makeStyles } from '@material-ui/core';
const useStyles = makeStyles({
@@ -27,7 +27,12 @@ const useStyles = makeStyles({
type Props = {
sortMethodNbr: number;
- handleSortMethodChange: any;
+ handleSortMethodChange:
+ | ((
+ event: ChangeEvent<{ name?: string | undefined; value: unknown }>,
+ child: ReactNode,
+ ) => void)
+ | undefined;
};
export const SortMethodSelector = ({
diff --git a/plugins/bazaar/src/components/SortView/SortView.tsx b/plugins/bazaar/src/components/SortView/SortView.tsx
index a7f99625e5..fa97ac69ee 100644
--- a/plugins/bazaar/src/components/SortView/SortView.tsx
+++ b/plugins/bazaar/src/components/SortView/SortView.tsx
@@ -33,7 +33,7 @@ import { fetchCatalogItems } from '../../util/fetchMethods';
import { parseBazaarProject } from '../../util/parseMethods';
const useStyles = makeStyles({
- button: { width: '12rem' },
+ button: { minWidth: '11rem' },
container: {
marginTop: '2rem',
},
@@ -141,7 +141,9 @@ export const SortView = () => {
}
}, [bazaarProjects, catalogEntities]);
- const handleSortMethodChange = (event: ChangeEvent) => {
+ const handleSortMethodChange = (
+ event: ChangeEvent<{ name?: string | undefined; value: unknown }>,
+ ) => {
setSortMethodNbr(
typeof event.target.value === 'number' ? event.target.value : 0,
);
diff --git a/plugins/bazaar/src/util/fetchMethods.ts b/plugins/bazaar/src/util/fetchMethods.ts
index 015abae210..f4bdb0ae38 100644
--- a/plugins/bazaar/src/util/fetchMethods.ts
+++ b/plugins/bazaar/src/util/fetchMethods.ts
@@ -19,6 +19,7 @@ import { parseMember } from './parseMethods';
import { BazaarProject, Member } from '../types';
import { BazaarApi } from '../api';
import { Entity } from '@backstage/catalog-model';
+import { CatalogApi } from '@backstage/plugin-catalog-react';
export const fetchProjectMembers = async (
bazaarApi: BazaarApi,
@@ -37,7 +38,9 @@ export const fetchProjectMembers = async (
return [];
};
-export const fetchCatalogItems = async (catalogApi: any): Promise => {
+export const fetchCatalogItems = async (
+ catalogApi: CatalogApi,
+): Promise => {
const entities = await catalogApi.getEntities({
filter: {
kind: ['Component', 'Resource'],
diff --git a/plugins/bitrise/CHANGELOG.md b/plugins/bitrise/CHANGELOG.md
index 3f606353c1..626f52a06c 100644
--- a/plugins/bitrise/CHANGELOG.md
+++ b/plugins/bitrise/CHANGELOG.md
@@ -1,5 +1,15 @@
# @backstage/plugin-bitrise
+## 0.1.22
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/core-components@0.8.4
+ - @backstage/core-plugin-api@0.5.0
+ - @backstage/plugin-catalog-react@0.6.11
+ - @backstage/catalog-model@0.9.9
+
## 0.1.21
### Patch Changes
diff --git a/plugins/bitrise/package.json b/plugins/bitrise/package.json
index e1dca12e2b..964f4da6d4 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.21",
+ "version": "0.1.22",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -21,10 +21,10 @@
"clean": "backstage-cli clean"
},
"dependencies": {
- "@backstage/catalog-model": "^0.9.7",
- "@backstage/core-components": "^0.8.3",
- "@backstage/core-plugin-api": "^0.4.1",
- "@backstage/plugin-catalog-react": "^0.6.10",
+ "@backstage/catalog-model": "^0.9.9",
+ "@backstage/core-components": "^0.8.4",
+ "@backstage/core-plugin-api": "^0.5.0",
+ "@backstage/plugin-catalog-react": "^0.6.11",
"@backstage/theme": "^0.2.14",
"@material-ui/core": "^4.12.2",
"@material-ui/icons": "^4.9.1",
@@ -40,10 +40,10 @@
"react": "^16.13.1 || ^17.0.0"
},
"devDependencies": {
- "@backstage/cli": "^0.10.5",
- "@backstage/core-app-api": "^0.3.1",
- "@backstage/dev-utils": "^0.2.16",
- "@backstage/test-utils": "^0.2.1",
+ "@backstage/cli": "^0.11.0",
+ "@backstage/core-app-api": "^0.4.0",
+ "@backstage/dev-utils": "^0.2.17",
+ "@backstage/test-utils": "^0.2.2",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^11.2.5",
"@testing-library/user-event": "^13.1.8",
diff --git a/plugins/catalog-backend-module-ldap/CHANGELOG.md b/plugins/catalog-backend-module-ldap/CHANGELOG.md
index b8e48924dc..b2da918f59 100644
--- a/plugins/catalog-backend-module-ldap/CHANGELOG.md
+++ b/plugins/catalog-backend-module-ldap/CHANGELOG.md
@@ -1,5 +1,17 @@
# @backstage/plugin-catalog-backend-module-ldap
+## 0.3.9
+
+### Patch Changes
+
+- 2b19fd2e94: Make sure to avoid accidental data sharing / mutation of `set` values
+- 722681b1b1: Clean up API report
+- Updated dependencies
+ - @backstage/config@0.1.12
+ - @backstage/plugin-catalog-backend@0.20.0
+ - @backstage/errors@0.2.0
+ - @backstage/catalog-model@0.9.9
+
## 0.3.8
### Patch Changes
diff --git a/plugins/catalog-backend-module-ldap/package.json b/plugins/catalog-backend-module-ldap/package.json
index 2817a0e209..ff79feaea2 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 modules that helps integrate towards LDAP",
- "version": "0.3.8",
+ "version": "0.3.9",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -29,10 +29,10 @@
"clean": "backstage-cli clean"
},
"dependencies": {
- "@backstage/catalog-model": "^0.9.7",
- "@backstage/config": "^0.1.11",
- "@backstage/errors": "^0.1.5",
- "@backstage/plugin-catalog-backend": "^0.19.0",
+ "@backstage/catalog-model": "^0.9.9",
+ "@backstage/config": "^0.1.12",
+ "@backstage/errors": "^0.2.0",
+ "@backstage/plugin-catalog-backend": "^0.20.0",
"@backstage/types": "^0.1.1",
"@types/ldapjs": "^2.2.0",
"ldapjs": "^2.2.0",
@@ -40,7 +40,7 @@
"winston": "^3.2.1"
},
"devDependencies": {
- "@backstage/cli": "^0.10.0",
+ "@backstage/cli": "^0.11.0",
"@types/lodash": "^4.14.151"
},
"files": [
diff --git a/plugins/catalog-backend-module-msgraph/CHANGELOG.md b/plugins/catalog-backend-module-msgraph/CHANGELOG.md
index 3db08d02fc..17afa99b76 100644
--- a/plugins/catalog-backend-module-msgraph/CHANGELOG.md
+++ b/plugins/catalog-backend-module-msgraph/CHANGELOG.md
@@ -1,5 +1,15 @@
# @backstage/plugin-catalog-backend-module-msgraph
+## 0.2.12
+
+### Patch Changes
+
+- 722681b1b1: Clean up API report
+- Updated dependencies
+ - @backstage/config@0.1.12
+ - @backstage/plugin-catalog-backend@0.20.0
+ - @backstage/catalog-model@0.9.9
+
## 0.2.11
### Patch Changes
diff --git a/plugins/catalog-backend-module-msgraph/package.json b/plugins/catalog-backend-module-msgraph/package.json
index db3e59c307..1afc377605 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 modules that helps integrate towards Microsoft Graph",
- "version": "0.2.11",
+ "version": "0.2.12",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -30,9 +30,9 @@
},
"dependencies": {
"@azure/msal-node": "^1.1.0",
- "@backstage/catalog-model": "^0.9.7",
- "@backstage/config": "^0.1.10",
- "@backstage/plugin-catalog-backend": "^0.19.3",
+ "@backstage/catalog-model": "^0.9.9",
+ "@backstage/config": "^0.1.12",
+ "@backstage/plugin-catalog-backend": "^0.20.0",
"@microsoft/microsoft-graph-types": "^2.6.0",
"@types/node-fetch": "^2.5.12",
"lodash": "^4.17.21",
@@ -42,9 +42,9 @@
"qs": "^6.9.4"
},
"devDependencies": {
- "@backstage/backend-common": "^0.10.0",
- "@backstage/cli": "^0.10.3",
- "@backstage/test-utils": "^0.2.0",
+ "@backstage/backend-common": "^0.10.3",
+ "@backstage/cli": "^0.11.0",
+ "@backstage/test-utils": "^0.2.2",
"@types/lodash": "^4.14.151",
"msw": "^0.35.0"
},
diff --git a/plugins/catalog-backend/CHANGELOG.md b/plugins/catalog-backend/CHANGELOG.md
index e53bb50e1a..e329c82ac0 100644
--- a/plugins/catalog-backend/CHANGELOG.md
+++ b/plugins/catalog-backend/CHANGELOG.md
@@ -1,5 +1,31 @@
# @backstage/plugin-catalog-backend
+## 0.20.0
+
+### Minor Changes
+
+- cd529c4094: In order to integrate the permissions system with the refresh endpoint in catalog-backend, a new AuthorizedRefreshService was created as a thin wrapper around the existing refresh service which performs authorization and handles the case when authorization is denied. In order to instantiate AuthorizedRefreshService, a permission client is required, which was added as a new field to `CatalogEnvironment`.
+
+ The new `permissions` field in `CatalogEnvironment` should already receive the permission client from the `PluginEnvrionment`, so there should be no changes required to the catalog backend setup. See [the create-app changelog](https://github.com/backstage/backstage/blob/master/packages/create-app/CHANGELOG.md) for more details.
+
+### Patch Changes
+
+- 0ae759dad4: Add catalog permission rules.
+- 3b4d8caff6: Allow a custom GithubCredentialsProvider to be passed to the GitHub processors.
+- 6fd70f8bc8: Provide support for Bitbucket servers with custom BaseURLs.
+- 5333451def: Cleaned up API exports
+- 730d01ab1a: Add apply-conditions endpoint for evaluating conditional permissions in catalog backend.
+- 0a6c68582a: Add authorization to catalog-backend entities GET endpoints
+- Updated dependencies
+ - @backstage/config@0.1.12
+ - @backstage/integration@0.7.1
+ - @backstage/backend-common@0.10.3
+ - @backstage/plugin-permission-node@0.3.0
+ - @backstage/errors@0.2.0
+ - @backstage/catalog-client@0.5.4
+ - @backstage/catalog-model@0.9.9
+ - @backstage/plugin-permission-common@0.3.1
+
## 0.19.4
### Patch Changes
diff --git a/plugins/catalog-backend/api-report.md b/plugins/catalog-backend/api-report.md
index 702597c7c8..c503d303ba 100644
--- a/plugins/catalog-backend/api-report.md
+++ b/plugins/catalog-backend/api-report.md
@@ -849,6 +849,7 @@ export type EntitiesRequest = {
filter?: EntityFilter;
fields?: (entity: Entity) => Entity;
pagination?: EntityPagination;
+ authorizationToken?: string;
};
// Warning: (ae-missing-release-tag) "EntitiesResponse" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
@@ -1358,7 +1359,7 @@ export interface NextRouterOptions {
// (undocumented)
logger: Logger_2;
// (undocumented)
- permissionRules?: PermissionRule[];
+ permissionIntegrationRouter?: express.Router;
// (undocumented)
refreshService?: RefreshService;
}
diff --git a/plugins/catalog-backend/package.json b/plugins/catalog-backend/package.json
index 504e86a736..71151c460d 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": "0.19.4",
+ "version": "0.20.0",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -30,15 +30,15 @@
"clean": "backstage-cli clean"
},
"dependencies": {
- "@backstage/backend-common": "^0.10.1",
- "@backstage/catalog-client": "^0.5.3",
- "@backstage/catalog-model": "^0.9.8",
- "@backstage/config": "^0.1.11",
- "@backstage/errors": "^0.1.5",
- "@backstage/integration": "^0.7.0",
+ "@backstage/backend-common": "^0.10.3",
+ "@backstage/catalog-client": "^0.5.4",
+ "@backstage/catalog-model": "^0.9.9",
+ "@backstage/config": "^0.1.12",
+ "@backstage/errors": "^0.2.0",
+ "@backstage/integration": "^0.7.1",
"@backstage/plugin-catalog-common": "^0.1.0",
- "@backstage/plugin-permission-common": "^0.3.0",
- "@backstage/plugin-permission-node": "^0.2.3",
+ "@backstage/plugin-permission-common": "^0.3.1",
+ "@backstage/plugin-permission-node": "^0.3.0",
"@backstage/search-common": "^0.2.1",
"@backstage/types": "^0.1.1",
"@octokit/graphql": "^4.5.8",
@@ -65,10 +65,10 @@
"yup": "^0.32.9"
},
"devDependencies": {
- "@backstage/backend-test-utils": "^0.1.12",
- "@backstage/cli": "^0.10.4",
- "@backstage/plugin-permission-common": "^0.3.0",
- "@backstage/test-utils": "^0.2.1",
+ "@backstage/backend-test-utils": "^0.1.13",
+ "@backstage/cli": "^0.11.0",
+ "@backstage/plugin-permission-common": "^0.3.1",
+ "@backstage/test-utils": "^0.2.2",
"@types/core-js": "^2.5.4",
"@types/git-url-parse": "^9.0.0",
"@types/lodash": "^4.14.151",
diff --git a/plugins/catalog-backend/src/catalog/types.ts b/plugins/catalog-backend/src/catalog/types.ts
index f030d63bce..f71d7fb7d9 100644
--- a/plugins/catalog-backend/src/catalog/types.ts
+++ b/plugins/catalog-backend/src/catalog/types.ts
@@ -70,6 +70,7 @@ export type EntitiesRequest = {
filter?: EntityFilter;
fields?: (entity: Entity) => Entity;
pagination?: EntityPagination;
+ authorizationToken?: string;
};
export type EntitiesResponse = {
diff --git a/plugins/catalog-backend/src/ingestion/processors/BitbucketDiscoveryProcessor.test.ts b/plugins/catalog-backend/src/ingestion/processors/BitbucketDiscoveryProcessor.test.ts
index 3f8d0ba0fb..7ace995fda 100644
--- a/plugins/catalog-backend/src/ingestion/processors/BitbucketDiscoveryProcessor.test.ts
+++ b/plugins/catalog-backend/src/ingestion/processors/BitbucketDiscoveryProcessor.test.ts
@@ -29,7 +29,10 @@ import { setupServer } from 'msw/node';
const server = setupServer();
-function setupStubs(projects: any[]) {
+function setupStubs(
+ projects: any[],
+ bitbucketBaseUrl = `https://bitbucket.mycompany.com`,
+) {
function pagedResponse(values: any): PagedResponse {
return {
values: values,
@@ -42,7 +45,7 @@ function setupStubs(projects: any[]) {
repos: string[],
): RequestHandler {
return rest.get(
- `https://bitbucket.mycompany.com/api/rest/1.0/projects/${project}/repos`,
+ `${bitbucketBaseUrl}/api/rest/1.0/projects/${project}/repos`,
(_, res, ctx) => {
const response = [];
for (const repo of repos) {
@@ -51,7 +54,7 @@ function setupStubs(projects: any[]) {
links: {
self: [
{
- href: `https://bitbucket.mycompany.com/projects/${project}/repos/${repo}/browse`,
+ href: `${bitbucketBaseUrl}/projects/${project}/repos/${repo}/browse`,
},
],
},
@@ -63,20 +66,17 @@ function setupStubs(projects: any[]) {
}
server.use(
- rest.get(
- `https://bitbucket.mycompany.com/api/rest/1.0/projects`,
- (_, res, ctx) => {
- return res(
- ctx.json(
- pagedResponse(
- projects.map(p => {
- return { key: p.key };
- }),
- ),
+ rest.get(`${bitbucketBaseUrl}/api/rest/1.0/projects`, (_, res, ctx) => {
+ return res(
+ ctx.json(
+ pagedResponse(
+ projects.map(p => {
+ return { key: p.key };
+ }),
),
- );
- },
- ),
+ ),
+ );
+ }),
);
for (const project of projects) {
@@ -249,6 +249,30 @@ describe('BitbucketDiscoveryProcessor', () => {
optional: true,
});
});
+
+ it('output repositories by target search ref', async () => {
+ setupStubs([{ key: 'demo', repos: ['demo'] }]);
+ const location: LocationSpec = {
+ type: 'bitbucket-discovery',
+ target:
+ 'https://bitbucket.mycompany.com/projects/demo/repos/demo/catalog.yaml?ref=branch-name',
+ };
+
+ const emitter = jest.fn();
+ await processor.readLocation(location, false, emitter);
+
+ expect(emitter).toHaveBeenCalledWith({
+ type: 'location',
+ location: {
+ type: 'url',
+ target:
+ 'https://bitbucket.mycompany.com/projects/demo/repos/demo/browse/catalog.yaml?ref=branch-name',
+ presence: 'optional',
+ },
+ optional: true,
+ });
+ });
+
it('filter unrelated repositories', async () => {
setupStubs([{ key: 'backstage', repos: ['test', 'abctest', 'testxyz'] }]);
const location: LocationSpec = {
@@ -302,6 +326,177 @@ describe('BitbucketDiscoveryProcessor', () => {
});
});
+ describe('handles organisation repositories with a custom baseURL', () => {
+ const processor = BitbucketDiscoveryProcessor.fromConfig(
+ new ConfigReader({
+ integrations: {
+ bitbucket: [
+ {
+ host: 'bitbucket.mycompany.com',
+ token: 'blob',
+ apiBaseUrl:
+ 'https://bitbucket.mycompany.com/custom-path/api/rest/1.0',
+ },
+ ],
+ },
+ }),
+ { logger: getVoidLogger() },
+ );
+
+ it('output all repositories', async () => {
+ setupStubs(
+ [
+ { key: 'backstage', repos: ['backstage'] },
+ { key: 'demo', repos: ['demo'] },
+ ],
+ 'https://bitbucket.mycompany.com/custom-path',
+ );
+ const location: LocationSpec = {
+ type: 'bitbucket-discovery',
+ target:
+ 'https://bitbucket.mycompany.com/custom-path/projects/*/repos/*/catalog.yaml',
+ };
+
+ const emitter = jest.fn();
+
+ await processor.readLocation(location, false, emitter);
+
+ expect(emitter).toHaveBeenCalledWith({
+ type: 'location',
+ location: {
+ type: 'url',
+ target:
+ 'https://bitbucket.mycompany.com/custom-path/projects/backstage/repos/backstage/browse/catalog.yaml',
+ presence: 'optional',
+ },
+ optional: true,
+ });
+ expect(emitter).toHaveBeenCalledWith({
+ type: 'location',
+ location: {
+ type: 'url',
+ target:
+ 'https://bitbucket.mycompany.com/custom-path/projects/demo/repos/demo/browse/catalog.yaml',
+ presence: 'optional',
+ },
+ optional: true,
+ });
+ });
+
+ it('output repositories with wildcards', async () => {
+ setupStubs(
+ [
+ { key: 'backstage', repos: ['backstage', 'techdocs-cli'] },
+ { key: 'demo', repos: ['demo'] },
+ ],
+ 'https://bitbucket.mycompany.com/custom-path',
+ );
+ const location: LocationSpec = {
+ type: 'bitbucket-discovery',
+ target:
+ 'https://bitbucket.mycompany.com/custom-path/projects/backstage/repos/techdocs-*/catalog.yaml',
+ };
+
+ const emitter = jest.fn();
+ await processor.readLocation(location, false, emitter);
+
+ expect(emitter).toHaveBeenCalledWith({
+ type: 'location',
+ location: {
+ type: 'url',
+ target:
+ 'https://bitbucket.mycompany.com/custom-path/projects/backstage/repos/techdocs-cli/browse/catalog.yaml',
+ presence: 'optional',
+ },
+ optional: true,
+ });
+ });
+
+ it('output repositories by target search ref', async () => {
+ setupStubs(
+ [{ key: 'demo', repos: ['demo'] }],
+ 'https://bitbucket.mycompany.com/custom-path',
+ );
+ const location: LocationSpec = {
+ type: 'bitbucket-discovery',
+ target:
+ 'https://bitbucket.mycompany.com/custom-path/projects/demo/repos/demo/catalog.yaml?ref=branch-name',
+ };
+
+ const emitter = jest.fn();
+ await processor.readLocation(location, false, emitter);
+
+ expect(emitter).toHaveBeenCalledWith({
+ type: 'location',
+ location: {
+ type: 'url',
+ target:
+ 'https://bitbucket.mycompany.com/custom-path/projects/demo/repos/demo/browse/catalog.yaml?ref=branch-name',
+ presence: 'optional',
+ },
+ optional: true,
+ });
+ });
+
+ it('filter unrelated repositories', async () => {
+ setupStubs(
+ [{ key: 'backstage', repos: ['test', 'abctest', 'testxyz'] }],
+ 'https://bitbucket.mycompany.com/custom-path',
+ );
+ const location: LocationSpec = {
+ type: 'bitbucket-discovery',
+ target:
+ 'https://bitbucket.mycompany.com/custom-path/projects/backstage/repos/test/catalog.yaml',
+ };
+
+ const emitter = jest.fn();
+ await processor.readLocation(location, false, emitter);
+
+ expect(emitter).toHaveBeenCalledWith({
+ type: 'location',
+ location: {
+ type: 'url',
+ target:
+ 'https://bitbucket.mycompany.com/custom-path/projects/backstage/repos/test/browse/catalog.yaml',
+ presence: 'optional',
+ },
+ optional: true,
+ });
+ });
+
+ it.each`
+ target
+ ${'https://bitbucket.mycompany.com/custom-path/projects/backstage/repos/*'}
+ ${'https://bitbucket.mycompany.com/custom-path/projects/backstage/repos/*/'}
+ ${'https://bitbucket.mycompany.com/custom-path/projects/backstage/repos/techdocs-*/'}
+ `("target '$target' adds default path to catalog", async ({ target }) => {
+ setupStubs(
+ [{ key: 'backstage', repos: ['techdocs-cli'] }],
+ 'https://bitbucket.mycompany.com/custom-path',
+ );
+
+ const location: LocationSpec = {
+ type: 'bitbucket-discovery',
+ target: target,
+ };
+
+ const emitter = jest.fn();
+ await processor.readLocation(location, false, emitter);
+
+ expect(emitter).toHaveBeenCalledTimes(1);
+ expect(emitter).toHaveBeenCalledWith({
+ type: 'location',
+ location: {
+ type: 'url',
+ target:
+ 'https://bitbucket.mycompany.com/custom-path/projects/backstage/repos/techdocs-cli/browse/catalog-info.yaml',
+ presence: 'optional',
+ },
+ optional: true,
+ });
+ });
+ });
+
describe('handles cloud repositories', () => {
const processor = BitbucketDiscoveryProcessor.fromConfig(
new ConfigReader({
diff --git a/plugins/catalog-backend/src/ingestion/processors/BitbucketDiscoveryProcessor.ts b/plugins/catalog-backend/src/ingestion/processors/BitbucketDiscoveryProcessor.ts
index 6a09694ae8..f08888d1ab 100644
--- a/plugins/catalog-backend/src/ingestion/processors/BitbucketDiscoveryProcessor.ts
+++ b/plugins/catalog-backend/src/ingestion/processors/BitbucketDiscoveryProcessor.ts
@@ -230,14 +230,18 @@ function parseUrl(urlString: string): {
catalogPath: string;
} {
const url = new URL(urlString);
- const path = url.pathname.substr(1).split('/');
+ const indexOfProjectSegment =
+ url.pathname.toLowerCase().indexOf('/projects/') + 1;
+ const path = url.pathname.substr(indexOfProjectSegment).split('/');
// /projects/backstage/repos/techdocs-*/catalog-info.yaml
if (path.length > 3 && path[1].length && path[3].length) {
return {
projectSearchPath: escapeRegExp(decodeURIComponent(path[1])),
repoSearchPath: escapeRegExp(decodeURIComponent(path[3])),
- catalogPath: `/${decodeURIComponent(path.slice(4).join('/'))}`,
+ catalogPath: `/${decodeURIComponent(
+ path.slice(4).join('/') + url.search,
+ )}`,
};
}
diff --git a/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.test.ts b/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.test.ts
new file mode 100644
index 0000000000..768e3a690b
--- /dev/null
+++ b/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.test.ts
@@ -0,0 +1,96 @@
+/*
+ * 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 { AuthorizeResult } from '@backstage/plugin-permission-common';
+import { createConditionTransformer } from '@backstage/plugin-permission-node';
+import { isEntityKind } from '../permissions/rules/isEntityKind';
+import { AuthorizedEntitiesCatalog } from './AuthorizedEntitiesCatalog';
+
+describe('AuthorizedEntitiesCatalog', () => {
+ const fakeCatalog = {
+ entities: jest.fn(),
+ removeEntityByUid: jest.fn(),
+ entityAncestry: jest.fn(),
+ };
+ const fakePermissionApi = {
+ authorize: jest.fn(),
+ };
+
+ afterEach(() => {
+ jest.clearAllMocks();
+ });
+
+ describe('entities', () => {
+ it('returns empty response on DENY', async () => {
+ fakePermissionApi.authorize.mockResolvedValue([
+ { result: AuthorizeResult.DENY },
+ ]);
+
+ const catalog = new AuthorizedEntitiesCatalog(
+ fakeCatalog,
+ fakePermissionApi,
+ createConditionTransformer([]),
+ );
+
+ expect(
+ await catalog.entities({
+ authorizationToken: 'abcd',
+ }),
+ ).toEqual({
+ entities: [],
+ pageInfo: { hasNextPage: false },
+ });
+ });
+
+ it('calls underlying catalog method with correct filter on CONDITIONAL', async () => {
+ fakePermissionApi.authorize.mockResolvedValue([
+ {
+ result: AuthorizeResult.CONDITIONAL,
+ conditions: { rule: 'IS_ENTITY_KIND', params: [['b']] },
+ },
+ ]);
+ const catalog = new AuthorizedEntitiesCatalog(
+ fakeCatalog,
+ fakePermissionApi,
+ createConditionTransformer([isEntityKind]),
+ );
+
+ await catalog.entities({ authorizationToken: 'abcd' });
+
+ expect(fakeCatalog.entities).toHaveBeenCalledWith({
+ authorizationToken: 'abcd',
+ filter: { key: 'kind', values: ['b'] },
+ });
+ });
+
+ it('calls underlying catalog method on ALLOW', async () => {
+ fakePermissionApi.authorize.mockResolvedValue([
+ { result: AuthorizeResult.ALLOW },
+ ]);
+ const catalog = new AuthorizedEntitiesCatalog(
+ fakeCatalog,
+ fakePermissionApi,
+ createConditionTransformer([]),
+ );
+
+ await catalog.entities({ authorizationToken: 'abcd' });
+
+ expect(fakeCatalog.entities).toHaveBeenCalledWith({
+ authorizationToken: 'abcd',
+ });
+ });
+ });
+});
diff --git a/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.ts b/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.ts
new file mode 100644
index 0000000000..5b65070c43
--- /dev/null
+++ b/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.ts
@@ -0,0 +1,77 @@
+/*
+ * 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 { catalogEntityReadPermission } from '@backstage/plugin-catalog-common';
+import {
+ AuthorizeResult,
+ PermissionAuthorizer,
+} from '@backstage/plugin-permission-common';
+import { ConditionTransformer } from '@backstage/plugin-permission-node';
+import {
+ EntitiesCatalog,
+ EntitiesRequest,
+ EntitiesResponse,
+ EntityAncestryResponse,
+ EntityFilter,
+} from '../catalog/types';
+
+export class AuthorizedEntitiesCatalog implements EntitiesCatalog {
+ constructor(
+ private readonly entitiesCatalog: EntitiesCatalog,
+ private readonly permissionApi: PermissionAuthorizer,
+ private readonly transformConditions: ConditionTransformer,
+ ) {}
+
+ async entities(request?: EntitiesRequest): Promise {
+ const authorizeResponse = (
+ await this.permissionApi.authorize(
+ [{ permission: catalogEntityReadPermission }],
+ { token: request?.authorizationToken },
+ )
+ )[0];
+
+ if (authorizeResponse.result === AuthorizeResult.DENY) {
+ return {
+ entities: [],
+ pageInfo: { hasNextPage: false },
+ };
+ }
+
+ if (authorizeResponse.result === AuthorizeResult.CONDITIONAL) {
+ const permissionFilter: EntityFilter = this.transformConditions(
+ authorizeResponse.conditions,
+ );
+ return this.entitiesCatalog.entities({
+ ...request,
+ filter: request?.filter
+ ? { allOf: [permissionFilter, request.filter] }
+ : permissionFilter,
+ });
+ }
+
+ return this.entitiesCatalog.entities(request);
+ }
+
+ removeEntityByUid(uid: string): Promise {
+ // TODO: Implement permissioning
+ return this.entitiesCatalog.removeEntityByUid(uid);
+ }
+
+ entityAncestry(entityRef: string): Promise {
+ // TODO: Implement permissioning
+ return this.entitiesCatalog.entityAncestry(entityRef);
+ }
+}
diff --git a/plugins/catalog-backend/src/service/NextCatalogBuilder.ts b/plugins/catalog-backend/src/service/NextCatalogBuilder.ts
index eecfb5fc11..18ee1e2042 100644
--- a/plugins/catalog-backend/src/service/NextCatalogBuilder.ts
+++ b/plugins/catalog-backend/src/service/NextCatalogBuilder.ts
@@ -23,7 +23,9 @@ import {
FieldFormatEntityPolicy,
makeValidator,
NoForeignRootFieldsEntityPolicy,
+ parseEntityRef,
SchemaValidEntityPolicy,
+ stringifyEntityRef,
Validators,
} from '@backstage/catalog-model';
import {
@@ -33,7 +35,7 @@ import {
} from '@backstage/integration';
import { createHash } from 'crypto';
import { Router } from 'express';
-import lodash from 'lodash';
+import lodash, { keyBy } from 'lodash';
import { EntitiesCatalog, EntitiesSearchFilter } from '../catalog';
import {
DatabaseLocationsCatalog,
@@ -90,7 +92,14 @@ import { LocationService } from './types';
import { connectEntityProviders } from '../processing/connectEntityProviders';
import { permissionRules as catalogPermissionRules } from '../permissions/rules';
import { PermissionAuthorizer } from '@backstage/plugin-permission-common';
-import { PermissionRule } from '@backstage/plugin-permission-node';
+import {
+ PermissionRule,
+ createConditionTransformer,
+ createPermissionIntegrationRouter,
+} from '@backstage/plugin-permission-node';
+import { AuthorizedEntitiesCatalog } from './AuthorizedEntitiesCatalog';
+import { basicEntityFilter } from './request/basicEntityFilter';
+import { RESOURCE_TYPE_CATALOG_ENTITY } from '@backstage/plugin-catalog-common';
export type CatalogEnvironment = {
logger: Logger;
@@ -399,7 +408,38 @@ export class NextCatalogBuilder {
parser,
policy,
});
- const entitiesCatalog = new NextEntitiesCatalog(dbClient);
+ const unauthorizedEntitiesCatalog = new NextEntitiesCatalog(dbClient);
+ const entitiesCatalog = new AuthorizedEntitiesCatalog(
+ unauthorizedEntitiesCatalog,
+ permissions,
+ createConditionTransformer(this.permissionRules),
+ );
+ const permissionIntegrationRouter = createPermissionIntegrationRouter({
+ resourceType: RESOURCE_TYPE_CATALOG_ENTITY,
+ getResources: async (resourceRefs: string[]) => {
+ const { entities } = await unauthorizedEntitiesCatalog.entities({
+ filter: {
+ anyOf: resourceRefs.map(resourceRef => {
+ const { kind, namespace, name } = parseEntityRef(resourceRef);
+
+ return basicEntityFilter({
+ kind,
+ 'metadata.namespace': namespace,
+ 'metadata.name': name,
+ });
+ }),
+ },
+ });
+
+ const entitiesByRef = keyBy(entities, stringifyEntityRef);
+
+ return resourceRefs.map(
+ resourceRef =>
+ entitiesByRef[stringifyEntityRef(parseEntityRef(resourceRef))],
+ );
+ },
+ rules: this.permissionRules,
+ });
const stitcher = new Stitcher(dbClient, logger);
const locationStore = new DefaultLocationStore(dbClient);
@@ -435,7 +475,7 @@ export class NextCatalogBuilder {
refreshService,
logger,
config,
- permissionRules: this.permissionRules,
+ permissionIntegrationRouter,
});
await connectEntityProviders(processingDatabase, entityProviders);
diff --git a/plugins/catalog-backend/src/service/NextRouter.test.ts b/plugins/catalog-backend/src/service/NextRouter.test.ts
index e835c4620a..b79fba4a56 100644
--- a/plugins/catalog-backend/src/service/NextRouter.test.ts
+++ b/plugins/catalog-backend/src/service/NextRouter.test.ts
@@ -25,6 +25,8 @@ import { LocationService, RefreshService } from './types';
import { basicEntityFilter } from './request';
import { createNextRouter } from './NextRouter';
import { AuthorizeResult } from '@backstage/plugin-permission-common';
+import { createPermissionIntegrationRouter } from '@backstage/plugin-permission-node';
+import { RESOURCE_TYPE_CATALOG_ENTITY } from '@backstage/plugin-catalog-common';
describe('createNextRouter readonly disabled', () => {
let entitiesCatalog: jest.Mocked;
@@ -52,7 +54,7 @@ describe('createNextRouter readonly disabled', () => {
logger: getVoidLogger(),
refreshService,
config: new ConfigReader(undefined),
- permissionRules: [],
+ permissionIntegrationRouter: express.Router(),
});
app = express().use(router);
});
@@ -340,7 +342,7 @@ describe('createNextRouter readonly enabled', () => {
readonly: true,
},
}),
- permissionRules: [],
+ permissionIntegrationRouter: express.Router(),
});
app = express().use(router);
});
@@ -468,7 +470,15 @@ describe('NextRouter permissioning', () => {
logger: getVoidLogger(),
refreshService,
config: new ConfigReader(undefined),
- permissionRules: [fakeRule],
+ permissionIntegrationRouter: createPermissionIntegrationRouter({
+ resourceType: RESOURCE_TYPE_CATALOG_ENTITY,
+ rules: [fakeRule],
+ getResources: jest.fn((resourceRefs: string[]) =>
+ Promise.resolve(
+ resourceRefs.map(resourceRef => ({ id: resourceRef })),
+ ),
+ ),
+ }),
});
app = express().use(router);
});
@@ -480,7 +490,7 @@ describe('NextRouter permissioning', () => {
it('accepts and evaluates conditions at the apply-conditions endpoint', async () => {
const spideySense: Entity = {
apiVersion: 'a',
- kind: 'b',
+ kind: 'component',
metadata: {
name: 'spidey-sense',
},
@@ -491,15 +501,22 @@ describe('NextRouter permissioning', () => {
});
const requestBody = {
- resourceType: 'catalog-entity',
- resourceRef: 'component:default/spidey-sense',
- conditions: { rule: 'FAKE_RULE', params: ['user:default/spiderman'] },
+ items: [
+ {
+ id: '123',
+ resourceType: 'catalog-entity',
+ resourceRef: 'component:default/spidey-sense',
+ conditions: { rule: 'FAKE_RULE', params: ['user:default/spiderman'] },
+ },
+ ],
};
const response = await request(app)
.post('/.well-known/backstage/permissions/apply-conditions')
.send(requestBody);
expect(response.status).toBe(200);
- expect(response.body).toEqual({ result: AuthorizeResult.ALLOW });
+ expect(response.body).toEqual({
+ items: [{ id: '123', result: AuthorizeResult.ALLOW }],
+ });
});
});
diff --git a/plugins/catalog-backend/src/service/NextRouter.ts b/plugins/catalog-backend/src/service/NextRouter.ts
index 5338f58f91..78550e1791 100644
--- a/plugins/catalog-backend/src/service/NextRouter.ts
+++ b/plugins/catalog-backend/src/service/NextRouter.ts
@@ -17,23 +17,16 @@
import { errorHandler } from '@backstage/backend-common';
import {
analyzeLocationSchema,
- Entity,
locationSpecSchema,
- parseEntityRef,
stringifyEntityRef,
} from '@backstage/catalog-model';
import { Config } from '@backstage/config';
import { NotFoundError } from '@backstage/errors';
-import { RESOURCE_TYPE_CATALOG_ENTITY } from '@backstage/plugin-catalog-common';
-import {
- createPermissionIntegrationRouter,
- PermissionRule,
-} from '@backstage/plugin-permission-node';
import express from 'express';
import Router from 'express-promise-router';
import { Logger } from 'winston';
import yn from 'yn';
-import { EntitiesCatalog, EntitiesSearchFilter } from '../catalog';
+import { EntitiesCatalog } from '../catalog';
import { LocationAnalyzer } from '../ingestion/types';
import {
basicEntityFilter,
@@ -51,7 +44,7 @@ export interface NextRouterOptions {
refreshService?: RefreshService;
logger: Logger;
config: Config;
- permissionRules?: PermissionRule[];
+ permissionIntegrationRouter?: express.Router;
}
export async function createNextRouter(
@@ -64,7 +57,7 @@ export async function createNextRouter(
refreshService,
config,
logger,
- permissionRules,
+ permissionIntegrationRouter,
} = options;
const router = Router();
@@ -88,21 +81,18 @@ export async function createNextRouter(
});
}
+ if (permissionIntegrationRouter) {
+ router.use(permissionIntegrationRouter);
+ }
+
if (entitiesCatalog) {
router
- .use(
- createPermissionIntegrationRouter({
- resourceType: RESOURCE_TYPE_CATALOG_ENTITY,
- getResource: resourceRef =>
- getEntityResource(resourceRef, entitiesCatalog),
- rules: permissionRules ?? [],
- }),
- )
.get('/entities', async (req, res) => {
const { entities, pageInfo } = await entitiesCatalog.entities({
filter: parseEntityFilterParams(req.query),
fields: parseEntityTransformParams(req.query),
pagination: parseEntityPaginationParams(req.query),
+ authorizationToken: getBearerToken(req.header('authorization')),
});
// Add a Link header to the next page
@@ -120,6 +110,7 @@ export async function createNextRouter(
const { uid } = req.params;
const { entities } = await entitiesCatalog.entities({
filter: basicEntityFilter({ 'metadata.uid': uid }),
+ authorizationToken: getBearerToken(req.header('authorization')),
});
if (!entities.length) {
throw new NotFoundError(`No entity with uid ${uid}`);
@@ -139,6 +130,7 @@ export async function createNextRouter(
'metadata.namespace': namespace,
'metadata.name': name,
}),
+ authorizationToken: getBearerToken(req.header('authorization')),
});
if (!entities.length) {
throw new NotFoundError(
@@ -204,23 +196,6 @@ export async function createNextRouter(
return router;
}
-async function getEntityResource(
- resourceRef: string,
- entitiesCatalog: EntitiesCatalog,
-): Promise {
- const parsed = parseEntityRef(resourceRef);
-
- const { entities } = await entitiesCatalog.entities({
- filter: basicEntityFilter({
- kind: parsed.kind,
- 'metadata.namespace': parsed.namespace,
- 'metadata.name': parsed.name,
- }),
- });
-
- return entities[0];
-}
-
function getBearerToken(
authorizationHeader: string | undefined,
): string | undefined {
diff --git a/plugins/catalog-common/package.json b/plugins/catalog-common/package.json
index da4f80cd1a..5026dc0074 100644
--- a/plugins/catalog-common/package.json
+++ b/plugins/catalog-common/package.json
@@ -30,10 +30,10 @@
"clean": "backstage-cli clean"
},
"dependencies": {
- "@backstage/plugin-permission-common": "^0.3.0"
+ "@backstage/plugin-permission-common": "^0.3.1"
},
"devDependencies": {
- "@backstage/cli": "^0.10.3"
+ "@backstage/cli": "^0.11.0"
},
"files": [
"dist"
diff --git a/plugins/catalog-graph/CHANGELOG.md b/plugins/catalog-graph/CHANGELOG.md
index ffbef5c63f..22020d0e97 100644
--- a/plugins/catalog-graph/CHANGELOG.md
+++ b/plugins/catalog-graph/CHANGELOG.md
@@ -1,5 +1,16 @@
# @backstage/plugin-catalog-graph
+## 0.2.6
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/core-components@0.8.4
+ - @backstage/core-plugin-api@0.5.0
+ - @backstage/plugin-catalog-react@0.6.11
+ - @backstage/catalog-client@0.5.4
+ - @backstage/catalog-model@0.9.9
+
## 0.2.5
### Patch Changes
diff --git a/plugins/catalog-graph/package.json b/plugins/catalog-graph/package.json
index 8718172cf4..de06748c90 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.5",
+ "version": "0.2.6",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -21,11 +21,11 @@
"clean": "backstage-cli clean"
},
"dependencies": {
- "@backstage/catalog-client": "^0.5.3",
- "@backstage/catalog-model": "^0.9.7",
- "@backstage/core-components": "^0.8.3",
- "@backstage/core-plugin-api": "^0.4.1",
- "@backstage/plugin-catalog-react": "^0.6.10",
+ "@backstage/catalog-client": "^0.5.4",
+ "@backstage/catalog-model": "^0.9.9",
+ "@backstage/core-components": "^0.8.4",
+ "@backstage/core-plugin-api": "^0.5.0",
+ "@backstage/plugin-catalog-react": "^0.6.11",
"@backstage/theme": "^0.2.14",
"@material-ui/core": "^4.12.2",
"@material-ui/icons": "^4.9.1",
@@ -42,10 +42,10 @@
"react": "^16.13.1 || ^17.0.0"
},
"devDependencies": {
- "@backstage/cli": "^0.10.5",
- "@backstage/core-app-api": "^0.3.1",
- "@backstage/dev-utils": "^0.2.16",
- "@backstage/test-utils": "^0.2.1",
+ "@backstage/cli": "^0.11.0",
+ "@backstage/core-app-api": "^0.4.0",
+ "@backstage/dev-utils": "^0.2.17",
+ "@backstage/test-utils": "^0.2.2",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^11.2.5",
"@testing-library/react-hooks": "^7.0.2",
diff --git a/plugins/catalog-graphql/CHANGELOG.md b/plugins/catalog-graphql/CHANGELOG.md
index fe6cc4cc00..e06952bb60 100644
--- a/plugins/catalog-graphql/CHANGELOG.md
+++ b/plugins/catalog-graphql/CHANGELOG.md
@@ -1,5 +1,18 @@
# @backstage/plugin-catalog-graphql
+## 0.3.0
+
+### Minor Changes
+
+- 0fb17da164: chore: bumping dependencies in the GraphQL modules and bringing them up to date with the latest `graphql-modules` library
+
+### Patch Changes
+
+- cf01627a33: Bump graphql versions
+- Updated dependencies
+ - @backstage/config@0.1.12
+ - @backstage/catalog-model@0.9.9
+
## 0.2.14
### Patch Changes
diff --git a/plugins/catalog-graphql/api-report.md b/plugins/catalog-graphql/api-report.md
index f3795efd9d..019f9c279f 100644
--- a/plugins/catalog-graphql/api-report.md
+++ b/plugins/catalog-graphql/api-report.md
@@ -4,13 +4,13 @@
```ts
import { Config } from '@backstage/config';
-import { GraphQLModule } from '@graphql-modules/core';
import { Logger as Logger_2 } from 'winston';
+import { Module } from 'graphql-modules';
// Warning: (ae-missing-release-tag) "createModule" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
-export function createModule(options: ModuleOptions): Promise;
+export function createModule(options: ModuleOptions): Promise;
// Warning: (ae-missing-release-tag) "ModuleOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
diff --git a/plugins/catalog-graphql/codegen.yml b/plugins/catalog-graphql/codegen.yml
index e100277942..d71c9a7017 100644
--- a/plugins/catalog-graphql/codegen.yml
+++ b/plugins/catalog-graphql/codegen.yml
@@ -9,7 +9,6 @@ generates:
afterOneFileWrite:
- eslint --fix
config:
- contextType: '@graphql-modules/core#ModuleContext'
allowParentTypeOverride: true
useIndexSignature: true
defaultMapper: Partial<{T}>
diff --git a/plugins/catalog-graphql/package.json b/plugins/catalog-graphql/package.json
index b95e65034c..aac63bee0b 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.2.14",
+ "version": "0.3.0",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -31,23 +31,25 @@
"clean": "backstage-cli clean"
},
"dependencies": {
- "@backstage/catalog-model": "^0.9.7",
- "@backstage/config": "^0.1.11",
+ "@backstage/catalog-model": "^0.9.9",
+ "@backstage/config": "^0.1.12",
"@backstage/types": "^0.1.1",
- "@graphql-modules/core": "^0.7.17",
- "apollo-server": "^2.16.1",
- "graphql": "^15.3.0",
+ "graphql-modules": "^1.0.0",
+ "apollo-server": "^3.0.0",
+ "graphql": "^16.0.0",
"graphql-tag": "^2.11.0",
"graphql-type-json": "^0.3.2",
"node-fetch": "^2.6.1",
"winston": "^3.2.1"
},
"devDependencies": {
- "@backstage/cli": "^0.10.3",
- "@backstage/test-utils": "^0.2.0",
+ "@backstage/cli": "^0.11.0",
+ "@backstage/test-utils": "^0.2.2",
"@graphql-codegen/cli": "^2.3.1",
"@graphql-codegen/typescript": "^2.4.2",
- "@graphql-codegen/typescript-resolvers": "^2.4.2",
+ "@graphql-codegen/typescript-resolvers": "^2.4.3",
+ "@graphql-codegen/graphql-modules-preset": "^2.3.2",
+ "@graphql-tools/schema": "^8.3.1",
"eslint-plugin-graphql": "^4.0.0",
"msw": "^0.35.0"
},
diff --git a/plugins/catalog-graphql/src/graphql/module.test.ts b/plugins/catalog-graphql/src/graphql/module.test.ts
index 3e835b3111..605e9d9aed 100644
--- a/plugins/catalog-graphql/src/graphql/module.test.ts
+++ b/plugins/catalog-graphql/src/graphql/module.test.ts
@@ -15,7 +15,7 @@
*/
import { createModule } from './module';
-import { execute } from 'graphql';
+import { makeExecutableSchema } from '@graphql-tools/schema';
import { rest } from 'msw';
import { setupServer } from 'msw/node';
import { ConfigReader } from '@backstage/config';
@@ -23,6 +23,7 @@ import { ReaderEntity } from '../service/client';
import { createLogger } from 'winston';
import { setupRequestMockHandlers } from '@backstage/test-utils';
import { gql } from 'apollo-server';
+import { Module, createApplication, testkit } from 'graphql-modules';
describe('Catalog Module', () => {
const worker = setupServer();
@@ -33,6 +34,20 @@ describe('Catalog Module', () => {
},
});
+ const createMockApplication = (module: Module) => {
+ const application = createApplication({
+ modules: [module],
+ schemaBuilder(input) {
+ return makeExecutableSchema({
+ ...input,
+ inheritResolversFromInterfaces: true,
+ });
+ },
+ });
+
+ return application;
+ };
+
setupRequestMockHandlers(worker);
describe('Default Entity', () => {
@@ -59,20 +74,21 @@ describe('Catalog Module', () => {
];
worker.use(
- rest.get(`${mockCatalogBaseUrl}/catalog/entities`, (_, res, ctx) =>
+ rest.get(`${mockCatalogBaseUrl}/api/catalog/entities`, (_, res, ctx) =>
res(ctx.status(200), ctx.json(mockResponse)),
),
);
});
it('should call the catalog client when requesting entities', async () => {
- const { schema } = await createModule({
- config: mockConfig,
- logger: createLogger(),
- });
+ const app = createMockApplication(
+ await createModule({
+ config: mockConfig,
+ logger: createLogger(),
+ }),
+ );
- const result = await execute({
- schema,
+ const result = await testkit.execute(app, {
document: gql`
query {
catalog {
@@ -116,18 +132,19 @@ describe('Catalog Module', () => {
},
];
worker.use(
- rest.get(`${mockCatalogBaseUrl}/catalog/entities`, (_, res, ctx) =>
+ rest.get(`${mockCatalogBaseUrl}/api/catalog/entities`, (_, res, ctx) =>
res(ctx.status(200), ctx.json(mockResponse)),
),
);
- const { schema } = await createModule({
- config: mockConfig,
- logger: createLogger(),
- });
+ const app = createMockApplication(
+ await createModule({
+ config: mockConfig,
+ logger: createLogger(),
+ }),
+ );
- const result = await execute({
- schema,
+ const result = await testkit.execute(app, {
document: gql`
query {
catalog {
@@ -167,18 +184,19 @@ describe('Catalog Module', () => {
},
];
worker.use(
- rest.get(`${mockCatalogBaseUrl}/catalog/entities`, (_, res, ctx) =>
+ rest.get(`${mockCatalogBaseUrl}/api/catalog/entities`, (_, res, ctx) =>
res(ctx.status(200), ctx.json(mockResponse)),
),
);
- const { schema } = await createModule({
- config: mockConfig,
- logger: createLogger(),
- });
+ const app = createMockApplication(
+ await createModule({
+ config: mockConfig,
+ logger: createLogger(),
+ }),
+ );
- const result = await execute({
- schema,
+ const result = await testkit.execute(app, {
document: gql`
query {
catalog {
@@ -217,18 +235,19 @@ describe('Catalog Module', () => {
},
];
worker.use(
- rest.get(`${mockCatalogBaseUrl}/catalog/entities`, (_, res, ctx) =>
+ rest.get(`${mockCatalogBaseUrl}/api/catalog/entities`, (_, res, ctx) =>
res(ctx.status(200), ctx.json(mockResponse)),
),
);
- const { schema } = await createModule({
- config: mockConfig,
- logger: createLogger(),
- });
+ const app = createMockApplication(
+ await createModule({
+ config: mockConfig,
+ logger: createLogger(),
+ }),
+ );
- const result = await execute({
- schema,
+ const result = await testkit.execute(app, {
document: gql`
query {
catalog {
@@ -267,18 +286,19 @@ describe('Catalog Module', () => {
},
];
worker.use(
- rest.get(`${mockCatalogBaseUrl}/catalog/entities`, (_, res, ctx) =>
+ rest.get(`${mockCatalogBaseUrl}/api/catalog/entities`, (_, res, ctx) =>
res(ctx.status(200), ctx.json(mockResponse)),
),
);
- const { schema } = await createModule({
- config: mockConfig,
- logger: createLogger(),
- });
+ const app = createMockApplication(
+ await createModule({
+ config: mockConfig,
+ logger: createLogger(),
+ }),
+ );
- const result = await execute({
- schema,
+ const result = await testkit.execute(app, {
document: gql`
query {
catalog {
diff --git a/plugins/catalog-graphql/src/graphql/module.ts b/plugins/catalog-graphql/src/graphql/module.ts
index e7948fb1ed..e33ee429b4 100644
--- a/plugins/catalog-graphql/src/graphql/module.ts
+++ b/plugins/catalog-graphql/src/graphql/module.ts
@@ -15,8 +15,11 @@
*/
import { Logger } from 'winston';
-import { makeExecutableSchema } from 'apollo-server';
-import { GraphQLModule } from '@graphql-modules/core';
+import {
+ createModule as createGraphQLModule,
+ Module,
+ gql,
+} from 'graphql-modules';
import { Resolvers, CatalogQuery } from './types';
import { Config } from '@backstage/config';
import { CatalogClient } from '../service/client';
@@ -29,9 +32,7 @@ export interface ModuleOptions {
config: Config;
}
-export async function createModule(
- options: ModuleOptions,
-): Promise {
+export async function createModule(options: ModuleOptions): Promise {
const catalogClient = new CatalogClient(
options.config.getString('backend.baseUrl'),
);
@@ -62,6 +63,7 @@ export async function createModule(
const {
entity: { kind },
} = rootValue as { entity: Entity };
+
switch (kind) {
case 'Component':
return 'ComponentMetadata';
@@ -94,16 +96,9 @@ export async function createModule(
},
};
- const schema = makeExecutableSchema({
- typeDefs,
+ return createGraphQLModule({
+ id: 'plugin-catalog-graphql',
+ typeDefs: gql(typeDefs),
resolvers,
- inheritResolversFromInterfaces: true,
});
-
- const module = new GraphQLModule({
- extraSchemas: [schema],
- logger: options.logger as any,
- });
-
- return module;
}
diff --git a/plugins/catalog-graphql/src/graphql/types.ts b/plugins/catalog-graphql/src/graphql/types.ts
index 5c53a6d1e3..4dc5a3522b 100644
--- a/plugins/catalog-graphql/src/graphql/types.ts
+++ b/plugins/catalog-graphql/src/graphql/types.ts
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 The Backstage Authors
+ * 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.
@@ -18,12 +18,18 @@ import {
GraphQLScalarType,
GraphQLScalarTypeConfig,
} from 'graphql';
-import { ModuleContext } from '@graphql-modules/core';
export type Maybe = T | null;
+export type InputMaybe = Maybe;
export type Exact = {
[K in keyof T]: T[K];
};
+export type MakeOptional = Omit & {
+ [SubKey in K]?: Maybe;
+};
+export type MakeMaybe = Omit & {
+ [SubKey in K]: Maybe;
+};
export type Omit = Pick>;
export type RequireFields = {
[X in Exclude]?: T[X];
@@ -39,120 +45,6 @@ export type Scalars = {
JSONObject: any;
};
-export type EntityMetadata = {
- name: Scalars['String'];
- annotations: Scalars['JSONObject'];
- annotation?: Maybe;
- labels: Scalars['JSONObject'];
- label?: Maybe;
- uid: Scalars['String'];
- etag: Scalars['String'];
- generation: Scalars['Int'];
-};
-
-export type EntityMetadataAnnotationArgs = {
- name: Scalars['String'];
-};
-
-export type EntityMetadataLabelArgs = {
- name: Scalars['String'];
-};
-
-export type DefaultEntityMetadata = EntityMetadata & {
- __typename?: 'DefaultEntityMetadata';
- name: Scalars['String'];
- annotations: Scalars['JSONObject'];
- annotation?: Maybe;
- labels: Scalars['JSONObject'];
- label?: Maybe;
- uid: Scalars['String'];
- etag: Scalars['String'];
- generation: Scalars['Int'];
-};
-
-export type DefaultEntityMetadataAnnotationArgs = {
- name: Scalars['String'];
-};
-
-export type DefaultEntityMetadataLabelArgs = {
- name: Scalars['String'];
-};
-
-export type ComponentMetadata = EntityMetadata & {
- __typename?: 'ComponentMetadata';
- name: Scalars['String'];
- annotations: Scalars['JSONObject'];
- annotation?: Maybe;
- labels: Scalars['JSONObject'];
- label?: Maybe;
- uid: Scalars['String'];
- etag: Scalars['String'];
- generation: Scalars['Int'];
- relationships?: Maybe;
-};
-
-export type ComponentMetadataAnnotationArgs = {
- name: Scalars['String'];
-};
-
-export type ComponentMetadataLabelArgs = {
- name: Scalars['String'];
-};
-
-export type TemplateMetadata = EntityMetadata & {
- __typename?: 'TemplateMetadata';
- name: Scalars['String'];
- annotations: Scalars['JSONObject'];
- annotation?: Maybe;
- labels: Scalars['JSONObject'];
- label?: Maybe;
- uid: Scalars['String'];
- etag: Scalars['String'];
- generation: Scalars['Int'];
- updatedBy?: Maybe;
-};
-
-export type TemplateMetadataAnnotationArgs = {
- name: Scalars['String'];
-};
-
-export type TemplateMetadataLabelArgs = {
- name: Scalars['String'];
-};
-
-export type TemplateEntitySpec = {
- __typename?: 'TemplateEntitySpec';
- type: Scalars['String'];
- path?: Maybe;
- schema: Scalars['JSONObject'];
- templater: Scalars['String'];
-};
-
-export type ComponentEntitySpec = {
- __typename?: 'ComponentEntitySpec';
- title: Scalars['String'];
- lifecycle: Scalars['String'];
- owner: Scalars['String'];
-};
-
-export type LocationEntitySpec = {
- __typename?: 'LocationEntitySpec';
- type: Scalars['String'];
- target?: Maybe;
- targets: Array;
-};
-
-export type DefaultEntitySpec = {
- __typename?: 'DefaultEntitySpec';
- raw?: Maybe;
-};
-
-export type EntitySpec =
- | DefaultEntitySpec
- | TemplateEntitySpec
- | LocationEntitySpec
- | ComponentEntitySpec;
-
export type CatalogEntity = {
__typename?: 'CatalogEntity';
apiVersion: Scalars['String'];
@@ -166,31 +58,128 @@ export type CatalogQuery = {
list: Array;
};
+export type ComponentEntitySpec = {
+ __typename?: 'ComponentEntitySpec';
+ lifecycle: Scalars['String'];
+ owner: Scalars['String'];
+ type: Scalars['String'];
+};
+
+export type ComponentMetadata = EntityMetadata & {
+ __typename?: 'ComponentMetadata';
+ annotation?: Maybe;
+ annotations: Scalars['JSONObject'];
+ etag: Scalars['String'];
+ generation: Scalars['Int'];
+ label?: Maybe;
+ labels: Scalars['JSONObject'];
+ name: Scalars['String'];
+ relationships?: Maybe;
+ uid: Scalars['String'];
+};
+
+export type ComponentMetadataAnnotationArgs = {
+ name: Scalars['String'];
+};
+
+export type ComponentMetadataLabelArgs = {
+ name: Scalars['String'];
+};
+
+export type DefaultEntityMetadata = EntityMetadata & {
+ __typename?: 'DefaultEntityMetadata';
+ annotation?: Maybe;
+ annotations: Scalars['JSONObject'];
+ etag: Scalars['String'];
+ generation: Scalars['Int'];
+ label?: Maybe;
+ labels: Scalars['JSONObject'];
+ name: Scalars['String'];
+ uid: Scalars['String'];
+};
+
+export type DefaultEntityMetadataAnnotationArgs = {
+ name: Scalars['String'];
+};
+
+export type DefaultEntityMetadataLabelArgs = {
+ name: Scalars['String'];
+};
+
+export type DefaultEntitySpec = {
+ __typename?: 'DefaultEntitySpec';
+ raw?: Maybe;
+};
+
+export type EntityMetadata = {
+ annotation?: Maybe;
+ annotations: Scalars['JSONObject'];
+ etag: Scalars['String'];
+ generation: Scalars['Int'];
+ label?: Maybe;
+ labels: Scalars['JSONObject'];
+ name: Scalars['String'];
+ uid: Scalars['String'];
+};
+
+export type EntityMetadataAnnotationArgs = {
+ name: Scalars['String'];
+};
+
+export type EntityMetadataLabelArgs = {
+ name: Scalars['String'];
+};
+
+export type EntitySpec =
+ | ComponentEntitySpec
+ | DefaultEntitySpec
+ | TemplateEntitySpec;
+
export type Query = {
__typename?: 'Query';
catalog: CatalogQuery;
};
+export type TemplateEntitySpec = {
+ __typename?: 'TemplateEntitySpec';
+ path?: Maybe;
+ schema: Scalars['JSONObject'];
+ templater: Scalars['String'];
+ type: Scalars['String'];
+};
+
+export type TemplateMetadata = EntityMetadata & {
+ __typename?: 'TemplateMetadata';
+ annotation?: Maybe;
+ annotations: Scalars['JSONObject'];
+ etag: Scalars['String'];
+ generation: Scalars['Int'];
+ label?: Maybe;
+ labels: Scalars['JSONObject'];
+ name: Scalars['String'];
+ uid: Scalars['String'];
+ updatedBy?: Maybe;
+};
+
+export type TemplateMetadataAnnotationArgs = {
+ name: Scalars['String'];
+};
+
+export type TemplateMetadataLabelArgs = {
+ name: Scalars['String'];
+};
+
export type WithIndex = TObject & Record;
export type ResolversObject = WithIndex;
export type ResolverTypeWrapper = Promise | T;
-export type LegacyStitchingResolver = {
- fragment: string;
+export type ResolverWithResolve = {
resolve: ResolverFn;
};
-
-export type NewStitchingResolver = {
- selectionSet: string;
- resolve: ResolverFn;
-};
-export type StitchingResolver =
- | LegacyStitchingResolver
- | NewStitchingResolver;
export type Resolver =
| ResolverFn
- | StitchingResolver;
+ | ResolverWithResolve;
export type ResolverFn = (
parent: TParent,
@@ -204,7 +193,7 @@ export type SubscriptionSubscribeFn = (
args: TArgs,
context: TContext,
info: GraphQLResolveInfo,
-) => AsyncIterator | Promise>;
+) => AsyncIterable | Promise>;
export type SubscriptionResolveFn = (
parent: TParent,
@@ -267,8 +256,9 @@ export type TypeResolveFn = (
info: GraphQLResolveInfo,
) => Maybe | Promise>;
-export type IsTypeOfResolverFn = (
+export type IsTypeOfResolverFn = (
obj: T,
+ context: TContext,
info: GraphQLResolveInfo,
) => boolean | Promise;
@@ -289,66 +279,202 @@ export type DirectiveResolverFn<
/** Mapping between all available schema types and the resolvers types */
export type ResolversTypes = ResolversObject<{
- JSON: ResolverTypeWrapper>;
- JSONObject: ResolverTypeWrapper>;
- EntityMetadata:
- | ResolversTypes['DefaultEntityMetadata']
- | ResolversTypes['ComponentMetadata']
- | ResolversTypes['TemplateMetadata'];
- String: ResolverTypeWrapper>;
- Int: ResolverTypeWrapper>;
- DefaultEntityMetadata: ResolverTypeWrapper>;
- ComponentMetadata: ResolverTypeWrapper>;
- TemplateMetadata: ResolverTypeWrapper>;
- TemplateEntitySpec: ResolverTypeWrapper>;
- ComponentEntitySpec: ResolverTypeWrapper>;
- LocationEntitySpec: ResolverTypeWrapper>;
- DefaultEntitySpec: ResolverTypeWrapper>;
- EntitySpec: Partial<
- | ResolversTypes['DefaultEntitySpec']
- | ResolversTypes['TemplateEntitySpec']
- | ResolversTypes['LocationEntitySpec']
- | ResolversTypes['ComponentEntitySpec']
- >;
+ Boolean: ResolverTypeWrapper>;
CatalogEntity: ResolverTypeWrapper<
Partial<
Omit & { spec: ResolversTypes['EntitySpec'] }
>
>;
CatalogQuery: ResolverTypeWrapper>;
+ ComponentEntitySpec: ResolverTypeWrapper>;
+ ComponentMetadata: ResolverTypeWrapper>;
+ DefaultEntityMetadata: ResolverTypeWrapper>;
+ DefaultEntitySpec: ResolverTypeWrapper>;
+ EntityMetadata:
+ | ResolversTypes['ComponentMetadata']
+ | ResolversTypes['DefaultEntityMetadata']
+ | ResolversTypes['TemplateMetadata'];
+ EntitySpec: Partial<
+ | ResolversTypes['ComponentEntitySpec']
+ | ResolversTypes['DefaultEntitySpec']
+ | ResolversTypes['TemplateEntitySpec']
+ >;
+ Int: ResolverTypeWrapper>;
+ JSON: ResolverTypeWrapper>;
+ JSONObject: ResolverTypeWrapper>;
Query: ResolverTypeWrapper<{}>;
- Boolean: ResolverTypeWrapper>;
+ String: ResolverTypeWrapper>;
+ TemplateEntitySpec: ResolverTypeWrapper>;
+ TemplateMetadata: ResolverTypeWrapper>;
}>;
/** Mapping between all available schema types and the resolvers parents */
export type ResolversParentTypes = ResolversObject<{
- JSON: Partial;
- JSONObject: Partial;
- EntityMetadata:
- | ResolversParentTypes['DefaultEntityMetadata']
- | ResolversParentTypes['ComponentMetadata']
- | ResolversParentTypes['TemplateMetadata'];
- String: Partial;
- Int: Partial;
- DefaultEntityMetadata: Partial;
- ComponentMetadata: Partial;
- TemplateMetadata: Partial;
- TemplateEntitySpec: Partial;
- ComponentEntitySpec: Partial;
- LocationEntitySpec: Partial;
- DefaultEntitySpec: Partial;
- EntitySpec: Partial<
- | ResolversParentTypes['DefaultEntitySpec']
- | ResolversParentTypes['TemplateEntitySpec']
- | ResolversParentTypes['LocationEntitySpec']
- | ResolversParentTypes['ComponentEntitySpec']
- >;
+ Boolean: Partial;
CatalogEntity: Partial<
Omit & { spec: ResolversParentTypes['EntitySpec'] }
>;
CatalogQuery: Partial;
+ ComponentEntitySpec: Partial;
+ ComponentMetadata: Partial;
+ DefaultEntityMetadata: Partial;
+ DefaultEntitySpec: Partial;
+ EntityMetadata:
+ | ResolversParentTypes['ComponentMetadata']
+ | ResolversParentTypes['DefaultEntityMetadata']
+ | ResolversParentTypes['TemplateMetadata'];
+ EntitySpec: Partial<
+ | ResolversParentTypes['ComponentEntitySpec']
+ | ResolversParentTypes['DefaultEntitySpec']
+ | ResolversParentTypes['TemplateEntitySpec']
+ >;
+ Int: Partial;
+ JSON: Partial;
+ JSONObject: Partial;
Query: {};
- Boolean: Partial;
+ String: Partial;
+ TemplateEntitySpec: Partial;
+ TemplateMetadata: Partial;
+}>;
+
+export type CatalogEntityResolvers<
+ ContextType = any,
+ ParentType = ResolversParentTypes['CatalogEntity'],
+> = ResolversObject<{
+ apiVersion?: Resolver;
+ kind?: Resolver;
+ metadata?: Resolver<
+ Maybe,
+ ParentType,
+ ContextType
+ >;
+ spec?: Resolver;
+ __isTypeOf?: IsTypeOfResolverFn;
+}>;
+
+export type CatalogQueryResolvers<
+ ContextType = any,
+ ParentType = ResolversParentTypes['CatalogQuery'],
+> = ResolversObject<{
+ list?: Resolver<
+ Array,
+ ParentType,
+ ContextType
+ >;
+ __isTypeOf?: IsTypeOfResolverFn;
+}>;
+
+export type ComponentEntitySpecResolvers<
+ ContextType = any,
+ ParentType = ResolversParentTypes['ComponentEntitySpec'],
+> = ResolversObject<{
+ lifecycle?: Resolver;
+ owner?: Resolver;
+ type?: Resolver;
+ __isTypeOf?: IsTypeOfResolverFn;
+}>;
+
+export type ComponentMetadataResolvers<
+ ContextType = any,
+ ParentType = ResolversParentTypes['ComponentMetadata'],
+> = ResolversObject<{
+ annotation?: Resolver<
+ Maybe,
+ ParentType,
+ ContextType,
+ RequireFields
+ >;
+ annotations?: Resolver;
+ etag?: Resolver;
+ generation?: Resolver;
+ label?: Resolver<
+ Maybe,
+ ParentType,
+ ContextType,
+ RequireFields
+ >;
+ labels?: Resolver;
+ name?: Resolver;
+ relationships?: Resolver<
+ Maybe,
+ ParentType,
+ ContextType
+ >;
+ uid?: Resolver;
+ __isTypeOf?: IsTypeOfResolverFn;
+}>;
+
+export type DefaultEntityMetadataResolvers<
+ ContextType = any,
+ ParentType = ResolversParentTypes['DefaultEntityMetadata'],
+> = ResolversObject<{
+ annotation?: Resolver<
+ Maybe,
+ ParentType,
+ ContextType,
+ RequireFields