,
+ ),
+ ];
+ },
+});
+```
diff --git a/.changeset/rare-peas-dream.md b/.changeset/rare-peas-dream.md
deleted file mode 100644
index 443f8c566d..0000000000
--- a/.changeset/rare-peas-dream.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/backend-defaults': patch
----
-
-Repack the package to fix issues with typescript with named exports
diff --git a/.changeset/real-lizards-sit.md b/.changeset/real-lizards-sit.md
new file mode 100644
index 0000000000..747f041508
--- /dev/null
+++ b/.changeset/real-lizards-sit.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-scaffolder': patch
+---
+
+Fix undefined in the title of Scaffolder Runs on the page load
diff --git a/.changeset/red-radios-promise.md b/.changeset/red-radios-promise.md
new file mode 100644
index 0000000000..ea876c3480
--- /dev/null
+++ b/.changeset/red-radios-promise.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-catalog-backend-module-gitlab': patch
+---
+
+Adds new optional `excludeRepos` configuration option to the Gitlab catalog provider.
diff --git a/.changeset/renovate-147ac48.md b/.changeset/renovate-147ac48.md
new file mode 100644
index 0000000000..257255dff1
--- /dev/null
+++ b/.changeset/renovate-147ac48.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-api-docs': patch
+---
+
+Updated dependency `@graphiql/react` to `^0.23.0`.
diff --git a/.changeset/renovate-f04beb1.md b/.changeset/renovate-f04beb1.md
new file mode 100644
index 0000000000..12d24ccc53
--- /dev/null
+++ b/.changeset/renovate-f04beb1.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-search-backend-module-explore': patch
+---
+
+Updated dependency `@backstage-community/plugin-explore-common` to `^0.0.4`.
diff --git a/.changeset/rich-bears-march.md b/.changeset/rich-bears-march.md
deleted file mode 100644
index ec4a4a9404..0000000000
--- a/.changeset/rich-bears-march.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@techdocs/cli': patch
----
-
-Import discovery from backend-defaults instead of backend-common
diff --git a/.changeset/rich-mugs-dress.md b/.changeset/rich-mugs-dress.md
new file mode 100644
index 0000000000..5008e33a70
--- /dev/null
+++ b/.changeset/rich-mugs-dress.md
@@ -0,0 +1,7 @@
+---
+'@backstage/config-loader': patch
+---
+
+Add boolean `allowMissingDefaultConfig` option to `ConfigSources.default` and
+`ConfigSources.defaultForTargets`, which results in omission of a ConfigSource
+for the default app-config.yaml configuration file if it's not present.
diff --git a/.changeset/selfish-bees-think.md b/.changeset/selfish-bees-think.md
new file mode 100644
index 0000000000..15598ea551
--- /dev/null
+++ b/.changeset/selfish-bees-think.md
@@ -0,0 +1,5 @@
+---
+'@backstage/backend-defaults': patch
+---
+
+Fixed the routing of the new health check service, the health endpoints should now properly be available at `/.backstage/health/v1/readiness` and `/.backstage/health/v1/liveness`.
diff --git a/.changeset/seven-days-film.md b/.changeset/seven-days-film.md
new file mode 100644
index 0000000000..9d757b0611
--- /dev/null
+++ b/.changeset/seven-days-film.md
@@ -0,0 +1,5 @@
+---
+'@backstage/backend-plugin-api': patch
+---
+
+Fixed a type issue where plugin and modules depending on multiton services would not receive the correct type.
diff --git a/.changeset/seven-eggs-admire.md b/.changeset/seven-eggs-admire.md
new file mode 100644
index 0000000000..d68b38e2d7
--- /dev/null
+++ b/.changeset/seven-eggs-admire.md
@@ -0,0 +1,5 @@
+---
+'@backstage/create-app': patch
+---
+
+Updated dockerfile and `app-config.production.yaml` to make it easier to get started with example data
diff --git a/.changeset/shaggy-dodos-applaud.md b/.changeset/shaggy-dodos-applaud.md
new file mode 100644
index 0000000000..b7f968aa39
--- /dev/null
+++ b/.changeset/shaggy-dodos-applaud.md
@@ -0,0 +1,5 @@
+---
+'@backstage/cli': patch
+---
+
+Switched the target from `'ES2022'` to `'es2022'` for better compatibility with older versions of `swc`.
diff --git a/.changeset/shaggy-mugs-return.md b/.changeset/shaggy-mugs-return.md
new file mode 100644
index 0000000000..6af5d1d18f
--- /dev/null
+++ b/.changeset/shaggy-mugs-return.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-techdocs-backend': patch
+---
+
+Update configuration schema to match actual behavior
diff --git a/.changeset/shy-games-poke.md b/.changeset/shy-games-poke.md
new file mode 100644
index 0000000000..1d2abff39c
--- /dev/null
+++ b/.changeset/shy-games-poke.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-notifications-backend-module-email': patch
+---
+
+Add support for stream transport for debugging purposes
diff --git a/.changeset/shy-waves-share.md b/.changeset/shy-waves-share.md
new file mode 100644
index 0000000000..861590fd01
--- /dev/null
+++ b/.changeset/shy-waves-share.md
@@ -0,0 +1,5 @@
+---
+'@backstage/backend-defaults': patch
+---
+
+Update the `UrlReader` service to depends on multiple instances of `UrlReaderFactoryProvider` service.
diff --git a/.changeset/silent-experts-move.md b/.changeset/silent-experts-move.md
deleted file mode 100644
index 06441a62c6..0000000000
--- a/.changeset/silent-experts-move.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/cli': patch
----
-
-Subpath export `package.json` should be of a unique name to avoid typescript resolution issues
diff --git a/.changeset/silly-candles-sin.md b/.changeset/silly-candles-sin.md
new file mode 100644
index 0000000000..b1d55113fd
--- /dev/null
+++ b/.changeset/silly-candles-sin.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-techdocs': patch
+---
+
+TechDocs now supports the `mkdocs-redirects` plugin. Redirects defined using the `mkdocs-redirect` plugin will be handled automatically in TechDocs. Redirecting to external urls is not supported. In the case that an external redirect url is provided, TechDocs will redirect to the current documentation site home.
diff --git a/.changeset/silly-cycles-tan.md b/.changeset/silly-cycles-tan.md
new file mode 100644
index 0000000000..517ce526ea
--- /dev/null
+++ b/.changeset/silly-cycles-tan.md
@@ -0,0 +1,6 @@
+---
+'@backstage/plugin-kubernetes-backend': patch
+---
+
+Add `kubernetes.clusterLocatorMethods[].clusters[].customResources` to the configuration schema.
+This was already documented and supported by the plugin.
diff --git a/.changeset/silly-scissors-turn.md b/.changeset/silly-scissors-turn.md
new file mode 100644
index 0000000000..985a6fb4fd
--- /dev/null
+++ b/.changeset/silly-scissors-turn.md
@@ -0,0 +1,5 @@
+---
+'@backstage/create-app': patch
+---
+
+Included permission config and enabled it out of the box
diff --git a/.changeset/silver-pillows-begin.md b/.changeset/silver-pillows-begin.md
new file mode 100644
index 0000000000..8fe1ccc230
--- /dev/null
+++ b/.changeset/silver-pillows-begin.md
@@ -0,0 +1,5 @@
+---
+'@backstage/backend-common': patch
+---
+
+Internal type refactor.
diff --git a/.changeset/six-mails-smell.md b/.changeset/six-mails-smell.md
new file mode 100644
index 0000000000..3845c72626
--- /dev/null
+++ b/.changeset/six-mails-smell.md
@@ -0,0 +1,5 @@
+---
+'@backstage/frontend-plugin-api': patch
+---
+
+Support merging of `inputs` in extension blueprints, but stop merging `output`. In addition, the original factory in extension blueprints now returns a data container that both provides access to the returned data, but can also be forwarded as output.
diff --git a/.changeset/six-rats-kick.md b/.changeset/six-rats-kick.md
new file mode 100644
index 0000000000..23958a2502
--- /dev/null
+++ b/.changeset/six-rats-kick.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-scaffolder-backend-module-gitlab': patch
+---
+
+Added test cases for gitlab:projectAccessToken:create example
diff --git a/.changeset/slow-ducks-rush.md b/.changeset/slow-ducks-rush.md
new file mode 100644
index 0000000000..c09f883e9c
--- /dev/null
+++ b/.changeset/slow-ducks-rush.md
@@ -0,0 +1,5 @@
+---
+'@backstage/core-compat-api': patch
+---
+
+Both `compatWrapper` and `convertLegacyRouteRef` now support converting from the new system to the old.
diff --git a/.changeset/slow-ligers-drum.md b/.changeset/slow-ligers-drum.md
new file mode 100644
index 0000000000..867cc07cee
--- /dev/null
+++ b/.changeset/slow-ligers-drum.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-scaffolder-react': patch
+---
+
+Fix null check in `isJsonObject` utility function for scaffolder review state component
diff --git a/.changeset/slow-toes-jog.md b/.changeset/slow-toes-jog.md
new file mode 100644
index 0000000000..245feab544
--- /dev/null
+++ b/.changeset/slow-toes-jog.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-home': patch
+---
+
+Fixed a bug on the WelcomeTitle component where the welcome message wasn't correct when the language was set to Spanish
diff --git a/.changeset/small-bottles-cough.md b/.changeset/small-bottles-cough.md
new file mode 100644
index 0000000000..40098a84c7
--- /dev/null
+++ b/.changeset/small-bottles-cough.md
@@ -0,0 +1,58 @@
+---
+'@backstage/backend-plugin-api': minor
+---
+
+The `createServiceRef` function now accepts a new boolean `multiple` option. The `multiple` option defaults to `false` and when set to `true`, it enables that multiple implementation are installed for the created service ref.
+
+We're looking for ways to make it possible to augment services without the need to replace the entire service.
+
+Typical example of that being the ability to install support for additional targets for the `UrlReader` service without replacing the service itself. This achieves that by allowing us to define services that can have multiple simultaneous implementation, allowing the `UrlReader` implementation to depend on such a service to collect all possible implementation of support for external targets:
+
+```diff
+// @backstage/backend-defaults
+
++ export const urlReaderFactoriesServiceRef = createServiceRef({
++ id: 'core.urlReader.factories',
++ scope: 'plugin',
++ multiton: true,
++ });
+
+...
+
+export const urlReaderServiceFactory = createServiceFactory({
+ service: coreServices.urlReader,
+ deps: {
+ config: coreServices.rootConfig,
+ logger: coreServices.logger,
++ factories: urlReaderFactoriesServiceRef,
+ },
+- async factory({ config, logger }) {
++ async factory({ config, logger, factories }) {
+ return UrlReaders.default({
+ config,
+ logger,
++ factories,
+ });
+ },
+});
+```
+
+With that, you can then add more custom `UrlReader` factories by installing more implementations of the `urlReaderFactoriesServiceRef` in your backend instance. Something like:
+
+```ts
+// packages/backend/index.ts
+import { createServiceFactory } from '@backstage/backend-plugin-api';
+import { urlReaderFactoriesServiceRef } from '@backstage/backend-defaults';
+...
+
+backend.add(createServiceFactory({
+ service: urlReaderFactoriesServiceRef,
+ deps: {},
+ async factory() {
+ return CustomUrlReader.factory;
+ },
+}));
+
+...
+
+```
diff --git a/.changeset/small-ears-poke.md b/.changeset/small-ears-poke.md
new file mode 100644
index 0000000000..de906a8643
--- /dev/null
+++ b/.changeset/small-ears-poke.md
@@ -0,0 +1,7 @@
+---
+'@backstage/frontend-plugin-api': minor
+---
+
+**BREAKING**: All types of route refs are always considered optional by `useRouteRef`, which means the caller must always handle a potential `undefined` return value. Related to this change, the `optional` option from `createExternalRouteRef` has been removed, since it is no longer necessary.
+
+This is released as an immediate breaking change as we expect the usage of the new route refs to be extremely low or zero, since plugins that support the new system will still use route refs and `useRouteRef` from `@backstage/core-plugin-api` in combination with `convertLegacyRouteRef` from `@backstage/core-compat-api`.
diff --git a/.changeset/small-spoons-shout.md b/.changeset/small-spoons-shout.md
new file mode 100644
index 0000000000..76c209edc6
--- /dev/null
+++ b/.changeset/small-spoons-shout.md
@@ -0,0 +1,13 @@
+---
+'@backstage/cli': minor
+---
+
+**BREAKING**: The lockfile (`yarn.lock`) dependency analysis and mutations have been removed from several commands.
+
+The `versions:bump` command will no longer attempt to bump and deduplicate dependencies by modifying the lockfile, it will only update `package.json` files.
+
+The `versions:check` command has been removed, since its only purpose was verification and mutation of the lockfile. We recommend using the `yarn dedupe` command instead, or the `yarn-deduplicate` package if you're using Yarn classic.
+
+The check that was built into the `package start` command has been removed, it will no longer warn about lockfile mismatches.
+
+The packages in the Backstage ecosystem handle package duplications much better now than when these CLI features were first introduced, so the need for these features has diminished. By removing them, we drastically reduce the integration between the Backstage CLI and Yarn, making it much easier to add support for other package managers in the future.
diff --git a/.changeset/smooth-countries-relate.md b/.changeset/smooth-countries-relate.md
new file mode 100644
index 0000000000..5e86ee8ab5
--- /dev/null
+++ b/.changeset/smooth-countries-relate.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-catalog-graph': patch
+---
+
+Use `entityPresentationApi` for the node title and the icon.
diff --git a/.changeset/soft-clocks-bake.md b/.changeset/soft-clocks-bake.md
deleted file mode 100644
index 29d7658869..0000000000
--- a/.changeset/soft-clocks-bake.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@backstage/plugin-catalog': patch
----
-
-Added small notes to AboutCard to discourage customizability PRs
diff --git a/.changeset/soft-gorillas-refuse.md b/.changeset/soft-gorillas-refuse.md
new file mode 100644
index 0000000000..323c4d20d2
--- /dev/null
+++ b/.changeset/soft-gorillas-refuse.md
@@ -0,0 +1,5 @@
+---
+'@backstage/backend-test-utils': patch
+---
+
+The default services for `startTestBackend` and `ServiceFactoryTester` now includes the Root Health Service.
diff --git a/.changeset/spicy-lies-listen.md b/.changeset/spicy-lies-listen.md
new file mode 100644
index 0000000000..6bc5e95846
--- /dev/null
+++ b/.changeset/spicy-lies-listen.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-scaffolder': patch
+---
+
+Fix helper text margin for scaffolder EntityNamePicker and EntityTagsPicker when using outlined text field
diff --git a/.changeset/spicy-planets-provide.md b/.changeset/spicy-planets-provide.md
new file mode 100644
index 0000000000..f2929df850
--- /dev/null
+++ b/.changeset/spicy-planets-provide.md
@@ -0,0 +1,46 @@
+---
+'@backstage/plugin-notifications-backend-module-email': minor
+---
+
+**BREAKING** Following `NotificationTemplateRenderer` methods now return a Promise and **must** be awaited: `getSubject`, `getText` and `getHtml`.
+
+Required changes and example usage:
+
+```diff
+import { notificationsEmailTemplateExtensionPoint } from '@backstage/plugin-notifications-backend-module-email';
+import { Notification } from '@backstage/plugin-notifications-common';
++import { getNotificationSubject, getNotificationTextContent, getNotificationHtmlContent } from 'my-notification-processing-library`
+export const notificationsModuleEmailDecorator = createBackendModule({
+ pluginId: 'notifications',
+ moduleId: 'email.templates',
+ register(reg) {
+ reg.registerInit({
+ deps: {
+ emailTemplates: notificationsEmailTemplateExtensionPoint,
+ },
+ async init({ emailTemplates }) {
+ emailTemplates.setTemplateRenderer({
+- getSubject(notification) {
++ async getSubject(notification) {
+- return `New notification from ${notification.source}`;
++ const subject = await getNotificationSubject(notification);
++ return `New notification from ${subject}`;
+ },
+- getText(notification) {
++ async getText(notification) {
+- return notification.content;
++ const text = await getNotificationTextContent(notification);
++ return text;
+ },
+- getHtml(notification) {
++ async getHtml(notification) {
+- return `
);
};
```
-We use the `useRouteRef` hook to create a link generator function that returns the details page path. We then call the link generator, passing it an object with the kind, namespace, and name. These parameters are used to construct a concrete path to the "Foo" details page.
+We use the `useRouteRef` hook to create a link generator function that returns the details page path. First we need to check whether the route is available, the link generator function will be `undefined` if it isn't. We then call the link generator, passing it an object with the kind, namespace, and name. These parameters are used to construct a concrete path to the "Foo" details page.
Let's see how the details page can get the parameters from the URL:
@@ -176,8 +179,11 @@ export const IndexPage = () => {
return (
);
};
@@ -289,42 +295,6 @@ export const createComponentExternalRouteRef = createExternalRouteRef({
});
```
-### Optional External Route References
-
-It is possible to define an `ExternalRouteRef` as optional, so it is not required to bind it in the app.
-
-```tsx title="plugins/catalog/src/routes.ts"
-import { createExternalRouteRef } from '@backstage/frontend-plugin-api';
-
-export const createComponentExternalRouteRef = createExternalRouteRef({
- // highlight-next-line
- optional: true,
-});
-```
-
-When calling `useRouteRef` with an optional external route, its return signature is changed to `RouteFunc | undefined`, and the returned value can be used to decide whether a certain link should be displayed or if an action should be taken:
-
-```tsx title="plugins/catalog/src/components/IndexPage.tsx"
-import React from 'react';
-import { useRouteRef } from '@backstage/frontend-plugin-api';
-import { createComponentExternalRouteRef } from '../routes';
-
-export const IndexPage = () => {
- const getCreateComponentPath = useRouteRef(createComponentExternalRouteRef);
- return (
-
-
Index Page
- {/* Rendering the link only if the getCreateComponentPath is defined */}
- {/* highlight-start */}
- {getCreateComponentPath && (
- Create Component
- )}
- {/* highlight-end */}
-
- );
-};
-```
-
## Sub Route References
The last kind of route ref that can be created is a `SubRouteRef`, which can be used to create a route ref with a fixed path relative to an absolute `RouteRef`. They are useful if you have a page that internally is mounted at a sub route of a page extension component, and you want other plugins to be able to route to that page. And they can be a useful utility to handle routing within a plugin itself as well.
@@ -359,7 +329,7 @@ export const detailsSubRouteRef = createSubRouteRef({
Using subroutes in a page extension is as simple as this:
-```tsx title="plugins/catalog/src/components/IndexPage.ts"
+```tsx title="plugins/catalog/src/components/IndexPage.tsx"
import React from 'react';
import { Routes, Route, useLocation } from 'react-router-dom';
import { useRouteRef } from '@backstage/frontend-plugin-api';
@@ -368,17 +338,21 @@ import { DetailsPage } from './DetailsPage';
export const IndexPage = () => {
const { pathname } = useLocation();
+
+ // highlight-start
const getIndexPath = useRouteRef(indexRouteRef);
const getDetailsPath = useRouteRef(detailsSubRouteRef);
+ // highlight-end
+
return (
@@ -402,7 +377,7 @@ export const IndexPage = () => {
This is how you can get the parameters of a sub route URL:
-```tsx title="plugins/catalog/src/components/DetailsPage.ts"
+```tsx title="plugins/catalog/src/components/DetailsPage.tsx"
import React from 'react';
import { useParams } from 'react-router-dom';
@@ -426,7 +401,7 @@ export const DetailsPage = () => {
Finally, see how a plugin can provide subroutes:
-```tsx title="plugins/catalog/src/plugin.ts"
+```tsx title="plugins/catalog/src/plugin.tsx"
import React from 'react';
import {
createPlugin,
diff --git a/docs/frontend-system/architecture/08-naming-patterns.md b/docs/frontend-system/architecture/08-naming-patterns.md
index 0916d9fd51..f031b80d84 100644
--- a/docs/frontend-system/architecture/08-naming-patterns.md
+++ b/docs/frontend-system/architecture/08-naming-patterns.md
@@ -38,33 +38,31 @@ Note that while we use this naming pattern for the plugin instance this is only
| Description | Pattern | Examples |
| ----------- | ------------------------------- | ------------------------------------------------------------------- |
-| Creator | `createExtension` | `createPageExtension`, `createEntityCardExtension` |
+| Blueprint | `Blueprint` | `PageBlueprint`, `EntityCardBlueprint` |
| ID | `[:][/]` | `'core.nav'`, `'page:user-settings'`, `'entity-card:catalog/about'` |
| Symbol | `[][]` | `coreNav`, `userSettingsPage`, `catalogAboutEntityCard` |
-When you create a new extension you never provide the ID directly. Instead, you indirectly or directly provide the kind, namespace, and name parts that make up the ID. The kind is always provided by the extension creator function used to create the extension, the only exception is if you use `createExtension` directly. Any extension that is provided by a plugin will by default have its namespace set to the plugin ID, so you generally only need to provide an explicit namespace if you want to override an existing extension. The name is also optional, and primarily used to distinguish between multiple extensions of the same kind and namespace. If a plugin doesn't need to distinguish between different extensions of the same kind, the name can be omitted.
+When you create a new extension you never provide the ID directly. Instead, you indirectly or directly provide the kind, namespace, and name parts that make up the ID. The kind is always provided by the blueprint creator, the only exception is if you use `createExtension` directly. Any extension that is provided by a plugin will by default have its namespace set to the plugin ID, so you generally only need to provide an explicit namespace if you want to override an existing extension. The name is also optional, and primarily used to distinguish between multiple extensions of the same kind and namespace. If a plugin doesn't need to distinguish between different extensions of the same kind, the name can be omitted.
Example:
```ts
-// This is an extension creator that is used to create an extension of the 'page' kind.
-export function createPageExtension(options) {
- return createExtension({
- kind: 'page', // Kinds are kebab-case
- // ...options
- });
-}
+// This is an extension blueprint that is used to create an extension of the 'page' kind.
+export const PageBlueprint = createExtensionBlueprint({
+ kind: 'page',
+ // ...
+});
// The namespace is inferred from the plugin ID, in this case 'catalog'
// The final ID for this extension will be 'page:catalog/entity'
-const catalogEntityPage = createPageExtension({
+const catalogEntityPage = PageBlueprint.make({
name: 'entity',
// ...
});
// The name is omitted, because the catalog plugin only provides a single extension of this kind
// The final ID for this extension will be 'search-result-list-item:catalog'
-const catalogSearchResultListItem = createSearchResultListItemExtension({
+const catalogSearchResultListItem = SearchResultListItemBlueprint.make({
// ...
});
@@ -100,9 +98,9 @@ export interface SearchResultItemExtensionData {
}
export const searchResultItemExtensionDataRef =
- createExtensionDataRef(
- 'search.search-result-item',
- );
+ createExtensionDataRef().with({
+ id: 'search.search-result-item',
+ });
```
#### Grouped Extension Data
@@ -111,8 +109,12 @@ This way of defining extension data is similar to the standalone way, but it use
```ts
export const coreExtensionData = {
- reactElement: createExtensionDataRef('core.react-element'),
- routePath: createExtensionDataRef('core.route-path'),
+ reactElement: createExtensionDataRef().with({
+ id: 'core.react-element',
+ }),
+ routePath: createExtensionDataRef().with({
+ id: 'core.route-path',
+ }),
};
```
@@ -127,9 +129,9 @@ export function createGraphiQLEndpointExtension(options) {
// Use a TypeScript namespace to merge the extension data references with the extension creator
export namespace createGraphiQLEndpointExtension {
- export const endpointDataRef = createExtensionDataRef* ... */>(
- 'graphiql.graphiql-endpoint.endpoint',
- );
+ export const endpointDataRef = createExtensionDataRef* ... */>().with({
+ id: 'graphiql.graphiql-endpoint.endpoint',
+ });
}
```
diff --git a/docs/frontend-system/building-apps/03-built-in-extensions.md b/docs/frontend-system/building-apps/03-built-in-extensions.md
index 4f8417f74f..a5e6476eb0 100644
--- a/docs/frontend-system/building-apps/03-built-in-extensions.md
+++ b/docs/frontend-system/building-apps/03-built-in-extensions.md
@@ -45,6 +45,7 @@ This extension is the first extension attached to the extension tree. It is resp
| themes | The app themes list. | [createThemeExtension.themeDataRef](https://backstage.io/docs/reference/frontend-plugin-api.createthemeextension.themedataref) | false | See [default themes](#default-theme-extensions). | [createThemeExtension](https://backstage.io/docs/reference/frontend-plugin-api.createthemeextension) |
| components | The app components list. | [createComponentExtension.componentDataRef](https://backstage.io/docs/reference/frontend-plugin-api.createcomponentextension.componentdataref) | false | See [default components](#default-components-extensions). | [createComponentExtension](https://backstage.io/docs/reference/frontend-plugin-api.createcomponentextension) |
| translations | The app translations list. | [createTranslationExtension.translationDataRef](https://backstage.io/docs/reference/frontend-plugin-api.createtranslationextension.translationdataref) | false | - | [createTranslationExtension](https://backstage.io/docs/reference/frontend-plugin-api.createtranslationextension) |
+| icons | The app icons list. | [IconBundleBlueprint.dataRefs.icons](https://backstage.io/docs/reference/frontend-plugin-api.iconbundleblueprint.dataRefs.icons) | true | - | [IconBundleBlueprint](https://backstage.io/docs/reference/frontend-plugin-api.iconbundleblueprint) |
#### Default theme extensions
diff --git a/docs/frontend-system/building-apps/08-migrating.md b/docs/frontend-system/building-apps/08-migrating.md
index 0abdd2aac3..716e0da772 100644
--- a/docs/frontend-system/building-apps/08-migrating.md
+++ b/docs/frontend-system/building-apps/08-migrating.md
@@ -314,6 +314,31 @@ const app = createApp({
});
```
+### `icons`
+
+Icons are now installed as extensions, using the `IconBundleBlueprint` to make new instances which can be added to the app.
+
+```ts
+import { IconBundleBlueprint } from '@backstage/frontend-plugin-api';
+
+const exampleIconBundle = IconBundleBlueprint.make({
+ name: 'example-bundle',
+ params: {
+ icons: {
+ user: MyOwnUserIcon,
+ },
+ },
+});
+
+const app = createApp({
+ features: [
+ createExtensionOverrides({
+ extensions: [exampleIconBundle],
+ }),
+ ],
+});
+```
+
### `bindRoutes`
Route bindings can still be done using this option, but you now also have the ability to bind routes using static configuration instead. See the section on [binding routes](../architecture/07-routes.md#binding-external-route-references) for more information.
diff --git a/docs/frontend-system/building-plugins/03-extension-types.md b/docs/frontend-system/building-plugins/03-extension-types.md
index 2bea073ed6..1f3baaa710 100644
--- a/docs/frontend-system/building-plugins/03-extension-types.md
+++ b/docs/frontend-system/building-plugins/03-extension-types.md
@@ -38,6 +38,10 @@ Sign-in page extension have a single purpose - to implement a custom sign-in pag
Theme extensions provide custom themes for the app. They are always attached to the app extension and you can have any number of themes extensions installed in an app at once, letting the user choose which theme to use.
+### Icons - [Reference](../../reference/frontend-plugin-api.iconbundleblueprint.md)
+
+Icon bundle extensions provide the ability to replace or provide new icons to the app. You can use the above blueprint to make new extension instances which can be installed into the app.
+
### Translation - [Reference](../../reference/frontend-plugin-api.createtranslationextension.md)
Translation extension provide custom translation messages for the app. They can be used both to override the default english messages to custom ones, as well as provide translations for additional languages.
diff --git a/docs/getting-started/app-custom-theme.md b/docs/getting-started/app-custom-theme.md
index 3fb0365ad0..4c013440da 100644
--- a/docs/getting-started/app-custom-theme.md
+++ b/docs/getting-started/app-custom-theme.md
@@ -64,7 +64,7 @@ const app = createApp({
})
```
-Note that your list of custom themes overrides the default themes. If you still want to use the default themes, they are exported as `themes.light` and `themes.light` from [`@backstage/theme`](https://www.npmjs.com/package/@backstage/theme).
+Note that your list of custom themes overrides the default themes. If you still want to use the default themes, they are exported as `themes.light` and `themes.dark` from [`@backstage/theme`](https://www.npmjs.com/package/@backstage/theme).
## Example of a custom theme
diff --git a/docs/getting-started/config/authentication.md b/docs/getting-started/config/authentication.md
index 874964696a..e97ed3d89c 100644
--- a/docs/getting-started/config/authentication.md
+++ b/docs/getting-started/config/authentication.md
@@ -50,7 +50,6 @@ Open `packages/app/src/App.tsx` and below the last `import` line, add:
```typescript title="packages/app/src/App.tsx"
import { githubAuthApiRef } from '@backstage/core-plugin-api';
-import { SignInPage } from '@backstage/core-components';
```
Search for `const app = createApp({` in this file, and below `apis,` add:
diff --git a/docs/getting-started/config/database.md b/docs/getting-started/config/database.md
index a560fe507b..0fbd66d5a3 100644
--- a/docs/getting-started/config/database.md
+++ b/docs/getting-started/config/database.md
@@ -73,8 +73,7 @@ to install and configure the client.
Go to the root directory of your freshly installed Backstage
App. Run the following to install the PostgreSQL client into your backend:
-```bash
-# From your Backstage root directory
+```bash title="From your Backstage root directory"
yarn --cwd packages/backend add pg
```
diff --git a/docs/getting-started/configure-app-with-plugins.md b/docs/getting-started/configure-app-with-plugins.md
index 2fdb016e7b..95fd456dc0 100644
--- a/docs/getting-started/configure-app-with-plugins.md
+++ b/docs/getting-started/configure-app-with-plugins.md
@@ -21,8 +21,7 @@ to an entity in the software catalog.
1. Add the plugin's npm package to the repo:
- ```bash
- # From your Backstage root directory
+ ```bash title="From your Backstage root directory"
yarn --cwd packages/app add @circleci/backstage-plugin
```
diff --git a/docs/getting-started/homepage.md b/docs/getting-started/homepage.md
index 7e1a2ed909..d7c9b46faa 100644
--- a/docs/getting-started/homepage.md
+++ b/docs/getting-started/homepage.md
@@ -28,8 +28,7 @@ Now, let's get started by installing the home plugin and creating a simple homep
#### 1. Install the plugin
-```bash
-# From your Backstage root directory
+```bash title="From your Backstage root directory"
yarn --cwd packages/app add @backstage/plugin-home
```
diff --git a/docs/getting-started/index.md b/docs/getting-started/index.md
index 99fdb3d8ed..8bb30d1db8 100644
--- a/docs/getting-started/index.md
+++ b/docs/getting-started/index.md
@@ -1,6 +1,6 @@
---
id: index
-title: Installing a standalone server
+title: Creating your Backstage App
sidebar_label: Introduction
description: How to install Backstage for your own use.
---
diff --git a/docs/getting-started/keeping-backstage-updated.md b/docs/getting-started/keeping-backstage-updated.md
index 1de8874d56..88e4a02ef2 100644
--- a/docs/getting-started/keeping-backstage-updated.md
+++ b/docs/getting-started/keeping-backstage-updated.md
@@ -63,18 +63,16 @@ When a given dependency version is the _same_ between different packages, the
dependency is hoisted to the main `node_modules` folder in the monorepo root to
be shared between packages. When _different_ versions of the same dependency are
encountered, Yarn creates a `node_modules` folder within a particular package.
+This can lead to multiple versions of the same package being installed and used
+in the same app.
-This can lead to confusing situations with type definitions, or anything with
-global state. React [Context](https://reactjs.org/docs/context.html), for
-example, depends on global referential equality. This can cause problems in
-Backstage with API lookup, or config loading.
+All Backstage core packages are implemented in such as way that package
+duplication is **not** a problem. For example, duplicate installations of
+packages like `@backstage/core-plugin-api`, `@backstage/core-components`,
+`@backstage/plugin-catalog-react`, and `@backstage/backend-plugin-api` are all
+acceptable.
-To help resolve these situations, the Backstage CLI has
-[versions:check](https://backstage.io/docs/tooling/cli/03-commands#versionscheck). This
-will validate versions of `@backstage` packages in your app to check for
-duplicate definitions:
-
-```bash
-# Add --fix to attempt automatic resolution in yarn.lock
-yarn backstage-cli versions:check
-```
+While package duplication might be acceptable in many cases, you might want to
+deduplicate packages for the purpose of optimizing bundle size and installation
+speed. We recommend using deduplication utilities such as `yarn dedupe` to trim
+down the number of duplicate packages.
diff --git a/docs/getting-started/logging-in.md b/docs/getting-started/logging-in.md
index fef8907e07..7d6fb5d55b 100644
--- a/docs/getting-started/logging-in.md
+++ b/docs/getting-started/logging-in.md
@@ -20,6 +20,8 @@ Run your Backstage app with `yarn dev`. Navigate to `http://localhost:3000`.
If you're not already logged in, you should see a login screen like this,
+
+
To login, you should choose the "Github" provider and click the "Sign in" button. This will redirect you to a Github OAuth page. Verify that the scopes mentioned on that page match the setup you did in [the authentication tutorial](./config/authentication.md). Once you click "Confirm", you will be brought back to the Backstage interface and signed in!
If you are already logged in, you will be automatically brought to your Backstage instance.
diff --git a/docs/integrations/aws-s3/discovery--old.md b/docs/integrations/aws-s3/discovery--old.md
new file mode 100644
index 0000000000..09b6eb6cc0
--- /dev/null
+++ b/docs/integrations/aws-s3/discovery--old.md
@@ -0,0 +1,88 @@
+---
+id: discovery--old
+title: AWS S3 Discovery
+sidebar_label: Discovery
+# prettier-ignore
+description: Automatically discovering catalog entities from an AWS S3 Bucket
+---
+
+:::info
+This documentation is written for the old backend which has been replaced by [the new backend system](../../backend-system/index.md), being the default since Backstage [version 1.24](../../releases/v1.24.0.md). If have migrated to the new backend system, you may want to read [its own article](./discovery.md) instead. Otherwise, [consider migrating](../../backend-system/building-backends/08-migrating.md)!
+:::
+
+The AWS S3 integration has a special entity provider for discovering catalog
+entities located in an S3 Bucket. If you have a bucket that contains multiple
+catalog files, and you want to automatically discover them, you can use this
+provider. The provider will crawl your S3 bucket and register entities
+matching the configured path. This can be useful as an alternative to static
+locations or manually adding things to the catalog.
+
+To use the entity provider, you'll need an AWS S3 integration
+[set up](locations.md) with `accessKeyId` and `secretAccessKey`, and/or
+a `roleArn` or none of these (e.g., profile- or instance-based credentials).
+
+At production deployments, you likely manage these with the permissions attached
+to your instance.
+
+In your configuration, you add a provider config per bucket:
+
+```yaml
+# app-config.yaml
+
+catalog:
+ providers:
+ awsS3:
+ yourProviderId: # identifies your dataset / provider independent of config changes
+ bucketName: sample-bucket
+ prefix: prefix/ # optional
+ region: us-east-2 # optional, uses the default region otherwise
+ schedule: # same options as in TaskScheduleDefinition
+ # supports cron, ISO duration, "human duration" as used in code
+ frequency: { minutes: 30 }
+ # supports ISO duration, "human duration" as used in code
+ timeout: { minutes: 3 }
+```
+
+For simple setups, you can omit the provider ID at the config
+which has the same effect as using `default` for it.
+
+```yaml
+# app-config.yaml
+
+catalog:
+ providers:
+ awsS3:
+ # uses "default" as provider ID
+ bucketName: sample-bucket
+ prefix: prefix/ # optional
+ region: us-east-2 # optional, uses the default region otherwise
+ schedule: # same options as in TaskScheduleDefinition
+ # supports cron, ISO duration, "human duration" as used in code
+ frequency: { minutes: 30 }
+ # supports ISO duration, "human duration" as used in code
+ timeout: { minutes: 3 }
+```
+
+As this provider is not one of the default providers, you will first need to install
+the AWS catalog plugin:
+
+```bash title="From your Backstage root directory"
+yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-aws
+```
+
+Once you've done that, you'll also need to add the segment below to `packages/backend/src/plugins/catalog.ts`:
+
+```ts
+/* packages/backend/src/plugins/catalog.ts */
+
+import { AwsS3EntityProvider } from '@backstage/plugin-catalog-backend-module-aws';
+
+const builder = await CatalogBuilder.create(env);
+/** ... other processors and/or providers ... */
+builder.addEntityProvider(
+ AwsS3EntityProvider.fromConfig(env.config, {
+ logger: env.logger,
+ scheduler: env.scheduler,
+ }),
+);
+```
diff --git a/docs/integrations/aws-s3/discovery.md b/docs/integrations/aws-s3/discovery.md
index d664466a16..db9119680e 100644
--- a/docs/integrations/aws-s3/discovery.md
+++ b/docs/integrations/aws-s3/discovery.md
@@ -6,6 +6,10 @@ sidebar_label: Discovery
description: Automatically discovering catalog entities from an AWS S3 Bucket
---
+:::info
+This documentation is written for [the new backend system](../../backend-system/index.md) which is the default since Backstage [version 1.24](../../releases/v1.24.0.md). If you are still on the old backend system, you may want to read [its own article](./discovery--old.md) instead, and [consider migrating](../../backend-system/building-backends/08-migrating.md)!
+:::
+
The AWS S3 integration has a special entity provider for discovering catalog
entities located in an S3 Bucket. If you have a bucket that contains multiple
catalog files, and you want to automatically discover them, you can use this
@@ -20,7 +24,7 @@ a `roleArn` or none of these (e.g., profile- or instance-based credentials).
At production deployments, you likely manage these with the permissions attached
to your instance.
-At your configuration, you add a provider config per bucket:
+In your configuration, you add a provider config per bucket:
```yaml
# app-config.yaml
@@ -62,24 +66,15 @@ catalog:
As this provider is not one of the default providers, you will first need to install
the AWS catalog plugin:
-```bash
-# From your Backstage root directory
+```bash title="From your Backstage root directory"
yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-aws
```
-Once you've done that, you'll also need to add the segment below to `packages/backend/src/plugins/catalog.ts`:
+Then update your backend by adding the following line:
-```ts
-/* packages/backend/src/plugins/catalog.ts */
-
-import { AwsS3EntityProvider } from '@backstage/plugin-catalog-backend-module-aws';
-
-const builder = await CatalogBuilder.create(env);
-/** ... other processors and/or providers ... */
-builder.addEntityProvider(
- AwsS3EntityProvider.fromConfig(env.config, {
- logger: env.logger,
- scheduler: env.scheduler,
- }),
-);
+```ts title="packages/backend/src/index.ts"
+backend.add(import('@backstage/plugin-catalog-backend/alpha'));
+/* highlight-add-start */
+backend.add(import('@backstage/plugin-catalog-backend-module-aws/alpha'));
+/* highlight-add-end */
```
diff --git a/docs/integrations/azure/discovery--old.md b/docs/integrations/azure/discovery--old.md
index be490d70fe..56a2fe559f 100644
--- a/docs/integrations/azure/discovery--old.md
+++ b/docs/integrations/azure/discovery--old.md
@@ -102,8 +102,7 @@ It may take some time before the branch is indexed and searchable.
As this provider is not one of the default providers, you will first need to install
the Azure catalog plugin:
-```bash
-# From your Backstage root directory
+```bash title="From your Backstage root directory"
yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-azure
```
diff --git a/docs/integrations/azure/discovery.md b/docs/integrations/azure/discovery.md
index 7e7b465118..c8a8a3af7c 100644
--- a/docs/integrations/azure/discovery.md
+++ b/docs/integrations/azure/discovery.md
@@ -102,8 +102,7 @@ It may take some time before the branch is indexed and searchable.
As this provider is not one of the default providers, you will first need to install
the Azure catalog plugin:
-```bash
-# From your Backstage root directory
+```bash title="From your Backstage root directory"
yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-azure
```
diff --git a/docs/integrations/azure/org--old.md b/docs/integrations/azure/org--old.md
index 13d53b24b3..899120e88a 100644
--- a/docs/integrations/azure/org--old.md
+++ b/docs/integrations/azure/org--old.md
@@ -18,8 +18,7 @@ Microsoft Graph API.
The package is not installed by default, therefore you have to add `@backstage/plugin-catalog-backend-module-msgraph` to your backend package.
-```bash
-# From your Backstage root directory
+```bash title="From your Backstage root directory"
yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-msgraph
```
diff --git a/docs/integrations/azure/org.md b/docs/integrations/azure/org.md
index 89abd4813b..1868188cdf 100644
--- a/docs/integrations/azure/org.md
+++ b/docs/integrations/azure/org.md
@@ -18,8 +18,7 @@ Microsoft Graph API.
The package is not installed by default, therefore you have to add `@backstage/plugin-catalog-backend-module-msgraph` to your backend package.
-```bash
-# From your Backstage root directory
+```bash title="From your Backstage root directory"
yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-msgraph
```
@@ -112,6 +111,17 @@ microsoftGraphOrg:
search: '"description:One" AND ("displayName:Video" OR "displayName:Drive")'
```
+If you don't want to only ingest groups matching the `search` and/or `filter` query, but also the groups which are members of the matched groups, you can use the `includeSubGroups` configuration:
+
+```yaml
+microsoftGraphOrg:
+ providerId:
+ group:
+ filter: securityEnabled eq false and mailEnabled eq true and groupTypes/any(c:c+eq+'Unified')
+ search: '"description:One" AND ("displayName:Video" OR "displayName:Drive")'
+ includeSubGroups: true
+```
+
In addition to these groups, one additional group will be created for your organization.
All imported groups will be a child of this group.
@@ -150,6 +160,18 @@ microsoftGraphOrg:
loadPhotos: false
```
+If you are using `userGroupMember`, the configuration for `loadPhotos` should still be managed under `users:` while omitting `search` and `filters`.
+
+```yaml
+microsoftGraphOrg:
+ providerId:
+ user:
+ loadPhotos: false
+ userGroupMember:
+ filter: "displayName eq 'Backstage Users'"
+ search: '"description:One" AND ("displayName:Video" OR "displayName:Drive")'
+```
+
## Customizing Transformation
Ingested entities can be customized by providing custom transformers.
@@ -169,6 +191,23 @@ microsoftGraphOrg:
select: ['id', 'displayName', 'description']
```
+### Using Provider Config Transformer
+
+Dynamic configuration scaling allows the `msgraph` catalog plugin to adjust its settings at runtime without requiring a redeploy. This feature is useful for scenarios where configuration needs to be updated based on real-time events or changing conditions. For example, you can dynamically adjust synchronization schedules, filters, and search parameters to optimize performance and responsiveness.
+
+:::note
+Adjusting fields that are not used on each scheduled ingestion (e.g., `id`, `schedule`) will have no effect.
+:::
+
+:::warning
+Dynamically changing configuration on the fly can introduce unintended consequences, such as system instability and configuration errors. Please review your transformer carefully to ensure that it is working as anticipated!
+:::
+
+#### Example Use Cases:
+
+- **Filter Scaling**: Adjust filters like `userGroupMember` and `groupFilter` dynamically.
+- **Search Parameter Adjustment**: Change search parameters such as `groupSearch` and `userSelect` on-the-fly.
+
### Using Custom Transformers
Transformers can be configured by extending `microsoftGraphOrgEntityProviderTransformExtensionPoint`. Here is an example:
@@ -180,6 +219,7 @@ import {
myUserTransformer,
myGroupTransformer,
myOrganizationTransformer,
+ myProviderConfigTransformer,
} from './transformers';
backend.add(
@@ -201,6 +241,9 @@ backend.add(
microsoftGraphTransformers.setOrganizationTransformer(
myOrganizationTransformer,
);
+ microsoftGraphTransformers.setProviderConfigTransformer(
+ myProviderConfigTransformer,
+ );
/* highlight-add-end */
},
});
@@ -209,7 +252,7 @@ backend.add(
);
```
-The `myUserTransformer`, `myGroupTransformer`, and `myOrganizationTransformer` transformer functions are from the examples in the section below.
+The `myUserTransformer`, `myGroupTransformer`, `myOrganizationTransformer`, and `myProviderConfigTransformer` transformer functions are from the examples in the section below.
### Transformer Examples
@@ -221,6 +264,7 @@ import {
defaultGroupTransformer,
defaultUserTransformer,
defaultOrganizationTransformer,
+ MicrosoftGraphProviderConfig,
} from '@backstage/plugin-catalog-backend-module-msgraph';
import { GroupEntity, UserEntity } from '@backstage/catalog-model';
@@ -263,6 +307,16 @@ export async function myOrganizationTransformer(
): Promise {
return undefined;
}
+
+// Example config transformer that expands the group filter to also include 'azure-group-a'
+export async function myProviderConfigTransformer(
+ provider: MicrosoftGraphProviderConfig,
+): Promise {
+ if (!provider.groupFilter?.includes('azure-group-a')) {
+ provider.groupFilter = `${provider.groupFilter} or displayName eq 'azure-group-a'`;
+ }
+ return provider;
+}
```
## Troubleshooting
diff --git a/docs/integrations/bitbucketCloud/discovery.md b/docs/integrations/bitbucketCloud/discovery.md
index 160827cb0a..04dc111d30 100644
--- a/docs/integrations/bitbucketCloud/discovery.md
+++ b/docs/integrations/bitbucketCloud/discovery.md
@@ -19,8 +19,7 @@ backend. The provider is not installed by default, therefore you have to add a
dependency to `@backstage/plugin-catalog-backend-module-bitbucket-cloud` to your backend
package.
-```bash
-# From your Backstage root directory
+```bash title="From your Backstage root directory"
yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-bitbucket-cloud
```
diff --git a/docs/integrations/bitbucketServer/discovery.md b/docs/integrations/bitbucketServer/discovery.md
index d9fc946460..99e04affa8 100644
--- a/docs/integrations/bitbucketServer/discovery.md
+++ b/docs/integrations/bitbucketServer/discovery.md
@@ -19,8 +19,7 @@ backend. The provider is not installed by default, therefore you have to add a
dependency to `@backstage/plugin-catalog-backend-module-bitbucket-server` to your backend
package.
-```bash
-# From your Backstage root directory
+```bash title="From your Backstage root directory"
yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-bitbucket-server
```
diff --git a/docs/integrations/datadog-rum/installation.md b/docs/integrations/datadog-rum/installation.md
index 4dc6c24134..6659bec182 100644
--- a/docs/integrations/datadog-rum/installation.md
+++ b/docs/integrations/datadog-rum/installation.md
@@ -28,6 +28,51 @@ app:
If your [`app-config.yaml`](https://github.com/backstage/backstage/blob/e0506af8fc54074a160fb91c83d6cae8172d3bb3/app-config.yaml#L5) file does not have this configuration, you may have to adjust your [`packages/app/public/index.html`](https://github.com/backstage/backstage/blob/e0506af8fc54074a160fb91c83d6cae8172d3bb3/packages/app/public/index.html#L69) to include the Datadog RUM `init()` section manually.
+Please note that the env value MUST be specified at build time
+
+:::note
+In case after a proper configuration, the events still are not being captured: Copy and paste this section in to your `packages/app/public/index.html` under the `` tag.
+
+```html
+<% if (config.has('app.datadogRum')) { %>
+
+<% } %>
+```
+
The `clientToken` and `applicationId` are generated from the Datadog RUM page
following
[these instructions](https://docs.datadoghq.com/real_user_monitoring/browser/).
diff --git a/docs/integrations/gerrit/discovery--old.md b/docs/integrations/gerrit/discovery--old.md
new file mode 100644
index 0000000000..250de80bdf
--- /dev/null
+++ b/docs/integrations/gerrit/discovery--old.md
@@ -0,0 +1,73 @@
+---
+id: discovery--old
+title: Gerrit Discovery
+sidebar_label: Discovery
+# prettier-ignore
+description: Automatically discovering catalog entities from Gerrit repositories
+---
+
+:::info
+This documentation is written for the old backend which has been replaced by [the new backend system](../../backend-system/index.md), being the default since Backstage [version 1.24](../../releases/v1.24.0.md). If have migrated to the new backend system, you may want to read [its own article](./discovery.md) instead. Otherwise, [consider migrating](../../backend-system/building-backends/08-migrating.md)!
+:::
+
+The Gerrit integration has a special entity provider for discovering catalog entities
+from Gerrit repositories. The provider uses the "List Projects" API in Gerrit to get
+a list of repositories and will automatically ingest all `catalog-info.yaml` files
+stored in the root of the matching projects.
+
+## Installation
+
+As this provider is not one of the default providers, you will first need to install
+the Gerrit provider plugin:
+
+```bash title="From your Backstage root directory"
+yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-gerrit
+```
+
+Then add the plugin to the plugin catalog `packages/backend/src/plugins/catalog.ts`:
+
+```ts
+/* packages/backend/src/plugins/catalog.ts */
+import { GerritEntityProvider } from '@backstage/plugin-catalog-backend-module-gerrit';
+const builder = await CatalogBuilder.create(env);
+/** ... other processors and/or providers ... */
+builder.addEntityProvider(
+ GerritEntityProvider.fromConfig(env.config, {
+ logger: env.logger,
+ scheduler: env.scheduler,
+ }),
+);
+```
+
+## Configuration
+
+To use the discovery processor, you'll need a Gerrit integration
+[set up](locations.md). Then you can add any number of providers.
+
+```yaml
+# app-config.yaml
+catalog:
+ providers:
+ gerrit:
+ yourProviderId: # identifies your dataset / provider independent of config changes
+ host: gerrit-your-company.com
+ branch: master # Optional
+ query: 'state=ACTIVE&prefix=webapps'
+ schedule:
+ # supports cron, ISO duration, "human duration" as used in code
+ frequency: { minutes: 30 }
+ # supports ISO duration, "human duration" as used in code
+ timeout: { minutes: 3 }
+ backend:
+ host: gerrit-your-company.com
+ branch: master # Optional
+ query: 'state=ACTIVE&prefix=backend'
+```
+
+The provider configuration is composed of three parts:
+
+- **`host`**: the host of the Gerrit integration to use.
+- **`branch`** _(optional)_: the branch where we will look for catalog entities (defaults to "master").
+- **`query`**: this string is directly used as the argument to the "List Project" API.
+ Typically, you will want to have some filter here to exclude projects that will
+ never contain any catalog files.
diff --git a/docs/integrations/gerrit/discovery.md b/docs/integrations/gerrit/discovery.md
index e2922c1f76..eca0417871 100644
--- a/docs/integrations/gerrit/discovery.md
+++ b/docs/integrations/gerrit/discovery.md
@@ -6,6 +6,10 @@ sidebar_label: Discovery
description: Automatically discovering catalog entities from Gerrit repositories
---
+:::info
+This documentation is written for [the new backend system](../../backend-system/index.md) which is the default since Backstage [version 1.24](../../releases/v1.24.0.md). If you are still on the old backend system, you may want to read [its own article](./discovery--old.md) instead, and [consider migrating](../../backend-system/building-backends/08-migrating.md)!
+:::
+
The Gerrit integration has a special entity provider for discovering catalog entities
from Gerrit repositories. The provider uses the "List Projects" API in Gerrit to get
a list of repositories and will automatically ingest all `catalog-info.yaml` files
@@ -16,24 +20,17 @@ stored in the root of the matching projects.
As this provider is not one of the default providers, you will first need to install
the Gerrit provider plugin:
-```bash
-# From your Backstage root directory
+```bash title="From your Backstage root directory"
yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-gerrit
```
-Then add the plugin to the plugin catalog `packages/backend/src/plugins/catalog.ts`:
+Then update your backend by adding the following line:
-```ts
-/* packages/backend/src/plugins/catalog.ts */
-import { GerritEntityProvider } from '@backstage/plugin-catalog-backend-module-gerrit';
-const builder = await CatalogBuilder.create(env);
-/** ... other processors and/or providers ... */
-builder.addEntityProvider(
- GerritEntityProvider.fromConfig(env.config, {
- logger: env.logger,
- scheduler: env.scheduler,
- }),
-);
+```ts title="packages/backend/src/index.ts"
+backend.add(import('@backstage/plugin-catalog-backend/alpha'));
+/* highlight-add-start */
+backend.add(import('@backstage/plugin-catalog-backend-module-gerrit/alpha'));
+/* highlight-add-end */
```
## Configuration
diff --git a/docs/integrations/github/discovery--old.md b/docs/integrations/github/discovery--old.md
index 138e54a538..752aa51bde 100644
--- a/docs/integrations/github/discovery--old.md
+++ b/docs/integrations/github/discovery--old.md
@@ -25,8 +25,7 @@ backend. They are not installed by default, therefore you have to add a
dependency on `@backstage/plugin-catalog-backend-module-github` to your backend
package.
-```bash
-# From your Backstage root directory
+```bash title="From your Backstage root directory"
yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-github
```
@@ -273,8 +272,7 @@ backend. They are not installed by default, therefore you have to add a
dependency on `@backstage/plugin-catalog-backend-module-github` to your backend
package, plus `@backstage/integration` for the basic credentials management:
-```bash
-# From your Backstage root directory
+```bash title="From your Backstage root directory"
yarn --cwd packages/backend add @backstage/integration @backstage/plugin-catalog-backend-module-github
```
diff --git a/docs/integrations/github/discovery.md b/docs/integrations/github/discovery.md
index 5c3a33416b..43e63a618c 100644
--- a/docs/integrations/github/discovery.md
+++ b/docs/integrations/github/discovery.md
@@ -24,8 +24,7 @@ You will have to add the GitHub Entity provider to your backend as it is not ins
dependency on `@backstage/plugin-catalog-backend-module-github` to your backend
package.
-```bash
-# From your Backstage root directory
+```bash title="From your Backstage root directory"
yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-github
```
@@ -40,8 +39,9 @@ backend.add(import('@backstage/plugin-catalog-backend-module-github/alpha'));
## Events Support
The catalog module for GitHub comes with events support enabled.
-This will make it subscribe to its relevant topics (`github.push`)
-and expects these events to be published via the `EventsService`.
+This will make it subscribe to its relevant topics (`github.push`,
+`github.repository`) and expects these events to be published
+via the `EventsService`.
Additionally, you should install the
[event router by `events-backend-module-github`](https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-github/README.md)
@@ -55,7 +55,15 @@ You can decide between the following options (extensible):
- [via HTTP endpoint](https://github.com/backstage/backstage/tree/master/plugins/events-backend/README.md)
- [via an AWS SQS queue](https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-aws-sqs/README.md)
-You can check the official docs to [configure your webhook](https://docs.github.com/en/developers/webhooks-and-events/webhooks/creating-webhooks) and to [secure your request](https://docs.github.com/en/developers/webhooks-and-events/webhooks/securing-your-webhooks). The webhook will need to be configured to forward `push` events.
+You can check the official docs to [configure your webhook](https://docs.github.com/en/developers/webhooks-and-events/webhooks/creating-webhooks) and to [secure your request](https://docs.github.com/en/developers/webhooks-and-events/webhooks/securing-your-webhooks).
+
+The webhook(s) will need to be configured to react to `push` and
+`repository` events.
+
+Certain actions like `transferred` by the `repository` event type
+will not be supported when you use repository webhooks.
+Please check the GitHubs documentation for these event types and
+its actions.
## Configuration
diff --git a/docs/integrations/github/github-apps.md b/docs/integrations/github/github-apps.md
index b5e252be74..298eba26e3 100644
--- a/docs/integrations/github/github-apps.md
+++ b/docs/integrations/github/github-apps.md
@@ -109,8 +109,8 @@ integrations:
webhookSecret: ${AUTH_ORG_WEBHOOK_SECRET}
```
-:::Note
-Note that in both examples above `apps` is an array which means you can add multiple GitHub Apps using `$include` or environment variables as long as they are each for a different GitHub Org as mentioned under the [Caveats](#caveats) section
+:::note
+Note that in both examples above `apps` is an array which means you can add multiple GitHub Apps using `$include` or environment variables as long as they are each for a different GitHub Org as mentioned under the [Caveats](#caveats) section.
:::
## Limiting the GitHub App installations
diff --git a/docs/integrations/github/org--old.md b/docs/integrations/github/org--old.md
index 3d1639a924..bf12cad036 100644
--- a/docs/integrations/github/org--old.md
+++ b/docs/integrations/github/org--old.md
@@ -29,8 +29,7 @@ the Processor method (not recommended), it is described separately below.
The provider is not installed by default, therefore you have to add a dependency
to `@backstage/plugin-catalog-backend-module-github` to your backend package.
-```bash
-# From your Backstage root directory
+```bash title="From your Backstage root directory"
yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-github
```
@@ -334,8 +333,7 @@ frequency with which they are refreshed, separately from other processors.
The `GithubOrgReaderProcessor` is not registered by default, so you have to
install and register it in the catalog plugin:
-```bash
-# From your Backstage root directory
+```bash title="From your Backstage root directory"
yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-github
```
diff --git a/docs/integrations/github/org.md b/docs/integrations/github/org.md
index f94ffe6c7a..18865cd630 100644
--- a/docs/integrations/github/org.md
+++ b/docs/integrations/github/org.md
@@ -38,8 +38,7 @@ You will have to add the GitHub Org provider to your backend as it is not instal
dependency on `@backstage/plugin-catalog-backend-module-github-org` to your backend
package.
-```bash
-# From your Backstage root directory
+```bash title="From your Backstage root directory"
yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-github-org
```
diff --git a/docs/integrations/gitlab/discovery.md b/docs/integrations/gitlab/discovery.md
index 98fbb0fbce..70f12f181e 100644
--- a/docs/integrations/gitlab/discovery.md
+++ b/docs/integrations/gitlab/discovery.md
@@ -20,8 +20,7 @@ This provider can also be configured to ingest GitLab data based on [GitLab Webh
As this provider is not one of the default providers, you will first need to install
the gitlab catalog plugin:
-```bash
-# From your Backstage root directory
+```bash title="From your Backstage root directory"
yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-gitlab
```
@@ -154,6 +153,7 @@ catalog:
group: example-group # Optional. Group and subgroup (if needed) to look for repositories. If not present the whole instance will be scanned
entityFilename: catalog-info.yaml # Optional. Defaults to `catalog-info.yaml`
projectPattern: '[\s\S]*' # Optional. Filters found projects based on provided patter. Defaults to `[\s\S]*`, which means to not filter anything
+ excludeRepos: [] # Optional. A list of project paths that should be excluded from discovery, e.g. group/subgroup/repo. Should not start or end with a slash.
schedule: # Same options as in TaskScheduleDefinition. Optional for the Legacy Backend System
# supports cron, ISO duration, "human duration" as used in code
frequency: { minutes: 30 }
diff --git a/docs/integrations/gitlab/org.md b/docs/integrations/gitlab/org.md
index da20af9d4a..303a4db752 100644
--- a/docs/integrations/gitlab/org.md
+++ b/docs/integrations/gitlab/org.md
@@ -25,8 +25,7 @@ This provider can also be configured to ingest GitLab data based on [GitLab Syst
As this provider is not one of the default providers, you will first need to install the Gitlab provider plugin:
-```bash
-# From your Backstage root directory
+```bash title="From your Backstage root directory"
yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-gitlab @backstage/plugin-catalog-backend-module-gitlab-org
```
@@ -225,11 +224,24 @@ Refer to the [GitLab Group Member Relation](https://docs.gitlab.com/ee/api/graph
### Users
-For self hosted, all `User` entities are ingested from the entire instance.
+For self hosted, all `User` entities are ingested from the entire instance by default.
For gitlab.com `User` entities for users who have [direct or inherited membership](https://docs.gitlab.com/ee/user/project/members/index.html#membership-types)
of the top-level group for the configured group path will be ingested.
+In both cases (SaaS & self hosted), you can limit the ingested users to users directly assigned to the group defined in your `app-config.yaml` by setting the configuration key `restrictUsersToGroup: true`. This is especially useful when you have a large user base that you don't want to import by default.
+
+```yaml
+catalog:
+ providers:
+ gitlab:
+ yourProviderId:
+ host: gitlab.com ## Could also be self hosted.
+ orgEnabled: true
+ group: org/teams # Required for gitlab.com when `orgEnabled: true`. Optional for self managed. Must not end with slash. Accepts only groups under the provided path (which will be stripped)
+ restrictUsersToGroup: true # Backstage will ingest only users directly assigned to org/teams.
+```
+
### Limiting `User` and `Group` entity ingestion in the provider
Optionally, you can limit the entity types ingested by the provider when using
diff --git a/docs/integrations/ldap/org--old.md b/docs/integrations/ldap/org--old.md
index 63f052371f..448e9bbed1 100644
--- a/docs/integrations/ldap/org--old.md
+++ b/docs/integrations/ldap/org--old.md
@@ -24,8 +24,7 @@ the Processor method (not recommended), it is described separately below.
The provider is not installed by default, therefore you have to add a dependency
to `@backstage/plugin-catalog-backend-module-ldap` to your backend package.
-```bash
-# From your Backstage root directory
+```bash title="From your Backstage root directory"
yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-ldap
```
diff --git a/docs/integrations/ldap/org.md b/docs/integrations/ldap/org.md
index 38f19af257..b1aa460bd6 100644
--- a/docs/integrations/ldap/org.md
+++ b/docs/integrations/ldap/org.md
@@ -21,8 +21,7 @@ Backstage in general supports OpenLDAP compatible vendors, as well as Active Dir
The provider is not installed by default, therefore you have to add a dependency
to `@backstage/plugin-catalog-backend-module-ldap` to your backend package.
-```bash
-# From your Backstage root directory
+```bash title="From your Backstage root directory"
yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-ldap
```
@@ -86,6 +85,14 @@ catalog:
These config blocks have a lot of options in them, so we will describe each
"root" key within the block separately.
+> NOTE:
+>
+> If you want to import users and groups from different LDAP servers, you can define multiple providers with different names.
+> If they should come from the same server, you can define multiple users and groups blocks within the same provider using an array of users / groups.
+> Entries coming from the same block will be able to detect group memberships based on the `memberOf` attribute.
+>
+> If you want only to import users or groups, you can omit the groups or users block.
+
### target
This is the URL of the targeted server, typically on the form
diff --git a/docs/notifications/index.md b/docs/notifications/index.md
new file mode 100644
index 0000000000..95d77a9b7f
--- /dev/null
+++ b/docs/notifications/index.md
@@ -0,0 +1,320 @@
+---
+id: index
+title: Getting Started
+description: How to get started with the notifications and signals
+---
+
+The Backstage Notifications System provides a way for plugins and external services to send notifications to Backstage users.
+These notifications are displayed in the dedicated page of the Backstage frontend UI or by frontend plugins per specific scenarios.
+Additionally, notifications can be sent to external channels (like email) via "processors" implemented within plugins.
+
+Notifications can be optionally integrated with the signals (a push mechanism) to ensure users receive them immediately.
+
+### Upgrade to the latest version of Backstage
+
+To ensure your version of Backstage has all the latest notifications and signals related functionality, it’s important to upgrade to the latest version. The [Backstage upgrade helper](https://backstage.github.io/upgrade-helper/) is a great tool to help ensure that you’ve made all the necessary changes during the upgrade!
+
+## About notifications
+
+Notifications are messages sent to either individual users or groups.
+They are not intended for inter-process communication of any kind.
+
+There are two basic types of notifications:
+
+- **Broadcast**: Messages sent to all users of Backstage.
+- **Entity**: Messages delivered to specific listed entities, such as Users or Groups.
+
+Example of use-cases:
+
+- System-wide announcements or alerts
+- Notifications for component owners: e.g., build failures, successful deployments, new vulnerabilities
+- Notifications for individuals: e.g., updates you have subscribed to, new required training courses
+- Notifications pertaining to a particular entity in the catalog: A notification might apply to an entity and the owning team.
+
+## Installation in Older Environments
+
+Newer versions of instances created by the create-app have both the notifications and signals plugins included by default, this section can be skipped right to the Configuration.
+
+Following installation instructions are valid for enabling the plugins in older environments.
+
+### Add Notifications Backend
+
+```bash
+yarn workspace backend add @backstage/plugin-notifications-backend
+```
+
+Add the notifications to your `backend/src/index.ts`:
+
+```ts
+const backend = createBackend();
+// ...
+backend.add(import('@backstage/plugin-notifications-backend'));
+```
+
+### Add Notifications Frontend
+
+```bash
+yarn workspace app add @backstage/notifications
+```
+
+To add the notifications main menu, add following to your `packages/app/src/components/Root/Root.tsx`:
+
+```tsx
+import { NotificationsSidebarItem } from '@backstage/plugin-notifications';
+
+
+
+
+ // ...
+
+
+
+;
+```
+
+Also add the route to notifications to `packages/app/src/App.tsx`:
+
+```tsx
+import { NotificationsPage } from '@backstage/plugin-notifications';
+
+
+ // ...
+ } />
+;
+```
+
+### Optional: Add Signals Backend
+
+Optionally add Signals to your backend by
+
+```bash
+yarn workspace backend add @backstage/plugin-signals-backend
+```
+
+Add the signals to your `backend/src/index.ts`:
+
+```ts
+const backend = createBackend();
+// ...
+backend.add(import('@backstage/plugin-signals-backend'));
+```
+
+### Optional: Signals Frontend
+
+The use of signals is optional but improves user experience.
+
+Start with:
+
+```bash
+yarn workspace app add @backstage/plugin-signals
+```
+
+To install the plugin, you have to add the following to your `packages/app/src/plugins.ts`:
+
+```ts
+export { signalsPlugin } from '@backstage/plugin-signals';
+```
+
+And make sure that your `packages/app/src/App.tsx` contains:
+
+```ts
+import * as plugins from './plugins';
+
+const app = createApp({
+ // ...
+ plugins: Object.values(plugins),
+ // ...
+});
+```
+
+If the signals plugin is properly configured, it will be automatically discovered by the notifications plugin and used.
+
+## Configuration
+
+### Notifications Backend
+
+The Notifications backend plugin provides an API to create notifications, list notifications per logged-in user, and search based on parameters.
+
+The plugin uses a relational [database](https://backstage.io/docs/getting-started/config/database) for persistence, no specifics are introduced in this context.
+
+No additional configuration in the app-config is needed, except for optional additional modules for `processors`.
+
+### Notifications Frontend
+
+The recipients of notifications have to be entities in the catalog, e.g. of the User or Group kind.
+
+Otherwise no specific configuration is needed for the front-end notifications plugin.
+
+All parametrization is done through component properties, such as the `NotificationsSidebarItem`, which can be used as an active left-side menu item in the front-end.
+
+
+
+In the `packages/app/src/components/Root/Root.tsx`, tweak the [properties](https://backstage.io/docs/reference/plugin-notifications.notificationssidebaritem) of the `` per specific needs.
+
+## Use
+
+New notifications can be sent either by a backend plugin or an external service through the REST API.
+
+### Backend
+
+Regardless of technical feasibility, a backend plugin should avoid directly accessing the notifications REST API.
+Instead, it should integrate with the `@backstage/plugin-notifications-node` to `send` (create) a new notification.
+
+The reasons for this approach include the propagation of authorization in the API request and improved maintenance and backward compatibility in the future.
+
+```ts
+import { notificationService } from '@backstage/plugin-notifications-node';
+
+export const myPlugin = createBackendPlugin({
+ pluginId: 'myPlugin',
+ register(env) {
+ env.registerInit({
+ deps: {
+ // ...
+ notificationService: notificationService,
+ },
+ async init({ config, logger, httpRouter, notificationService }) {
+ httpRouter.use(
+ await createRouter({
+ // ...
+ notificationService,
+ }),
+ );
+ },
+ });
+ },
+});
+```
+
+To emit a new notification:
+
+```ts
+notificationService.send({
+ recipients /* of the broadcast or entity type */,
+ payload /* actual message */,
+});
+```
+
+Refer the [API documentation](https://github.com/backstage/backstage/blob/master/plugins/notifications-node/api-report.md) for further details.
+
+### Signals
+
+The use of signals with notifications is optional but generally enhances user experience and performance.
+
+When a notification is created, a new signal is emitted to a general-purpose message bus to announce it to subscribed listeners.
+
+The frontend maintains a persistent connection (WebSocket) to receive these announcements from the notifications channel.
+The specific details of the updated or created notification should be retrieved via a request to the notifications API, except for new notifications, where the payload is included in the signal for performance reasons.
+
+In a frontend plugin, to subscribe for notifications' signals:
+
+```ts
+import { useSignal } from '@backstage/plugin-signals-react';
+
+const { lastSignal } = useSignal('notifications');
+
+React.useEffect(() => {
+ /* ... */
+}, [lastSignal, notificationsApi]);
+```
+
+### Consuming Notifications
+
+In a front-end plugin, the simplest way to query a notification is by its ID:
+
+```ts
+import { useApi } from '@backstage/core-plugin-api';
+import { notificationsApiRef } from '@backstage/plugin-notifications';
+
+const notificationsApi = useApi(notificationsApiRef);
+
+notificationsApi.getNotification(yourId);
+
+// or with connection to signals:
+notificationsApi.getNotification(lastSignal.notification_id);
+```
+
+### Extending Notifications via Processors
+
+The notifications can be extended with `NotificationProcessor`. These processors allow to decorate notifications before they are sent or/and send the notifications to external services.
+
+Depending on the needs, a processor can modify the content of a notification or route it to different systems like email, Slack, or other services.
+
+A good example of how to write a processor is the [Email Processor](https://github.com/backstage/backstage/tree/master/plugins/notifications-backend-module-email).
+
+Start off by creating a notification processor:
+
+```ts
+import { Notification } from '@backstage/plugin-notifications-common';
+import { NotificationProcessor } from '@backstage/plugin-notifications-node';
+
+class MyNotificationProcessor implements NotificationProcessor {
+ async decorate(notification: Notification): Promise {
+ if (notification.origin === 'plugin-my-plugin') {
+ notification.payload.icon = 'my-icon';
+ }
+ return notification;
+ }
+
+ async send(notification: Notification): Promise {
+ nodemailer.sendEmail({
+ from: 'backstage',
+ to: 'user',
+ subject: notification.payload.title,
+ text: notification.payload.description,
+ });
+ }
+}
+```
+
+Both of the processing functions are optional, and you can implement only one of them.
+
+Add the notification processor to the notification system by:
+
+```ts
+import { notificationsProcessingExtensionPoint } from '@backstage/plugin-notifications-node';
+import { Notification } from '@backstage/plugin-notifications-common';
+
+export const myPlugin = createBackendPlugin({
+ pluginId: 'myPlugin',
+ register(env) {
+ env.registerInit({
+ deps: {
+ notifications: notificationsProcessingExtensionPoint,
+ // ...
+ },
+ async init({ notifications }) {
+ // ...
+ notifications.addProcessor(new MyNotificationProcessor());
+ },
+ });
+ },
+});
+```
+
+### External Services
+
+When the emitter of a notification is a Backstage backend plugin, it is mandatory to use the integration via `@backstage/plugin-notifications-node` as described above.
+
+If the emitter is a service external to Backstage, an HTTP POST request can be issued directly to the API, assuming that authentication is properly configured.
+Refer to the [service-to-service auth documentation](https://backstage.io/docs/auth/service-to-service-auth) for more details, focusing on the Static Tokens section for the simplest setup option.
+
+An example request for creating a broadcast notification might look like:
+
+```bash
+curl -X POST https://[BACKSTAGE_BACKEND]/api/notifications -H "Content-Type: application/json" -H "Authorization: Bearer YOUR_BASE64_SHARED_KEY_TOKEN" -d '{"recipients":{"type":"broadcast"},"payload": {"title": "Title of broadcast message","link": "http://foo.com/bar","severity": "high","topic": "The topic"}}'
+```
+
+## Additional info
+
+An example of a backend plugin sending notifications can be found in https://github.com/backstage/backstage/tree/master/plugins/scaffolder-backend-module-notifications.
+
+Sources of the notifications and signal plugins:
+
+- https://github.com/backstage/backstage/blob/master/plugins/notifications
+
+- https://github.com/backstage/backstage/blob/master/plugins/notifications-backend
+
+- https://github.com/backstage/backstage/blob/master/plugins/notifications-node
+
+- https://github.com/backstage/backstage/blob/master/plugins/signals-react
diff --git a/docs/notifications/notificationsPage.png b/docs/notifications/notificationsPage.png
new file mode 100644
index 0000000000..7c96ab77af
Binary files /dev/null and b/docs/notifications/notificationsPage.png differ
diff --git a/docs/overview/threat-model.md b/docs/overview/threat-model.md
index da97f3fc83..c0e2d61e25 100644
--- a/docs/overview/threat-model.md
+++ b/docs/overview/threat-model.md
@@ -37,6 +37,8 @@ The operator is ultimately responsible for auditing usage of internal and extern
The operator is also responsible for maintaining the resolved NPM dependencies of their Backstage project. This involves ensuring that `yarn.lock` receives updated versions of packages that have vulnerabilities, when those fixed versions are in range of what the Backstage packages request in their respective `package.json` files. This is commonly done by employing automated tooling such as [Dependabot](https://dependabot.com/), [Snyk](https://snyk.io/), and/or [Renovate](https://docs.renovatebot.com/) on your own repository. When fixed versions exist that are _not_ in range of what Backstage packages request, or when larger operations such as switching out an entire dependency for another one is required, maintainers collaborate with contributors to try to address those dependency declarations in the main project as soon as possible.
+The built-in protection against unauthorized access does not by default include protection of the frontend bundle. The frontend bundle includes all the code of your frontend plugins and code in minified form, as well as any other frontend resources like images, fonts, etc. If this is a concern, you can use the [experimental public entry point](https://backstage.io/docs/tutorials/enable-public-entry/) to create two separate frontend builds, where authenticated users only have access to the full one.
+
## Common Backend Configuration
There are many common facilities that are configured centrally and available to all Backstage backend plugins. For example there is a `DatabaseManager` that provides access to a SQL database, `TaskScheduler` for scheduling long-running tasks, `Logger` as a general logging facility, and `UrlReader` for reading content from external sources. These are all configured either directly in code, or within the `backend` block of the static configuration. The appropriate care needs to be taken to ensure that any secrets remain confidential and no malicious configuration is injected.
diff --git a/docs/permissions/custom-rules.md b/docs/permissions/custom-rules.md
index 9063ed7257..57565755fb 100644
--- a/docs/permissions/custom-rules.md
+++ b/docs/permissions/custom-rules.md
@@ -66,9 +66,8 @@ import { catalogConditions, createCatalogConditionalDecision, createCatalogPermi
/* highlight-remove-next-line */
import { createConditionFactory } from '@backstage/plugin-permission-node';
/* highlight-add-next-line */
-import { PermissionPolicy, PolicyQuery, createConditionFactory } from '@backstage/plugin-permission-node';
+import { PermissionPolicy, PolicyQuery, PolicyQueryUser, createConditionFactory } from '@backstage/plugin-permission-node';
/* highlight-add-start */
-import { BackstageIdentityResponse } from '@backstage/plugin-auth-node';
import { AuthorizeResult, PolicyDecision, isResourcePermission } from '@backstage/plugin-permission-common';
/* highlight-add-end */
...
@@ -102,21 +101,21 @@ const isInSystem = createConditionFactory(isInSystemRule);
class TestPermissionPolicy implements PermissionPolicy {
async handle(
request: PolicyQuery,
- user?: BackstageIdentityResponse,
+ user?: PolicyQueryUser,
): Promise {
if (isResourcePermission(request.permission, 'catalog-entity')) {
return createCatalogConditionalDecision(
request.permission,
/* highlight-remove-start */
catalogConditions.isEntityOwner({
- claims: user?.identity.ownershipEntityRefs ?? [],
+ claims: user?.info.ownershipEntityRefs ?? [],
}),
/* highlight-remove-end */
/* highlight-add-start */
{
anyOf: [
catalogConditions.isEntityOwner({
- claims: user?.identity.ownershipEntityRefs ?? [],
+ claims: user?.info.ownershipEntityRefs ?? [],
}),
isInSystem({ systemRef: 'interviewing' }),
],
diff --git a/docs/permissions/getting-started.md b/docs/permissions/getting-started.md
index 4dabf3fcbd..e8132e571b 100644
--- a/docs/permissions/getting-started.md
+++ b/docs/permissions/getting-started.md
@@ -50,8 +50,7 @@ The permissions framework uses a new `permission-backend` plugin to accept autho
1. Add `@backstage/plugin-permission-backend` as a dependency of your Backstage backend:
- ```bash
- # From your Backstage root directory
+ ```bash title="From your Backstage root directory"
yarn --cwd packages/backend add @backstage/plugin-permission-backend
```
diff --git a/docs/permissions/plugin-authors/01-setup.md b/docs/permissions/plugin-authors/01-setup.md
index a674d82e25..f11bdff930 100644
--- a/docs/permissions/plugin-authors/01-setup.md
+++ b/docs/permissions/plugin-authors/01-setup.md
@@ -39,8 +39,7 @@ The source code is available here:
2. Add these packages as dependencies for your Backstage app:
- ```sh
- # From your Backstage root directory
+ ```sh title="From your Backstage root directory"
yarn --cwd packages/backend add @internal/plugin-todo-list-backend @internal/plugin-todo-list-common
yarn --cwd packages/app add @internal/plugin-todo-list
```
diff --git a/docs/permissions/plugin-authors/02-adding-a-basic-permission-check.md b/docs/permissions/plugin-authors/02-adding-a-basic-permission-check.md
index aacd60af8c..724edb7ccb 100644
--- a/docs/permissions/plugin-authors/02-adding-a-basic-permission-check.md
+++ b/docs/permissions/plugin-authors/02-adding-a-basic-permission-check.md
@@ -169,15 +169,12 @@ Before running this step, please make sure you followed the steps described in [
In order to test the logic above, the integrators of your backstage instance need to change their permission policy to return `DENY` for our newly-created permission:
```ts title="packages/backend/src/plugins/permission.ts"
-/* highlight-add-start */
-import {
- BackstageIdentityResponse,
-} from '@backstage/plugin-auth-node';
-/* highlight-add-end */
import {
PermissionPolicy,
- /* highlight-add-next-line */
+ /* highlight-add-start */
PolicyQuery,
+ PolicyQueryUser,
+ /* highlight-add-end */
} from '@backstage/plugin-permission-node';
/* highlight-add-start */
import { isPermission } from '@backstage/plugin-permission-common';
@@ -190,7 +187,7 @@ class TestPermissionPolicy implements PermissionPolicy {
/* highlight-add-start */
async handle(
request: PolicyQuery,
- _user?: BackstageIdentityResponse,
+ _user?: PolicyQueryUser,
): Promise {
if (isPermission(request.permission, todoListCreatePermission)) {
return {
diff --git a/docs/permissions/plugin-authors/03-adding-a-resource-permission-check.md b/docs/permissions/plugin-authors/03-adding-a-resource-permission-check.md
index b3aeb13a68..7ad551e926 100644
--- a/docs/permissions/plugin-authors/03-adding-a-resource-permission-check.md
+++ b/docs/permissions/plugin-authors/03-adding-a-resource-permission-check.md
@@ -237,12 +237,12 @@ Let's go back to the permission policy's handle function and try to authorize ou
```ts title="packages/backend/src/plugins/permission.ts"
import {
- BackstageIdentityResponse,
IdentityClient
} from '@backstage/plugin-auth-node';
import {
PermissionPolicy,
PolicyQuery,
+ PolicyQueryUser,
} from '@backstage/plugin-permission-node';
import { isPermission } from '@backstage/plugin-permission-common';
/* highlight-remove-next-line */
@@ -262,9 +262,9 @@ import {
async handle(
request: PolicyQuery,
/* highlight-remove-next-line */
- _user?: BackstageIdentityResponse,
+ _user?: PolicyQueryUser,
/* highlight-add-next-line */
- user?: BackstageIdentityResponse,
+ user?: PolicyQueryUser,
): Promise {
if (isPermission(request.permission, todoListCreatePermission)) {
return {
@@ -276,7 +276,7 @@ async handle(
return createTodoListConditionalDecision(
request.permission,
todoListConditions.isOwner({
- userId: user?.identity.userEntityRef ?? '',
+ userId: user?.info.userEntityRef ?? '',
}),
);
}
diff --git a/docs/permissions/plugin-authors/05-frontend-authorization.md b/docs/permissions/plugin-authors/05-frontend-authorization.md
index 60458aaf4d..4d673e3b4f 100644
--- a/docs/permissions/plugin-authors/05-frontend-authorization.md
+++ b/docs/permissions/plugin-authors/05-frontend-authorization.md
@@ -199,7 +199,8 @@ const routes = (
- {/* highlight-add-end */}}
+ {/* highlight-add-end */}
+ }>
{/* ... */}
diff --git a/docs/permissions/writing-a-policy.md b/docs/permissions/writing-a-policy.md
index 3d4371f038..0f2d4fe091 100644
--- a/docs/permissions/writing-a-policy.md
+++ b/docs/permissions/writing-a-policy.md
@@ -10,7 +10,10 @@ That policy looked like this:
```typescript title="packages/backend/src/plugins/permission.ts"
class TestPermissionPolicy implements PermissionPolicy {
- async handle(request: PolicyQuery): Promise {
+ async handle(
+ request: PolicyQuery,
+ _user?: PolicyQueryUser,
+ ): Promise {
if (request.permission.name === 'catalog.entity.delete') {
return {
result: AuthorizeResult.DENY,
@@ -35,14 +38,6 @@ As we confirmed in the previous section, we know that this now prevents us from
Let's change the policy to the following:
```ts
-/* highlight-remove-next-line */
-import { IdentityClient } from '@backstage/plugin-auth-node';
-/* highlight-add-start */
-import {
- BackstageIdentityResponse,
- IdentityClient
-} from '@backstage/plugin-auth-node';
- /* highlight-add-end */
import {
AuthorizeResult,
PolicyDecision,
@@ -65,7 +60,7 @@ class TestPermissionPolicy implements PermissionPolicy {
/* highlight-add-start */
async handle(
request: PolicyQuery,
- user?: BackstageIdentityResponse,
+ user?: PolicyQueryUser,
): Promise {
/* highlight-add-end */
/* highlight-remove-next-line */
@@ -81,7 +76,7 @@ class TestPermissionPolicy implements PermissionPolicy {
return createCatalogConditionalDecision(
request.permission,
catalogConditions.isEntityOwner({
- claims: user?.identity.ownershipEntityRefs ?? [],
+ claims: user?.info.ownershipEntityRefs ?? [],
}),
);
/* highlight-add-end */
@@ -95,7 +90,7 @@ Let's walk through the new code that we just added.
Instead of returning an Definitive Policy Decision, we use factory methods to construct a [Conditional Policy Decision](https://backstage.io/docs/reference/plugin-permission-common.conditionalpolicydecision) (See the [Concepts page](./concepts.md) for more details). Since the policy doesn't have enough information to determine if `user` is the entity owner, this criteria is encapsulated within the conditional decision. However, `createCatalogConditionalDecision` will not compile unless `request.permission` is a catalog entity [`ResourcePermission`](https://backstage.io/docs/reference/plugin-permission-common.resourcepermission). This type constraint ensures that policies return conditional decisions that are compatible with the requested permission. To address this, we use [`isPermission`](https://backstage.io/docs/reference/plugin-permission-common.ispermission) to ["narrow"](https://www.typescriptlang.org/docs/handbook/2/narrowing.html) the type of `request.permission` to `ResourcePermission<'catalog-entity'>`. This matches the runtime behavior that was in place before, but you'll notice that the type of `request.permission` has changed within the scope of that `if` statement.
-The `catalogConditions` object contains all of the rules defined by the catalog plugin. These rules can be combined to form a [`PermissionCriteria`](https://backstage.io/docs/reference/plugin-permission-common.permissioncriteria) object, but for this case we only need to use the `isEntityOwner` rule. This rule accepts a list of entity refs that represent User identity and Group membership used to determine ownership. The second argument to `PermissionPolicy#handle` provides us with a `BackstageIdentityResponse` object, from which we can grab the user's `ownershipEntityRefs`. We provide an empty array as a fallback since the user may be anonymous.
+The `catalogConditions` object contains all of the rules defined by the catalog plugin. These rules can be combined to form a [`PermissionCriteria`](https://backstage.io/docs/reference/plugin-permission-common.permissioncriteria) object, but for this case we only need to use the `isEntityOwner` rule. This rule accepts a list of entity refs that represent User identity and Group membership used to determine ownership. The second argument to `PermissionPolicy#handle` provides us with a `PolicyQueryUser` object, from which we can grab the user's `ownershipEntityRefs`. We provide an empty array as a fallback since the user may be anonymous.
You should now be able to see in your Backstage app that the unregister entity button is enabled for entities that you own, but disabled for all other entities!
@@ -125,7 +120,7 @@ import {
class TestPermissionPolicy implements PermissionPolicy {
async handle(
request: PolicyQuery,
- user?: BackstageIdentityResponse,
+ user?: PolicyQueryUser,
): Promise {
/* highlight-remove-next-line */
if (isPermission(request.permission, catalogEntityDeletePermission)) {
@@ -134,7 +129,7 @@ class TestPermissionPolicy implements PermissionPolicy {
return createCatalogConditionalDecision(
request.permission,
catalogConditions.isEntityOwner({
- claims: user?.identity.ownershipEntityRefs ?? [],
+ claims: user?.info.ownershipEntityRefs ?? [],
}),
);
}
diff --git a/docs/plugins/backend-plugin.md b/docs/plugins/backend-plugin.md
index 7f155f3b05..1366a59099 100644
--- a/docs/plugins/backend-plugin.md
+++ b/docs/plugins/backend-plugin.md
@@ -71,8 +71,7 @@ Backstage application / backend exposes it.
To actually attach and run the plugin router, you will make some modifications
to your backend.
-```bash
-# From your Backstage root directory
+```bash title="From your Backstage root directory"
yarn --cwd packages/backend add @internal/plugin-carmen-backend@^0.1.0 # Change this to match the plugin's package.json
```
diff --git a/docs/plugins/observability.md b/docs/plugins/observability.md
index e13653706f..324e6751d4 100644
--- a/docs/plugins/observability.md
+++ b/docs/plugins/observability.md
@@ -17,7 +17,12 @@ See how to install Datadog Events in your app
### New Backend
-The backend supplies a central logging service, [`rootLogger`](../backend-system/core-services/root-logger.md), as well as a plugin based logger, [`logger`](../backend-system/core-services/logger.md) from `coreServices`. To add additional granularity to your logs, you can create children from the plugin based logger, using the `.child()` method and provide is with JSON data. For example, if you wanted to log items for a specific span in your plugin, you could do
+The backend supplies a central logging service,
+[`rootLogger`](../backend-system/core-services/root-logger.md), as well as a plugin
+based logger, [`logger`](../backend-system/core-services/logger.md) from `coreServices`.
+To add additional granularity to your logs, you can create children from the plugin
+based logger, using the `.child()` method and provide is with JSON data. For example,
+if you wanted to log items for a specific span in your plugin, you could do
```ts
export function createRouter({ logger }) {
@@ -37,7 +42,9 @@ export function createRouter({ logger }) {
}
```
-You can also add additional metadata to all logs for your Backstage instance by overriding the `rootLogger` implementation, you can see an example in [the `logger` docs](../backend-system/core-services/logger.md#configuring-the-service).
+You can also add additional metadata to all logs for your Backstage instance by
+overriding the `rootLogger` implementation, you can see an example in
+[the `rootLogger` docs](../backend-system/core-services/root-logger.md#configuring-the-service).
### Old Backend
@@ -63,9 +70,19 @@ An example log line could look as follows:
## Health Checks
-### New Backend
+### New Backend (post 1.29.0)
-The new backend is moving towards health checks being plugin-based, as such there is no current plugin for providing a health check route. You can add this yourself easily though,
+The new backend provides a `RootHealthService` which implements
+`/.backstage/health/v1/readiness` and `/.backstage/health/v1/liveness` endpoints
+to provide health checks for the entire backend instance.
+
+You can read more about this new service and how to customize it in the
+[Root Health Service documentation](../backend-system/core-services/root-health.md).
+
+### New Backend (pre 1.29.0)
+
+The new backend is moving towards health checks being plugin-based, as such there is no
+current plugin for providing a health check route. You can add this yourself easily though,
```ts
import {
diff --git a/docs/plugins/testing.md b/docs/plugins/testing.md
index a97b3d8166..7292ac9754 100644
--- a/docs/plugins/testing.md
+++ b/docs/plugins/testing.md
@@ -24,7 +24,7 @@ Running an individual test (e.g. `MyComponent.test.tsx`):
To run both `MyComponent.test.tsx` and `MyControl.test.tsx` suite of tests:
- yarn test MyCo
+ yarn test MyComponent MyControl
:::note Note
@@ -52,10 +52,6 @@ We use the light-weight
[react-testing-library](https://github.com/kentcdodds/react-testing-library) to
render React components.
-## Testing Utilities
-
-TODO.
-
## Writing Unit Tests
The following principles are good guides for determining if you are writing high
diff --git a/docs/publishing.md b/docs/publishing.md
index d7a4f65008..50d78ebf09 100644
--- a/docs/publishing.md
+++ b/docs/publishing.md
@@ -75,7 +75,7 @@ Given one or more PRs towards master that we want to create a patch release for,
./scripts/patch-release-for-pr.js ...
```
-Wait until the script has finished executing, at the end of the output you will find a link of the format `https://github.com/backstage/backstage/compare/patch/...`. Open this link in your browser to create a PR for the patch release. Finish the sentence "This release fixes an issue where..." and create the PR.
+Wait until the script has finished executing, at the end of the output you will find a link of the format `https://github.com/backstage/backstage/pull/new/patch-release-pr-...`. Open this link in your browser to create a PR for the patch release. Finish the sentence "This release fixes an issue where..." and create the PR.
Once the PR has been approved and merged, the patch release will be automatically created. The patch release is complete when a notification has been posted to Discord in the `#announcements` channel. Keep an eye on "Deploy Packages" workflow and re-trigger if it fails. It is safe to re-trigger any part of this workflow, including the release step.
diff --git a/docs/releases/v1.29.0-changelog.md b/docs/releases/v1.29.0-changelog.md
new file mode 100644
index 0000000000..86cb84d1f1
--- /dev/null
+++ b/docs/releases/v1.29.0-changelog.md
@@ -0,0 +1,2495 @@
+# Release v1.29.0
+
+Upgrade Helper: [https://backstage.github.io/upgrade-helper/?to=1.29.0](https://backstage.github.io/upgrade-helper/?to=1.29.0)
+
+## @backstage/backend-app-api@0.8.0
+
+### Minor Changes
+
+- 1cb84d7: **BREAKING**: Removed the depreacted `getPath` option from `httpRouterServiceFactory`, as well as the `HttpRouterFactoryOptions` type.
+- f691c9b: **BREAKING**: Removed the ability to pass callback-form service factories through the `defaultServiceFactories` option of `createSpecializedBackend`. This is an immediate breaking change as usage of this function is expected to be very rare.
+
+### Patch Changes
+
+- 2f99178: The `ServiceFactoryTest.get` method was deprecated and the `ServiceFactoryTest.getSubject` should be used instead. The `getSubject` method has the same behavior, but has a better method name to indicate that the service instance returned is the subject currently being tested.
+- b05e1e1: Service factories exported by this package have been updated to use the new service factory format that doesn't use a callback.
+- 617a7d2: Internal refactor that avoids the use of service factory options.
+- b60db08: Fixing exporting of classes properly from new packages
+- 18b96b1: The ability to install backend features in callback form (`() => BackendFeature`) has been deprecated. This typically means that you need to update the installed features to use the latest version of `@backstage/backend-plugin-api`. If the feature is from a third-party package, please reach out to the package maintainer to update it.
+- a63c4b6: Fixing issue with `MiddlewareFactory` deprecation wrapping
+- Updated dependencies
+ - @backstage/backend-plugin-api@0.7.0
+ - @backstage/backend-common@0.23.3
+ - @backstage/cli-node@0.2.7
+ - @backstage/backend-tasks@0.5.27
+ - @backstage/plugin-permission-node@0.8.0
+ - @backstage/plugin-auth-node@0.4.17
+ - @backstage/config-loader@1.8.1
+ - @backstage/cli-common@0.1.14
+ - @backstage/config@1.2.0
+ - @backstage/errors@1.2.4
+ - @backstage/types@1.1.1
+
+## @backstage/backend-defaults@0.4.0
+
+### Minor Changes
+
+- 1cb84d7: **BREAKING**: Removed the depreacted `getPath` option from `httpRouterServiceFactory`, as well as the `HttpRouterFactoryOptions` type.
+
+### Patch Changes
+
+- 53ced70: Added a new Root Health Service which adds new endpoints for health checks.
+- 2f99178: The `ServiceFactoryTest.get` method was deprecated and the `ServiceFactoryTest.getSubject` should be used instead. The `getSubject` method has the same behavior, but has a better method name to indicate that the service instance returned is the subject currently being tested.
+- 083eaf9: Fix bug where ISO durations could no longer be used for schedules
+- b05e1e1: Service factories exported by this package have been updated to use the new service factory format that doesn't use a callback.
+- 419f387: Refactor of `rootHttpRouterServiceFactory` to allow it to be constructed with options, but without declaring options via `createServiceFactory`.
+- cb14a05: Repack the package to fix issues with typescript with named exports
+- b9ed1bb: bumped better-sqlite3 from ^9.0.0 to ^11.0.0
+- e28af58: Refactor of `rootConfigServiceFactory` to allow it to be constructed with options, but without declaring options via `createServiceFactory`.
+- Updated dependencies
+ - @backstage/backend-plugin-api@0.7.0
+ - @backstage/backend-app-api@0.8.0
+ - @backstage/backend-common@0.23.3
+ - @backstage/plugin-permission-node@0.8.0
+ - @backstage/integration@1.13.0
+ - @backstage/plugin-events-node@0.3.8
+ - @backstage/plugin-auth-node@0.4.17
+ - @backstage/config-loader@1.8.1
+ - @backstage/backend-dev-utils@0.1.4
+ - @backstage/cli-common@0.1.14
+ - @backstage/config@1.2.0
+ - @backstage/errors@1.2.4
+ - @backstage/integration-aws-node@0.1.12
+ - @backstage/types@1.1.1
+
+## @backstage/backend-plugin-api@0.7.0
+
+### Minor Changes
+
+- 36f91e8: **BREAKING**: The `PermissionsService` no longer supports passing the deprecated `token` option, and the request options are now required.
+
+### Patch Changes
+
+- 53ced70: Added a new Root Health Service which adds new endpoints for health checks.
+
+- 083eaf9: Fix bug where ISO durations could no longer be used for schedules
+
+- 062c01c: Deprecated the ability to define options for service factories through `createServiceFactory`. In the future all service factories will return a plain `ServiceFactory` object, rather than allowing users to pass options to the factory. To allow for customization of a service implementation one can instead export one or a few building blocks that allows for simple re-implementation of the service instead.
+
+ For example, instead of:
+
+ ```ts
+ export const fooServiceFactory = createServiceFactory(
+ (options?: { bar: string }) => ({
+ service: fooServiceRef,
+ deps: { logger: coreServices.logger },
+ factory({ logger }) {
+ return {
+ // Implementation of the foo service using the `bar` option.
+ };
+ },
+ }),
+ );
+ ```
+
+ We instead encourage service implementations to provide an easy to use API for re-implementing the service for advanced use-cases:
+
+ ```ts
+ /** @public */
+ export class DefaultFooService implements FooService {
+ static create(options: { bar: string; logger: LoggerService }) {
+ return new DefaultFooService(options.logger, options.bar ?? 'default');
+ }
+
+ private constructor(
+ private readonly logger: string,
+ private readonly bar: string,
+ ) {}
+
+ // The rest of the implementation
+ }
+ ```
+
+ A user that wishes to customize the service can then easily do so by defining their own factory:
+
+ ```ts
+ export const customFooServiceFactory = createServiceFactory({
+ service: fooServiceRef,
+ deps: { logger: coreServices.logger },
+ factory({ logger }) {
+ return DefaultFooService.create({ logger, bar: 'baz' });
+ },
+ });
+ ```
+
+ This is of course more verbose than the previous solution where the factory could be customized through `fooServiceFactory({ bar: 'baz' })`, but this is a simplified which in practice should be using static configuration instead.
+
+ In cases where the old options patterns significantly improves the usability of the service factory, the old pattern can still be implemented like this:
+
+ ```ts
+ const fooServiceFactoryWithOptions = (options?: { bar: string }) =>
+ createServiceFactory({
+ service: fooServiceRef,
+ deps: { logger: coreServices.logger },
+ factory({ logger }) {
+ return {
+ // Implementation of the foo service using the `bar` option.
+ };
+ },
+ });
+
+ export const fooServiceFactory = Object.assign(
+ fooServiceFactoryWithOptions,
+ fooServiceFactoryWithOptions(),
+ );
+ ```
+
+ This change is being made because the ability to define an options callback encourages bad design of services factories. When possible, a service should be configurable through static configuration, and the existence of options may discourage that. More importantly though, the existing options do not work well with the dependency injection system of services, which is a problem for callbacks an other more advanced options. This lead to a bad pattern where only a few explicit dependencies where made available in callbacks, rather than providing an API that allowed simple re-implementation of the service with full access to dependency injection.
+
+ A separate benefit of this change is that it simplifies the TypeScript types in a way that allows TypeScript to provide a much better error message when a service factory doesn't properly implement the service interface.
+
+- fe47a3e: All service config types were renamed to option types in order to standardize frontend and backend `create*` function signatures:
+
+ - The `ServiceRefConfig` type was renamed to`ServiceRefOptions`;
+ - The `RootServiceFactoryConfig` type was renamed to `RootServiceFactoryOptions`;
+ - The `PluginServiceFactoryConfig` type was renamed to `PluginServiceFactoryOptions`
+
+- Updated dependencies
+ - @backstage/plugin-permission-common@0.8.0
+ - @backstage/plugin-auth-node@0.4.17
+ - @backstage/cli-common@0.1.14
+ - @backstage/config@1.2.0
+ - @backstage/errors@1.2.4
+ - @backstage/types@1.1.1
+
+## @backstage/core-app-api@1.14.0
+
+### Minor Changes
+
+- d3c39fc: Allow for the disabling of external routes through config, which was rendered impossible after the introduction of default targets.
+
+ ```yaml
+ app:
+ routes:
+ bindings:
+ # This has the effect of removing the button for registering new
+ # catalog entities in the scaffolder template list view
+ scaffolder.registerComponent: false
+ ```
+
+### Patch Changes
+
+- db2e2d5: Updated config schema to support app.routes.bindings
+- Updated dependencies
+ - @backstage/config@1.2.0
+ - @backstage/core-plugin-api@1.9.3
+ - @backstage/types@1.1.1
+ - @backstage/version-bridge@1.0.8
+
+## @backstage/integration@1.13.0
+
+### Minor Changes
+
+- b5deed0: Add support for `token` for `bitbucketCloud` integration
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/config@1.2.0
+ - @backstage/errors@1.2.4
+
+## @backstage/plugin-catalog-backend@1.24.0
+
+### Minor Changes
+
+- b9ed1bb: bumped better-sqlite3 from ^9.0.0 to ^11.0.0
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/backend-plugin-api@0.7.0
+ - @backstage/backend-common@0.23.3
+ - @backstage/backend-tasks@0.5.27
+ - @backstage/plugin-permission-common@0.8.0
+ - @backstage/plugin-permission-node@0.8.0
+ - @backstage/integration@1.13.0
+ - @backstage/plugin-events-node@0.3.8
+ - @backstage/backend-openapi-utils@0.1.15
+ - @backstage/plugin-catalog-node@1.12.4
+ - @backstage/plugin-search-backend-module-catalog@0.1.28
+ - @backstage/plugin-catalog-common@1.0.25
+ - @backstage/catalog-client@1.6.5
+ - @backstage/catalog-model@1.5.0
+ - @backstage/config@1.2.0
+ - @backstage/errors@1.2.4
+ - @backstage/types@1.1.1
+
+## @backstage/plugin-catalog-backend-module-ldap@0.7.0
+
+### Minor Changes
+
+- cb32ca7: **BREAKING**: `readLdapOrg` and the `LdapProviderConfig` type now always accept arrays of user and group configs, not just single items.
+
+ Added support for single ldap catalog provider to provide list and undefined user and group bindings next to standard single one.
+
+### Patch Changes
+
+- 083eaf9: Fix bug where ISO durations could no longer be used for schedules
+- Updated dependencies
+ - @backstage/backend-plugin-api@0.7.0
+ - @backstage/backend-tasks@0.5.27
+ - @backstage/plugin-catalog-node@1.12.4
+ - @backstage/plugin-catalog-common@1.0.25
+ - @backstage/catalog-model@1.5.0
+ - @backstage/config@1.2.0
+ - @backstage/errors@1.2.4
+ - @backstage/types@1.1.1
+
+## @backstage/plugin-permission-common@0.8.0
+
+### Minor Changes
+
+- f4085b8: **BREAKING**: Removed the deprecated and unused `token` option from `EvaluatorRequestOptions`. The `PermissionsClient` now has its own `PermissionClientRequestOptions` type that declares the `token` option instead.
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/config@1.2.0
+ - @backstage/errors@1.2.4
+ - @backstage/types@1.1.1
+
+## @backstage/plugin-permission-node@0.8.0
+
+### Minor Changes
+
+- 36f91e8: **BREAKING**: Updated the `ServerPermissionClient` to match the new `PermissionsService` interface, where the deprecated `token` option has been removed and the options are now required.
+
+### Patch Changes
+
+- ed10fd2: The `PermissionPolicy` interface has been updated to align with the recent changes to the Backstage auth system. The second argument to the `handle` method is now of the new `PolicyQueryUser` type. This type maintains the old fields from the `BackstageIdentityResponse`, which are now all deprecated. Instead, two new fields have been added, which allows access to the same information:
+
+ - `credentials` - A `BackstageCredentials` object, which is useful for making requests to other services on behalf of the user as part of evaluating the policy. This replaces the deprecated `token` field. See the [Auth Service documentation](https://backstage.io/docs/backend-system/core-services/auth#creating-request-tokens) for information about how to create a token using these credentials.
+ - `info` - A `BackstageUserInfo` object, which contains the same information as the deprecated `identity`, except for the `type` field that was redundant.
+
+ Most existing policies can be updated by replacing the `BackstageIdentityResponse` type with `PolicyQueryUser`, which is exported from `@backstage/plugin-permission-node`, as well as replacing any occurrences of `user?.identity` with `user?.info`.
+
+- 28b2cfb: Fix invalid cross-reference in API Reference docs
+
+- Updated dependencies
+ - @backstage/backend-plugin-api@0.7.0
+ - @backstage/backend-common@0.23.3
+ - @backstage/plugin-permission-common@0.8.0
+ - @backstage/plugin-auth-node@0.4.17
+ - @backstage/config@1.2.0
+ - @backstage/errors@1.2.4
+
+## @backstage/plugin-scaffolder@1.23.0
+
+### Minor Changes
+
+- 52b6db0: Use virtualization with `EntityPicker` as done earlier with `MultiEntityPicker` to fix performance issues with large data sets. `VirtualizedListbox` extracted into reusable component.
+- 3583ce5: Use virtualization with `MultiEntityPicker`. Fixes performance issues with large data sets.
+- b5deed0: Add support for `bitbucketCloud` autocomplete in `RepoUrlPicker`
+
+### Patch Changes
+
+- 4d7e11f: enable resizing of the task log stream viewer
+- 661b354: Fixed a bug where the `RepoUrlPicker` would still require the `owner` field for `azure`
+- cc81579: Updated dependency `@rjsf/utils` to `5.18.5`.
+ Updated dependency `@rjsf/core` to `5.18.5`.
+ Updated dependency `@rjsf/material-ui` to `5.18.5`.
+ Updated dependency `@rjsf/validator-ajv8` to `5.18.5`.
+- 89c44b3: Support `catalogFilter` array on `OwnedEntityPicker`
+- Updated dependencies
+ - @backstage/core-components@0.14.9
+ - @backstage/integration@1.13.0
+ - @backstage/plugin-catalog-react@1.12.2
+ - @backstage/plugin-scaffolder-react@1.10.0
+ - @backstage/plugin-permission-react@0.4.24
+ - @backstage/plugin-catalog-common@1.0.25
+ - @backstage/plugin-scaffolder-common@1.5.4
+ - @backstage/frontend-plugin-api@0.6.7
+ - @backstage/integration-react@1.1.29
+ - @backstage/catalog-client@1.6.5
+ - @backstage/catalog-model@1.5.0
+ - @backstage/core-compat-api@0.2.7
+ - @backstage/core-plugin-api@1.9.3
+ - @backstage/errors@1.2.4
+ - @backstage/types@1.1.1
+
+## @backstage/plugin-scaffolder-backend@1.23.0
+
+### Minor Changes
+
+- b5deed0: Add support for `autocomplete` extension point to provide additional `autocomplete` handlers
+- 0b52438: Serialization of the scaffolder workspace into GCP bucket
+
+### Patch Changes
+
+- b9451dd: Updated `catalog:write` scaffolder action to show correct file path location in log message
+- ff1bb4c: Added a documentation how to use checkpoints
+- da90cce: Updated dependency `esbuild` to `^0.21.0`.
+- 62d1fe3: Fix user entity not being fetched for scaffolder dry runner
+- Updated dependencies
+ - @backstage/backend-plugin-api@0.7.0
+ - @backstage/backend-common@0.23.3
+ - @backstage/backend-tasks@0.5.27
+ - @backstage/plugin-scaffolder-backend-module-github@0.4.0
+ - @backstage/plugin-permission-common@0.8.0
+ - @backstage/plugin-permission-node@0.8.0
+ - @backstage/plugin-scaffolder-backend-module-gitlab@0.4.4
+ - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.1.12
+ - @backstage/integration@1.13.0
+ - @backstage/plugin-scaffolder-backend-module-azure@0.1.14
+ - @backstage/plugin-scaffolder-node@0.4.8
+ - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.1.12
+ - @backstage/plugin-bitbucket-cloud-common@0.2.21
+ - @backstage/plugin-auth-node@0.4.17
+ - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.20
+ - @backstage/plugin-catalog-node@1.12.4
+ - @backstage/plugin-scaffolder-backend-module-bitbucket@0.2.12
+ - @backstage/plugin-scaffolder-backend-module-gerrit@0.1.14
+ - @backstage/plugin-scaffolder-backend-module-gitea@0.1.12
+ - @backstage/plugin-scaffolder-common@1.5.4
+ - @backstage/catalog-client@1.6.5
+ - @backstage/catalog-model@1.5.0
+ - @backstage/config@1.2.0
+ - @backstage/errors@1.2.4
+ - @backstage/types@1.1.1
+
+## @backstage/plugin-scaffolder-backend-module-gcp@0.1.0
+
+### Minor Changes
+
+- 0b52438: Serialization of the scaffolder workspace into GCP bucket
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/backend-plugin-api@0.7.0
+ - @backstage/integration@1.13.0
+ - @backstage/plugin-scaffolder-node@0.4.8
+ - @backstage/config@1.2.0
+ - @backstage/errors@1.2.4
+
+## @backstage/plugin-scaffolder-backend-module-github@0.4.0
+
+### Minor Changes
+
+- 70c4b36: Adds support for custom tag policies when creating GitHub environments.
+
+### Patch Changes
+
+- ccfc9d1: Fixed bug resulting from missing required owner and repo arguments in `getEnvironmentPublicKey` in action `github:environment:create`.
+
+ Adding environment secrets now works as expected.
+
+- 141f366: Added action to enable GitHub Pages on a repo
+
+- 4410fed: Fixed issue with octokit call missing owner and repo when creating environment variables and secrets using github:environment:create action
+
+- dfaa28d: Adds `requireLastPushApproval` input property to configure Branch Protection Settings in `github:publish` action
+
+ Adds `requireLastPushApproval` input property to configure Branch Protection Settings in `github:repo:push` action
+
+- Updated dependencies
+ - @backstage/backend-plugin-api@0.7.0
+ - @backstage/backend-common@0.23.3
+ - @backstage/integration@1.13.0
+ - @backstage/plugin-scaffolder-node@0.4.8
+ - @backstage/config@1.2.0
+ - @backstage/errors@1.2.4
+
+## @backstage/plugin-scaffolder-react@1.10.0
+
+### Minor Changes
+
+- 354e68c: Improve validation error display text in scaffolder
+- b5deed0: Add support for `bitbucketCloud` autocomplete in `RepoUrlPicker`
+
+### Patch Changes
+
+- cc81579: Updated dependency `@rjsf/utils` to `5.18.5`.
+ Updated dependency `@rjsf/core` to `5.18.5`.
+ Updated dependency `@rjsf/material-ui` to `5.18.5`.
+ Updated dependency `@rjsf/validator-ajv8` to `5.18.5`.
+- 4d7e11f: disables rendering of output box if no output is returned
+- Updated dependencies
+ - @backstage/core-components@0.14.9
+ - @backstage/plugin-catalog-react@1.12.2
+ - @backstage/plugin-permission-react@0.4.24
+ - @backstage/plugin-scaffolder-common@1.5.4
+ - @backstage/catalog-client@1.6.5
+ - @backstage/catalog-model@1.5.0
+ - @backstage/core-plugin-api@1.9.3
+ - @backstage/theme@0.5.6
+ - @backstage/types@1.1.1
+ - @backstage/version-bridge@1.0.8
+
+## @backstage/app-defaults@1.5.8
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/core-components@0.14.9
+ - @backstage/core-app-api@1.14.0
+ - @backstage/plugin-permission-react@0.4.24
+ - @backstage/core-plugin-api@1.9.3
+ - @backstage/theme@0.5.6
+
+## @backstage/backend-common@0.23.3
+
+### Patch Changes
+
+- 8c09c97: Deprecate legacy status check factory, handler and types.
+- d228862: Update default backend plugin created by the cli to use non-deprecated error handling middleware
+- c964a3d: Add dependencies that are needed by cross-imports from backend-defaults
+- b60db08: Fixing exporting of classes properly from new packages
+- b9ed1bb: bumped better-sqlite3 from ^9.0.0 to ^11.0.0
+- Updated dependencies
+ - @backstage/backend-plugin-api@0.7.0
+ - @backstage/integration@1.13.0
+ - @backstage/plugin-auth-node@0.4.17
+ - @backstage/config-loader@1.8.1
+ - @backstage/backend-dev-utils@0.1.4
+ - @backstage/cli-common@0.1.14
+ - @backstage/config@1.2.0
+ - @backstage/errors@1.2.4
+ - @backstage/integration-aws-node@0.1.12
+ - @backstage/types@1.1.1
+
+## @backstage/backend-dynamic-feature-service@0.2.15
+
+### Patch Changes
+
+- b05e1e1: Service factories exported by this package have been updated to use the new service factory format that doesn't use a callback.
+- Updated dependencies
+ - @backstage/backend-plugin-api@0.7.0
+ - @backstage/backend-app-api@0.8.0
+ - @backstage/backend-common@0.23.3
+ - @backstage/cli-node@0.2.7
+ - @backstage/backend-tasks@0.5.27
+ - @backstage/plugin-permission-common@0.8.0
+ - @backstage/plugin-permission-node@0.8.0
+ - @backstage/plugin-scaffolder-node@0.4.8
+ - @backstage/plugin-events-node@0.3.8
+ - @backstage/plugin-auth-node@0.4.17
+ - @backstage/plugin-catalog-backend@1.24.0
+ - @backstage/plugin-app-node@0.1.22
+ - @backstage/plugin-events-backend@0.3.9
+ - @backstage/plugin-search-backend-node@1.2.27
+ - @backstage/config-loader@1.8.1
+ - @backstage/plugin-search-common@1.2.13
+ - @backstage/cli-common@0.1.14
+ - @backstage/config@1.2.0
+ - @backstage/errors@1.2.4
+ - @backstage/types@1.1.1
+
+## @backstage/backend-openapi-utils@0.1.15
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/backend-plugin-api@0.7.0
+ - @backstage/errors@1.2.4
+
+## @backstage/backend-tasks@0.5.27
+
+### Patch Changes
+
+- 083eaf9: Fix bug where ISO durations could no longer be used for schedules
+- Updated dependencies
+ - @backstage/backend-plugin-api@0.7.0
+ - @backstage/backend-common@0.23.3
+ - @backstage/config@1.2.0
+ - @backstage/errors@1.2.4
+ - @backstage/types@1.1.1
+
+## @backstage/backend-test-utils@0.4.4
+
+### Patch Changes
+
+- 2f99178: The `ServiceFactoryTest.get` method was deprecated and the `ServiceFactoryTest.getSubject` should be used instead. The `getSubject` method has the same behavior, but has a better method name to indicate that the service instance returned is the subject currently being tested.
+- edf5cc3: The function `isDockerDisabledForTests` is deprecated and will no longer be exported in the near future as it should only be used internally.
+- b05e1e1: Service factories exported by this package have been updated to use the new service factory format that doesn't use a callback.
+- fce7887: Added mock for the Root Health Service in `mockServices`.
+- 906c817: Updated `startTestBackend` and `ServiceFactoryTester` to only accept plain service factory or backend feature objects, no longer supporting the callback form. This lines up with the changes to `@backstage/backend-plugin-api` and should not require any code changes.
+- 95a3a0b: Rename frontend and backend `setupRequestMockHandlers` methods to `registerMswTestHooks`.
+- b9ed1bb: bumped better-sqlite3 from ^9.0.0 to ^11.0.0
+- 98ccf00: Internal refactor of `mockServices.httpAuth.factory` to allow it to still be constructed with options, but without declaring options via `createServiceFactory`.
+- Updated dependencies
+ - @backstage/backend-plugin-api@0.7.0
+ - @backstage/backend-defaults@0.4.0
+ - @backstage/backend-app-api@0.8.0
+ - @backstage/plugin-events-node@0.3.8
+ - @backstage/plugin-auth-node@0.4.17
+ - @backstage/config@1.2.0
+ - @backstage/errors@1.2.4
+ - @backstage/types@1.1.1
+
+## @backstage/cli@0.26.11
+
+### Patch Changes
+
+- 133464c: Added experimental support for dynamic frontend plugin builds, enabled via setting `EXPERIMENTAL_MODULE_FEDERATION` for the app build, and using the `frontend-dynamic-container` package role to create a container. Both of these are experimental and will change in the future.
+- e2e320c: - remove unused dependencies `winston` and `yn` from the template of backend plugins;
+ - update `msw` to version `2.3.1` in the template of backend plugins;
+ starting with v1 and switching later to v2 is tedious and not straight forward; it's easier to start with v2;
+- 0540c5a: Updated the scaffolding output message for `plugin-common` in `backstage-cli`. Now, when executing `backstage-cli new` to create a new `plugin-common` package, the output message accurately reflects the action by displaying `Creating common plugin package...` instead of the previous, less accurate `Creating backend plugin...`.
+- 7652db4: Only bootstrap global-agent if it's actually being used
+- f0c0039: Fix issue with CLI that was preventing upgrading from 1.28
+- d228862: Update default backend plugin created by the cli to use non-deprecated error handling middleware
+- da90cce: Updated dependency `esbuild` to `^0.21.0`.
+- a60d73b: Fix a few minor issues with the backend template that were causing failing linting checks in the main repo.
+- 0510d98: Subpath export `package.json` should be of a unique name to avoid typescript resolution issues
+- 4baac0c: The `backendPlugin` and `backendModule` factory now includes a step for automatically adding the new backend plugin/module to the `index.ts` file of the backend.
+- Updated dependencies
+ - @backstage/cli-node@0.2.7
+ - @backstage/integration@1.13.0
+ - @backstage/config-loader@1.8.1
+ - @backstage/catalog-model@1.5.0
+ - @backstage/cli-common@0.1.14
+ - @backstage/config@1.2.0
+ - @backstage/errors@1.2.4
+ - @backstage/eslint-plugin@0.1.8
+ - @backstage/release-manifests@0.0.11
+ - @backstage/types@1.1.1
+
+## @backstage/cli-node@0.2.7
+
+### Patch Changes
+
+- 133464c: Added internal metadata for the new experimental `frontend-dynamic-container` role.
+- Updated dependencies
+ - @backstage/cli-common@0.1.14
+ - @backstage/errors@1.2.4
+ - @backstage/types@1.1.1
+
+## @backstage/core-compat-api@0.2.7
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/frontend-plugin-api@0.6.7
+ - @backstage/core-plugin-api@1.9.3
+ - @backstage/version-bridge@1.0.8
+
+## @backstage/core-components@0.14.9
+
+### Patch Changes
+
+- d4ffdbb: Fixed bug where `