Merge branch 'master' into milliehartnt123-create-ui-doc

Signed-off-by: milliehartnt123 <108491788+milliehartnt123@users.noreply.github.com>
This commit is contained in:
milliehartnt123
2025-12-23 10:17:58 -05:00
committed by GitHub
1172 changed files with 45388 additions and 15688 deletions
+54 -54
View File
@@ -10,31 +10,31 @@ Backstage plugins strive to be self-contained, with as much functionality as pos
Backstage provides two primary methods for plugins to communicate across their
boundaries in client-side code. The first one being the
[`createPlugin`](../reference/core-plugin-api.createplugin.md) API along with the
[`createPlugin`](https://backstage.io/api/stable/functions/_backstage_core-plugin-api.index.createPlugin.html) API along with the
extensions that it can provide, and the second one being Utility APIs. While the
[`createPlugin`](../reference/core-plugin-api.createplugin.md) API is focused on
[`createPlugin`](https://backstage.io/api/stable/functions/_backstage_core-plugin-api.index.createPlugin.html) API is focused on
the initialization plugins and the app, the Utility APIs provide ways for
plugins to communicate during their entire life cycle.
## Consuming APIs
Each Utility API is tied to an [`ApiRef`](../reference/core-plugin-api.apiref.md)
Each Utility API is tied to an [`ApiRef`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ApiRef.html)
instance, which is a global singleton object without any additional state or
functionality, its only purpose is to reference Utility APIs.
[`ApiRef`](../reference/core-plugin-api.apiref.md)s are created using
[`createApiRef`](../reference/core-plugin-api.createapiref.md), which is exported
by [`@backstage/core-plugin-api`](../reference/core-plugin-api.md). There are also
[`ApiRef`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ApiRef.html)s are created using
[`createApiRef`](https://backstage.io/api/stable/functions/_backstage_frontend-plugin-api.createApiRef.html), which is exported
by [`@backstage/core-plugin-api`](https://backstage.io/api/stable/modules/_backstage_core-plugin-api.html). There are also
many predefined Utility APIs in
[`@backstage/core-plugin-api`](../reference/core-plugin-api.md), and they're all
[`@backstage/core-plugin-api`](https://backstage.io/api/stable/modules/_backstage_core-plugin-api.html), and they're all
exported with a name of the pattern `*ApiRef`, for example
[`errorApiRef`](../reference/core-plugin-api.errorapiref.md).
[`errorApiRef`](https://backstage.io/api/stable/variables/_backstage_frontend-plugin-api.errorApiRef.html).
To access one of the Utility APIs inside a React component, use the
[`useApi`](../reference/core-plugin-api.useapi.md) hook exported by
[`@backstage/core-plugin-api`](../reference/core-plugin-api.md), or the
[`withApis`](../reference/core-plugin-api.withapis.md) HOC if you prefer class
[`useApi`](https://backstage.io/api/stable/functions/_backstage_frontend-plugin-api.useApi.html) hook exported by
[`@backstage/core-plugin-api`](https://backstage.io/api/stable/modules/_backstage_core-plugin-api.html), or the
[`withApis`](https://backstage.io/api/stable/functions/_backstage_frontend-plugin-api.withApis.html) HOC if you prefer class
components. For example, the
[`ErrorApi`](../reference/core-plugin-api.errorapi.md) can be accessed like this:
[`ErrorApi`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ErrorApi.html) can be accessed like this:
```tsx
import { useApi, errorApiRef } from '@backstage/core-plugin-api';
@@ -52,14 +52,14 @@ export const MyComponent = () => {
```
Note that there is no explicit type given for
[`ErrorApi`](../reference/core-plugin-api.errorapi.md). This is because the
[`errorApiRef`](../reference/core-plugin-api.errorapiref.md) has the type
embedded, and [`useApi`](../reference/core-plugin-api.useapi.md) is able to infer
[`ErrorApi`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ErrorApi.html). This is because the
[`errorApiRef`](https://backstage.io/api/stable/variables/_backstage_frontend-plugin-api.errorApiRef.html) has the type
embedded, and [`useApi`](https://backstage.io/api/stable/functions/_backstage_frontend-plugin-api.useApi.html) is able to infer
the type.
Also note that consuming Utility APIs is not limited to plugins; it can be done
from any component inside Backstage, including the ones in
[`@backstage/core-plugin-api`](../reference/core-plugin-api.md). The only
[`@backstage/core-plugin-api`](https://backstage.io/api/stable/modules/_backstage_core-plugin-api.html). The only
requirement is that they are beneath the `AppProvider` in the react tree.
## Supplying APIs
@@ -67,15 +67,15 @@ requirement is that they are beneath the `AppProvider` in the react tree.
### API Factories
APIs are registered in the form of
[`ApiFactory`](../reference/core-plugin-api.apifactory.md) instances, which encapsulate
[`ApiFactory`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ApiFactory.html) instances, which encapsulate
the process of instantiating an API. It is a collection of three things: the
[`ApiRef`](../reference/core-plugin-api.apiref.md) of the API to instantiate, a
[`ApiRef`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ApiRef.html) of the API to instantiate, a
list of all required dependencies, and a factory function that returns a new API
instance.
For example, this is the default
[`ApiFactory`](../reference/core-plugin-api.apifactory.md) for the
[`ErrorApi`](../reference/core-plugin-api.errorapi.md):
[`ApiFactory`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ApiFactory.html) for the
[`ErrorApi`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ErrorApi.html):
```ts
createApiFactory({
@@ -89,25 +89,25 @@ createApiFactory({
});
```
In this example, the [`errorApiRef`](../reference/core-plugin-api.errorapiref.md)
In this example, the [`errorApiRef`](https://backstage.io/api/stable/variables/_backstage_frontend-plugin-api.errorApiRef.html)
is our API, which encapsulates the
[`ErrorApi`](../reference/core-plugin-api.errorapi.md) type. The
[`alertApiRef`](../reference/core-plugin-api.alertapiref.md) is our single
[`ErrorApi`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ErrorApi.html) type. The
[`alertApiRef`](https://backstage.io/api/stable/variables/_backstage_frontend-plugin-api.alertApiRef.html) is our single
dependency, which we give the name `alertApi`, and is then passed on to the
factory function, which returns an implementation of the
[`ErrorApi`](../reference/core-plugin-api.errorapi.md).
[`ErrorApi`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ErrorApi.html).
The [`createApiFactory`](../reference/core-plugin-api.createapifactory.md)
The [`createApiFactory`](https://backstage.io/api/stable/functions/_backstage_frontend-plugin-api.createApiFactory.html)
function is a thin wrapper that enables TypeScript type inference. You may
notice that there are no type annotations in the above example, and that is
because we're able to infer all types from the
[`ApiRef`](../reference/core-plugin-api.apiref.md)s. TypeScript will make sure
[`ApiRef`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ApiRef.html)s. TypeScript will make sure
that the return value of the `factory` function matches the type embedded in
`api`'s [`ApiRef`](../reference/core-plugin-api.apiref.md), in this case the
[`ErrorApi`](../reference/core-plugin-api.errorapi.md). It will also match the
`api`'s [`ApiRef`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ApiRef.html), in this case the
[`ErrorApi`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ErrorApi.html). It will also match the
types between the `deps` and the parameters of the `factory` function, again
using the type embedded within the
[`ApiRef`](../reference/core-plugin-api.apiref.md)s.
[`ApiRef`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ApiRef.html)s.
## Registering API Factories
@@ -119,13 +119,13 @@ app, and the app itself.
Starting with the Backstage core library, it provides implementations for all of
the core APIs. The core APIs are the ones exported by
[`@backstage/core-plugin-api`](../reference/core-plugin-api.md), such as the
[`errorApiRef`](../reference/core-plugin-api.errorapiref.md) and
[`configApiRef`](../reference/core-plugin-api.configapiref.md).
[`@backstage/core-plugin-api`](https://backstage.io/api/stable/modules/_backstage_core-plugin-api.html), such as the
[`errorApiRef`](https://backstage.io/api/stable/variables/_backstage_frontend-plugin-api.errorApiRef.html) and
[`configApiRef`](https://backstage.io/api/stable/variables/_backstage_frontend-plugin-api.configApiRef.html).
The core APIs are loaded for any app created with
[`createApp`](../reference/app-defaults.createapp.md) from
[`@backstage/core-plugin-api`](../reference/app-defaults.md), which means that
[`createApp`](https://backstage.io/api/stable/functions/_backstage_app-defaults.createApp.html) from
[`@backstage/core-plugin-api`](https://backstage.io/api/stable/modules/_backstage_core-plugin-api.html), which means that
there is no step that needs to be taken to include these APIs in an app.
### Plugin APIs
@@ -133,13 +133,13 @@ there is no step that needs to be taken to include these APIs in an app.
In addition to the core APIs, plugins can define and export their own APIs.
While doing so, they should usually also provide default implementations of their
own APIs; for example, the `catalog` plugin exports `catalogApiRef` and also
supplies a default [`ApiFactory`](../reference/core-plugin-api.apifactory.md) of
supplies a default [`ApiFactory`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ApiFactory.html) of
that API using the `CatalogClient`. There is one restriction to plugin-provided
API Factories: plugins may not supply factories for core APIs; trying to do so
will cause the app to refuse to start.
Plugins supply their APIs through the `apis` option of
[`createPlugin`](../reference/core-plugin-api.createplugin.md), for example:
[`createPlugin`](https://backstage.io/api/stable/functions/_backstage_core-plugin-api.index.createPlugin.html), for example:
```ts
export const techdocsPlugin = createPlugin({
@@ -164,7 +164,7 @@ Lastly, the app itself is the final point where APIs can be added, and what has
the final say in what APIs will be loaded at runtime? The app may override the
factories for any of the core or plugin APIs, with the exception of the config,
app theme, and identity APIs. These are static APIs that are tied into the
[`createApp`](../reference/app-defaults.createapp.md) implementation and
[`createApp`](https://backstage.io/api/stable/functions/_backstage_app-defaults.createApp.html) implementation and
therefore, not possible to override.
Overriding APIs is useful for apps that want to switch out behavior to tailor it
@@ -227,33 +227,33 @@ const app = createApp({
```
Note that the above line will cause an error if `IgnoreErrorApi` does not fully
implement the [`ErrorApi`](../reference/core-plugin-api.errorapi.md), as it is
implement the [`ErrorApi`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ErrorApi.html), as it is
checked by the type embedded in the
[`errorApiRef`](../reference/core-plugin-api.errorapiref.md) at compile time.
[`errorApiRef`](https://backstage.io/api/stable/variables/_backstage_frontend-plugin-api.errorApiRef.html) at compile time.
## Defining custom Utility APIs
Plugins are free to define their own Utility APIs. Simply define the TypeScript
interface for the API and create an
[`ApiRef`](../reference/core-plugin-api.apiref.md) using
[`createApiRef`](../reference/core-plugin-api.createapiref.md) exported from
[`@backstage/core-plugin-api`](../reference/core-plugin-api.md). Also, be sure to
[`ApiRef`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ApiRef.html) using
[`createApiRef`](https://backstage.io/api/stable/functions/_backstage_frontend-plugin-api.createApiRef.html) exported from
[`@backstage/core-plugin-api`](https://backstage.io/api/stable/modules/_backstage_core-plugin-api.html). Also, be sure to
provide at least one implementation of the API and to declare a default factory
for the API in [`createPlugin`](../reference/core-plugin-api.createplugin.md).
for the API in [`createPlugin`](https://backstage.io/api/stable/functions/_backstage_core-plugin-api.index.createPlugin.html).
Custom Utility APIs can be either public or private, which is up to the plugin to choose. Private APIs do not expose an external API surface, and it's therefore possible to make breaking changes to the API without affecting other users of the plugin. If an API is made public, however, it opens up for other plugins to make use of the API, and it also makes it possible for users for your plugin to override the API in the app. It is, however, important to maintain backward compatibility of public APIs, as you may otherwise break apps that are using your plugin.
To make an API public, simply export the
[`ApiRef`](../reference/core-plugin-api.apiref.md) of the API, and any associated
[`ApiRef`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ApiRef.html) of the API, and any associated
types. To make an API private, just avoid exporting the
[`ApiRef`](../reference/core-plugin-api.apiref.md), but still be sure to supply a
default factory to [`createPlugin`](../reference/core-plugin-api.createplugin.md).
[`ApiRef`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ApiRef.html), but still be sure to supply a
default factory to [`createPlugin`](https://backstage.io/api/stable/functions/_backstage_core-plugin-api.index.createPlugin.html).
Private APIs are useful for plugins that want to depend on other APIs outside of
React components, but not have to expose an entire API surface to maintain. When
using private APIs, it is fine to use the `typeof` of an implementing class as
the type parameter passed to
[`createApiRef`](../reference/core-plugin-api.createapiref.md), while public APIs
[`createApiRef`](https://backstage.io/api/stable/functions/_backstage_frontend-plugin-api.createApiRef.html), while public APIs
should always define a separate TypeScript interface type.
Plugins may depend on APIs from other plugins, both in React components and as
@@ -262,13 +262,13 @@ dependencies between plugins.
## Architecture
The [`ApiRef`](../reference/core-plugin-api.apiref.md) instances mentioned above
The [`ApiRef`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ApiRef.html) instances mentioned above
provide a point of indirection between consumers and producers of Utility APIs.
It allows for plugins and components to depend on APIs in a type-safe way,
without having a direct reference to a concrete implementation of the APIs. The
Apps are also given a lot of flexibility in what implementations to provide. As
long as they adhere to the contract established by an
[`ApiRef`](../reference/core-plugin-api.apiref.md), they are free to choose any
[`ApiRef`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ApiRef.html), they are free to choose any
implementation they want.
The figure below shows the relationship between
@@ -291,16 +291,16 @@ The indirection provided by Utility APIs also makes it straightforward to test
components that depend on APIs, and to provide a standard common development
environment for plugins. A proper test wrapper with mocked API implementations
is not yet ready, but it will be provided as a part of
[`@backstage/test-utils`](../reference/test-utils.md). It will provide mocked
[`@backstage/test-utils`](https://backstage.io/api/stable/modules/_backstage_test-utils.html). It will provide mocked
variants of APIs, with additional methods for asserting a component's
interaction with the API.
The common development environment for plugins is included in
[`@backstage/dev-utils`](../reference/dev-utils.md), where the exported
[`createDevApp`](../reference/dev-utils.createdevapp.md) function creates an
[`@backstage/dev-utils`](https://backstage.io/api/stable/modules/_backstage_dev-utils.html), where the exported
[`createDevApp`](https://backstage.io/api/stable/functions/_backstage_dev-utils.createDevApp.html) function creates an
application with implementations for all core APIs already present. Contrary to
the method for wiring up Utility API implementations in an app created with
[`createApp`](../reference/app-defaults.createapp.md),
[`createDevApp`](../reference/dev-utils.createdevapp.md) uses automatic dependency
[`createApp`](https://backstage.io/api/stable/functions/_backstage_app-defaults.createApp.html),
[`createDevApp`](https://backstage.io/api/stable/functions/_backstage_dev-utils.createDevApp.html) uses automatic dependency
injection. This is to make it possible to replace any API implementation, and
having that be reflected in dependents of that API.
+37 -1
View File
@@ -340,7 +340,7 @@ The method with which frontend plugins request access to third-party services is
through [Utility APIs](../api/utility-apis.md) for each service provider. These
are all suffixed with `*AuthApiRef`, for example `githubAuthApiRef`. For a
full list of providers, see the
[@backstage/core-plugin-api](../reference/core-plugin-api.md#variables) reference.
[@backstage/core-plugin-api](https://backstage.io/api/stable/modules/_backstage_core-plugin-api.index.html#alertapiref) reference.
## Custom Authentication Provider
@@ -459,6 +459,42 @@ providerFactories: {
},
```
In the new backend system you can leverage the `authProvidersExtensionPoint` for this:
```ts
// your-auth-plugin-module.ts
export const gheAuth = createBackendModule({
// This ID must be exactly "auth" because that's the plugin it targets
pluginId: 'auth',
// This ID must be unique, but can be anything
moduleId: 'ghe-auth-provider',
register(reg) {
reg.registerInit({
deps: {
providers: authProvidersExtensionPoint,
logger: coreServices.logger,
},
async init({ providers, logger }) {
providers.registerProvider({
// This ID must match the actual provider config, e.g. addressing
// auth.providers.ghe means that this must be "ghe".
providerId: 'ghe',
factory: createOAuthProviderFactory({
authenticator: githubAuthenticator,
signInResolverFactories: {
...commonSignInResolvers,
},
}),
});
},
});
},
});
// backend index.ts
backend.add(gheAuth);
```
## Configuring token issuers
By default, the Backstage authentication backend generates and manages its own signing keys automatically for any issued
+6
View File
@@ -241,6 +241,12 @@ These parameters have implicit default values. Don't override them unless you kn
- `prompt`: Recommended to use `auto` so the browser will request sign-in to the IDP if the
user has no active session.
- `sessionDuration`: Lifespan of the user session.
- `startUrlSearchParams`: This is a dictionary of search (query) parameters for the OIDC
authorization start URL. Don't define it unless you want to change the identity
provider's behavior. (For example, you could set the `organization` parameter to guide
users towards a particular sign-in option that your organization prefers.) **Note:** the
start URL is controlled by the browser, so this feature is only for improving the
Backstage user experience.
:::note Config Reloading
Backstage does not yet support hot reloading of auth provider configuration. Any changes to this YAML file require a restart of Backstage.
@@ -38,3 +38,28 @@ Once you have added all desired features we call the `.start()` method. This cau
Underneath the hood, `createBackend` calls `createSpecializedBackend` from `@backstage/backend-app-api` which is responsible for actually creating the backend instance, without any services or features. You can think of `createBackend` more of a 'batteries included' approach, while `createSpecializedBackend` is more low level.
As mentioned previously there's also the ability to create multiple of these backends in your project so that you can split apart your backend and deploy different backends that can scale independently of each other. For instance you might choose to deploy a backend with only the catalog plugin enabled, and one with just the scaffolder plugin enabled.
### Backend Startup Result
The `Backend.start()` method returns a `BackendStartupResult` with detailed success/failure status and timing information for all plugins and modules. When startup fails, a `BackendStartupError` is thrown that includes the complete startup results, making it easier to diagnose which plugins or modules failed.
```ts
backend.start(
({ result }) => {
console.log(`Backend startup result: ${JSON.stringify(result, null, 2)}`);
},
error => {
if (error instanceof BackendStartupError) {
console.error(
`Backend startup failed: ${JSON.stringify(error.result, null, 2)}`,
);
} else {
console.error(
`Unexpected error during backend startup: ${error.message}`,
);
}
},
);
```
This information is mostly useful if you want to add additional monitoring or debugging tools to your backend. The information is a structured representation of what is already logged during startup.
+67 -6
View File
@@ -11,24 +11,84 @@ This service lets your plugin interact with a cache. It is bound to your plugin
The cache service can be configured using the `backend.cache` section in your `app-config.yaml`:
### In-Memory (default)
```yaml
backend:
cache:
store: redis # or 'valkey', 'memcache', 'memory'
store: memory
```
### Memcache
```yaml
backend:
cache:
store: memcache
connection: user:pass@cache.example.com:11211
```
### Redis
```yaml
backend:
cache:
store: redis
connection: redis://localhost:6379
# Store-specific configuration (Redis/Valkey only)
# Store-specific configuration (optional)
redis:
client:
# Optional: Global namespace prefix for all cache keys
# Global namespace prefix for all cache keys
namespace: 'my-app'
# Optional: Separator used between namespace and plugin ID (default: ':')
# Separator used between namespace and plugin ID (default: ':')
keyPrefixSeparator: ':'
# Other Redis-specific options...
clearBatchSize: 1000
useUnlink: false
```
### Valkey
```yaml
backend:
cache:
store: valkey
connection: redis://localhost:6379
# Store-specific configuration (optional)
valkey:
# Global namespace prefix for all cache keys (including separator used between namespace and plugin ID)
keyPrefix: 'my-app:'
```
### Infinispan
```yaml
backend:
cache:
store: infinispan
# Store-specific configuration (optional)
infinispan:
servers:
# IP address or hostname of the server (default: '127.0.0.1')
- host: 127.0.0.1
# Port number of the server (default: '11222')
port: 11222
# Name of the cache (default: 'cache')
cacheName: cache
mediaType: application/json
authentication:
# Whether authentication is enabled (default: 'false')
enabled: true
userName: yourusername
password: yourpassword
saslMechanism: PLAIN
```
A full list of configuration items is available [here](https://docs.jboss.org/infinispan/hotrod-clients/javascript/1.0/apidocs/module-infinispan.html), including support for backup clusters.
### Namespace Configuration
For Redis and Valkey stores, you can configure a global namespace that will be prefixed to all cache keys:
@@ -36,9 +96,10 @@ For Redis and Valkey stores, you can configure a global namespace that will be p
- **Without namespace**: Cache keys use only the plugin ID (e.g., `catalog:some-key`)
- **With namespace**: Cache keys use the format `namespace:pluginId:key` (e.g., `my-app:catalog:some-key`)
The `keyPrefixSeparator` controls what character is used between the namespace and plugin ID (defaults to `:`).
For **Redis**, `keyPrefixSeparator` controls what character is used between the namespace and plugin ID (defaults to `:`).
For **Valkey**, you set the full `keyPrefix` including the separator.
**Note**: Memory and Memcache stores do not support namespace configuration and will always use the plugin ID directly.
**Note**: In-memory, Memcache and Infinispan stores do not support namespace configuration and will always use the plugin ID directly.
## Using the service
+2 -2
View File
@@ -7,7 +7,7 @@ description: Documentation on Reading Backstage Configuration
## Config API
There's a common configuration API for by both frontend and backend plugins. An
API reference can be found [here](../reference/config.config.md).
API reference can be found [here](https://backstage.io/api/stable/types/_backstage_config.Config.html).
The configuration API is tailored towards failing fast in case of missing or bad
config. That's because configuration errors can always be considered programming
@@ -115,7 +115,7 @@ example `getString`. These will throw an error if there is no value available.
## Accessing ConfigApi in Frontend Plugins
The [ConfigApi](../reference/core-plugin-api.configapi.md) in the frontend is a
The [ConfigApi](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ConfigApi.html) in the frontend is a
[UtilityApi](../api/utility-apis.md). It's accessible as usual via the
`configApiRef` exported from `@backstage/core-plugin-api`:
+17 -16
View File
@@ -103,13 +103,13 @@ Backstage UI is using light by default under `:root` but you can target it more
[data-theme-mode='light'] {
/* Light theme specific styles */
  --bui-bg: #f8f8f8;
  --bui-bg-surface-0: #f8f8f8;
--bui-fg-primary: #000;
}
[data-theme-mode='dark'] {
/* Dark theme specific styles */
  --bui-bg: #333333;
  --bui-bg-surface-0: #333333;
--bui-fg-primary: #fff;
}
```
@@ -122,18 +122,18 @@ We recommend starting with a core set of CSS variables to quickly achieve a bran
And if youd like to go even further, you can target specific component class names for advanced customization.
| Token Name | Description |
| -------------------- | ----------------------------------------------------------------------------------- |
| `--bui-bg` | This is used to define the background color of your app. It will only be used once. |
| `--bui-bg-surface-1` | We ar using this color to sit on top of `--bui-bg` mostly for `Card`, `Dialog`, ... |
| `--bui-bg-surface-2` | This is for content inside elevated components. This colour is less common. |
| `--bui-bg-solid` | This is used for main actions like primary buttons. |
| `--bui-fg-solid` | This is for texts or icons on top of a solid backgrounds. |
| `--bui-fg-primary` | Your primary text or icon colours. |
| `--bui-fg-secondary` | Your secondary text or icon colours. |
| `--bui-fg-link` | Used for links. |
| `--bui-border` | Main borders around surfaces like `Card`, `Dialog`, ... |
| `--bui-font-regular` | The main font of your app. |
| Token Name | Description |
| -------------------- | --------------------------------------------------------------------------------------------- |
| `--bui-bg-surface-0` | This is used to define the background color of your app. It will only be used once. |
| `--bui-bg-surface-1` | We ar using this color to sit on top of `--bui-bg-surface-0` mostly for `Card`, `Dialog`, ... |
| `--bui-bg-surface-2` | This is for content inside elevated components. This colour is less common. |
| `--bui-bg-solid` | This is used for main actions like primary buttons. |
| `--bui-fg-solid` | This is for texts or icons on top of a solid backgrounds. |
| `--bui-fg-primary` | Your primary text or icon colours. |
| `--bui-fg-secondary` | Your secondary text or icon colours. |
| `--bui-fg-link` | Used for links. |
| `--bui-border` | Main borders around surfaces like `Card`, `Dialog`, ... |
| `--bui-font-regular` | The main font of your app. |
<details>
<summary>All available CSS variables</summary>
@@ -157,13 +157,14 @@ These colors are used for special purposes like ring, scrollbar, ...
#### Core background colors
These colors are used for the background of your application. We are mostly using for now a single elevated background for panels. `--bui-bg` should mostly use as the main background color of your app.
These colors are used for the background of your application. We are mostly using for now a single elevated background for panels. `--bui-bg-surface-0` should mostly use as the main background color of your app.
| Token Name | Description |
| ------------------------- | ------------------------------------------------ |
| `--bui-bg` | The background color of your Backstage instance. |
| `--bui-bg-surface-0` | The background color of your Backstage instance. |
| `--bui-bg-surface-1` | Use for any panels or elevated surfaces. |
| `--bui-bg-surface-2` | Use for any panels or elevated surfaces. |
| `--bui-bg-surface-3` | Use for any panels or elevated surfaces. |
| `--bui-bg-solid` | Used for solid background colors. |
| `--bui-bg-solid-hover` | Used for solid background colors when hovered. |
| `--bui-bg-solid-pressed` | Used for solid background colors when pressed. |
+1 -1
View File
@@ -17,7 +17,7 @@ into multiple different services, each running a different set of plugins. This
is a more advanced approach and requires you to be able to route requests to
the appropriate backends based on the plugin ID. Both for ingress, but also
internal traffic between Backstage backends, which is done by creating a custom
implementation of the [DiscoveryService](../reference/backend-plugin-api.discoveryservice.md) interface. See the [backend system docs](../backend-system/building-backends/01-index.md#split-into-multiple-backends) for more details on how to separate your deployment into multiple backend instances.
implementation of the [DiscoveryService](https://backstage.io/api/stable/interfaces/_backstage_backend-plugin-api.index.DiscoveryService.html) interface. See the [backend system docs](../backend-system/building-backends/01-index.md#split-into-multiple-backends) for more details on how to separate your deployment into multiple backend instances.
Lastly, you can also replicate the Backstage deployments across multiple regions.
This is not a pattern that there is built-in support for and typically only makes
@@ -48,6 +48,65 @@ add the `repoVisibility` key within a software template:
repoVisibility: public # or 'internal' or 'private'
```
### Default Environment
The scaffolder supports a `defaultEnvironment` configuration that provides default parameters and secrets to all templates. This reduces template complexity and improves security by centralizing common values.
```yaml
scaffolder:
defaultEnvironment:
parameters:
region: eu-west-1
organizationName: acme-corp
defaultRegistry: registry.acme-corp.com
secrets:
AWS_ACCESS_KEY: ${AWS_ACCESS_KEY}
GITHUB_TOKEN: ${GITHUB_TOKEN}
DOCKER_REGISTRY_TOKEN: ${DOCKER_REGISTRY_TOKEN}
```
#### Default parameters
Default parameters are accessible via `${{ environment.parameters.* }}` in templates. Default parameters are isolated in their own context to avoid naming conflicts.
```yaml
parameters:
- title: Fill in some steps
required:
- organizationName
properties:
organizationName:
title: organizationName
type: string
description: Unique name of the organization
ui:autofocus: true
ui:options:
rows: 5
steps:
- id: deploy
name: Deploy Application
action: aws:deploy
input:
region: ${{ environment.parameters.region }} # Resolves to defaultEnvironment.parameters.region
organization: ${{ parameters.organizationName }} # Resolves to frontend input value
otherOrganization: ${{ environment.parameters.organizationName }} # Resolves to defaultEnvironment.parameters.organizationName
```
#### Secrets
Default secrets are resolved from environment variables and accessible via `${{ environment.secrets.* }}` in template actions. Secrets are only available during action execution, not in frontend forms.
```yaml
- id: deploy
name: Deploy with credentials
action: aws:deploy
input:
accessKey: ${{ environment.secrets.AWS_ACCESS_KEY }} # Resolves to defaultEnvironment.secrets.AWS_ACCESS_KEY
```
**Security Note:** Secrets are automatically masked in logs and are only available to backend actions, never exposed to the frontend.
## Disabling Docker in Docker situation (Optional)
Software templates use the `fetch:template` action by default, which requires no
@@ -468,3 +468,59 @@ repoUrl:
The supported `additionalScopes` values are `gerrit`, `github`, `gitlab`, `bitbucket`, and `azure`.
If you're also using the `RepoUrlPicker` field extension, you should simply duplicate this part from there.
## RepoOwnerPicker
The input props that can be specified under `ui:options` for the `RepoOwnerPicker` field extension.
### `host`
The SCM integration host that owners should be fetched from for autocompletion.
- Fetch owners from `github.com`
```yaml
repoUrl:
title: Repository Owner
type: string
ui:field: RepoOwnerPicker
ui:options:
host: github.com
```
### `excludedOwners`
List of owners that should be excluded from autocompletion.
- Exclude owner `owner_1` from autocompletion
```yaml
repoUrl:
title: Repository Owner
type: string
ui:field: RepoOwnerPicker
ui:options:
excludedOwners:
- owner_1
```
### `requestUserCredentials`
If defined will request user credentials to auth against the given SCM platform.
```yaml
repoUrl:
title: Repository Owner
type: string
ui:field: RepoOwnerPicker
ui:options:
requestUserCredentials:
secretsKey: USER_OAUTH_TOKEN
additionalScopes:
github:
- workflow:write
```
`secretsKey` is the key used within the template secrets context to store the credential and `additionalScopes` is any additional permission scopes to request.
The supported `additionalScopes` values are `gerrit`, `github`, `gitlab`, `bitbucket`, and `azure`.
@@ -555,6 +555,35 @@ The `RepoBranchPicker` is a custom field that we provide part of the
`plugin-scaffolder`. You can provide your own custom fields by
[writing your own Custom Field Extensions](./writing-custom-field-extensions.md)
### The Repository Owner Picker
Similar to the repository picker, there is a picker for owners to support autocompletion. A full example could look like this:
```yaml
- title: Choose an owner
required:
- repoOwner
properties:
repoOwner:
title: Repository Owner
type: string
ui:field: RepoOwnerPicker
ui:options:
host: github.com
excludedOwners:
- backstage
requestUserCredentials:
secretsKey: USER_OAUTH_TOKEN
```
Passing the `requestUserCredentials` and `host` properties is required for autocompletion to work. For more information regarding the `requestUserCredentials` object, please refer to the [Using the Users `oauth` token](#using-the-users-oauth-token) section under [The Repository Picker](#the-repository-picker).
For a list of all possible `ui:options` input props for `RepoOwnerPicker`, please visit [here](./ui-options-examples.md#repoownerpicker).
The `RepoOwnerPicker` is a custom field that we provide part of the
`plugin-scaffolder`. You can provide your own custom fields by
[writing your own Custom Field Extensions](./writing-custom-field-extensions.md)
### Accessing the signed-in users details
Sometimes when authoring templates, you'll want to access the user that is running the template, and get details from the profile or the users `Entity` in the Catalog.
@@ -14,16 +14,16 @@ A Backstage App is a monorepo setup that includes everything you need to run Bac
To create a new Backstage app we recommend using the `@backstage/create-app` command line, and the easiest way to run this package is with `npx`:
:::note
The create-app CLI requires Node.js Active LTS Release.
The create-app CLI requires Node.js Active LTS Release, see the [prerequisites documentation](../../getting-started/index.md) for all the details.
:::
```sh
# The command bellow creates a Backstage App inside the current folder.
# The name of the app-folder is the name that was provided when prompted.
npx @backstage/create-app@latest
npx @backstage/create-app@latest --next
```
The created-app is currently templated for legacy frontend system applications, so the app wiring code it creates needs to be migrated, see [the app instance](#the-app-instance) section for an example.
Using the `--next` flag will result in a Backstage app using the New Frontend System which will be further explained in the sections below.
## The app instance
@@ -676,8 +676,6 @@ createApp({
AppRootWrapperBlueprint.make({
name: 'custom-app-barrier',
params: {
// Whenever your component uses legacy core packages, wrap it with "compatWrapper"
// e.g. props => compatWrapper(<CustomAppBarrier {...props} />)
Component: CustomAppBarrier,
},
}),
@@ -700,41 +698,37 @@ import { SidebarContent } from './Sidebar';
export const navModule = createFrontendModule({
pluginId: 'app',
extensions: [SidebarContent],
extensions: [sidebarContent],
});
```
Then in the actual implementation for the `SidebarContent` extension, you can provide something like the following, where the component that is passed to the `compatWrapper` is the entire `Sidebar` component from your `Root` component.
The `compatWrapper` is there to ensure that any legacy plugins using things like `useRouteRef` work well in the new system, so if you run into some errors which look like compatibility issues, make sure that this wrapper is used in the relevant places.
Then in the actual implementation for the `sidebarContent` extension, you can provide something like the following, where you implement the entire `Sidebar` component.
```tsx title="in packages/app/src/modules/nav/Sidebar.tsx"
import { compatWrapper } from '@backstage/core-compat-api';
import { NavContentBlueprint } from '@backstage/frontend-plugin-api';
export const SidebarContent = NavContentBlueprint.make({
export const sidebarContent = NavContentBlueprint.make({
params: {
component: ({ items }) =>
compatWrapper(
<Sidebar>
<SidebarLogo />
<SidebarGroup label="Search" icon={<SearchIcon />} to="/search">
<SidebarSearchModal />
</SidebarGroup>
<SidebarDivider />
<SidebarGroup label="Menu" icon={<MenuIcon />}>
...
</SidebarGroup>
<SidebarGroup label="Plugins">
<SidebarScrollWrapper>
{/* Items in this group will be scrollable if they run out of space */}
{items.map((item, index) => (
<SidebarItem {...item} key={index} />
))}
</SidebarScrollWrapper>
</SidebarGroup>
</Sidebar>,
),
component: ({ items }) => (
<Sidebar>
<SidebarLogo />
<SidebarGroup label="Search" icon={<SearchIcon />} to="/search">
<SidebarSearchModal />
</SidebarGroup>
<SidebarDivider />
<SidebarGroup label="Menu" icon={<MenuIcon />}>
...
</SidebarGroup>
<SidebarGroup label="Plugins">
<SidebarScrollWrapper>
{/* Items in this group will be scrollable if they run out of space */}
{items.map((item, index) => (
<SidebarItem {...item} key={index} />
))}
</SidebarScrollWrapper>
</SidebarGroup>
</Sidebar>
),
},
});
```
@@ -220,6 +220,6 @@ export const examplePlugin = createFrontendPlugin({
});
```
The `ExampleEntityContent` itself is again a regular React component where you can implement any functionality you want. To access the entity that the content is being rendered for, you can use the `useEntity` hook from `@backstage/plugin-catalog-react`. You can see a full list of APIs provided by the catalog React library in [the API reference](../../reference/plugin-catalog-react.md).
The `ExampleEntityContent` itself is again a regular React component where you can implement any functionality you want. To access the entity that the content is being rendered for, you can use the `useEntity` hook from `@backstage/plugin-catalog-react`. You can see a full list of APIs provided by the catalog React library in [the API reference](https://backstage.io/api/stable/modules/_backstage_plugin-catalog-react.index.html).
For a more complete list of the different kinds of extensions that you can create for your plugin, see the [extension blueprints](./03-common-extension-blueprints.md) section.
@@ -11,35 +11,35 @@ This section covers many of the [extension blueprints](../architecture/23-extens
These are the [extension blueprints](../architecture/23-extension-blueprints.md) provided by the Backstage frontend framework itself.
### Api - [Reference](../../reference/frontend-plugin-api.apiblueprint.md)
### Api - [Reference](https://backstage.io/api/stable/variables/_backstage_frontend-plugin-api.ApiBlueprint.html)
An API extension is used to add or override [Utility API factories](../utility-apis/01-index.md) in the app. They are commonly used by plugins for both internal and shared APIs. There are also many built-in Api extensions provided by the framework that you are able to override.
### NavItem - [Reference](../../reference/frontend-plugin-api.navitemblueprint.md)
### NavItem - [Reference](https://backstage.io/api/stable/variables/_backstage_frontend-plugin-api.NavItemBlueprint.html)
Navigation item extensions are used to provide menu items that link to different parts of the app. By default nav items are attached to the app nav extension, which by default is rendered as the left sidebar in the app.
### Page - [Reference](../../reference/frontend-plugin-api.pageblueprint.md)
### Page - [Reference](https://backstage.io/api/stable/variables/_backstage_frontend-plugin-api.PageBlueprint.html)
Page extensions provide content for a particular route in the app. By default pages are attached to the app routes extensions, which renders the root routes.
### SignInPage - [Reference](../../reference/frontend-plugin-api.signinpageblueprint.md)
### SignInPage - [Reference](https://backstage.io/api/stable/variables/_backstage_frontend-plugin-api.SignInPageBlueprint.html)
Sign-in page extension have a single purpose - to implement a custom sign-in page. They are always attached to the app root extension and are rendered before the rest of the app until the user is signed in.
### SwappableComponent - [Reference](../../reference/frontend-plugin-api.swappablecomponentblueprint.md)
### SwappableComponent - [Reference](https://backstage.io/api/stable/variables/_backstage_frontend-plugin-api.SwappableComponentBlueprint.html)
Swappable Components are extensions that are used to replace the implementations of components in the app and plugins.
### Theme - [Reference](../../reference/frontend-plugin-api.themeblueprint.md)
### Theme - [Reference](https://backstage.io/api/stable/variables/_backstage_frontend-plugin-api.ThemeBlueprint.html)
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)
### Icons - [Reference](https://backstage.io/api/stable/variables/_backstage_frontend-plugin-api.IconBundleBlueprint.html)
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.translationblueprint.md)
### Translation - [Reference](https://backstage.io/api/stable/variables/_backstage_frontend-plugin-api.TranslationBlueprint.html)
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.
@@ -106,7 +106,6 @@ it can be migrated as the following, keeping in mind that you may need to switch
```tsx
import { PageBlueprint } from '@backstage/frontend-plugin-api';
import { compatWrapper } from '@backstage/core-compat-api';
const fooPage = PageBlueprint.make({
params: {
@@ -116,12 +115,7 @@ const fooPage = PageBlueprint.make({
// You can reuse the existing routeRef.
routeRef: rootRouteRef,
// these inputs usually match the props required by the component.
loader: () =>
import('./components/').then(m =>
// The compatWrapper utility allows you to keep using @backstage/core-plugin-api in the
// implementation of the component and switch to @backstage/frontend-plugin-api later.
compatWrapper(<m.FooPage />),
),
loader: () => import('./components/').then(m => <m.FooPage />),
},
});
```
@@ -54,6 +54,8 @@ You need to decide how you want to receive events from external sources like
- [via HTTP endpoint](https://github.com/backstage/backstage/tree/master/plugins/events-backend/README.md)
- [via an AWS SQS queue](https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-aws-sqs/README.md)
- [via Google Pub/Sub](https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-google-pubsub/README.md)
- [via a Kafka topic](https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-kafka/README.md)
Further documentation:
@@ -72,6 +74,8 @@ Additionally, you need to decide how you want to receive events from external so
- [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)
- [via Google Pub/Sub](https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-google-pubsub/README.md)
- [via a Kafka topic](https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-kafka/README.md)
Set up your provider
+12 -1
View File
@@ -32,6 +32,15 @@ integrations:
appPassword: my-password
```
OAuth 2.0 client credentials flow:
```yaml
integrations:
bitbucketCloud:
- clientId: client-id
clientSecret: client-secret
```
:::note Note
A public Bitbucket Cloud provider is added automatically at startup for
@@ -41,7 +50,7 @@ convenience, so you only need to list it if you want to supply credentials.
:::note Note
The credential required for this type is either an [Api token](https://support.atlassian.com/bitbucket-cloud/docs/using-api-tokens/) or an [App Password](https://support.atlassian.com/bitbucket-cloud/docs/app-passwords/). An Atlassian Account API key will not work.
The credential required for this type is either an [Api token](https://support.atlassian.com/bitbucket-cloud/docs/using-api-tokens/), an [App Password](https://support.atlassian.com/bitbucket-cloud/docs/app-passwords/) or an [OAuth 2.0 client credentials](https://support.atlassian.com/bitbucket-cloud/docs/use-oauth-on-bitbucket-cloud/). An Atlassian Account API key will not work.
:::
@@ -55,3 +64,5 @@ This one entry will have the following elements:
neither a username nor token are supplied, anonymous access will be used.
- `token`: The token used to authenticate requests.
- `appPassword`: The app password for the Bitbucket Cloud user.
- `clientId`: The OAuth client ID for Bitbucket Cloud (used with `clientSecret` for OAuth 2.0 client credentials flow).
- `clientSecret`: The OAuth client secret for Bitbucket Cloud (used with `clientId` for OAuth 2.0 client credentials flow).
@@ -42,6 +42,8 @@ You need to decide how you want to receive events from external sources like
- [via HTTP endpoint](https://github.com/backstage/backstage/tree/master/plugins/events-backend/README.md)
- [via an AWS SQS queue](https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-aws-sqs/README.md)
- [via Google Pub/Sub](https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-google-pubsub/README.md)
- [via a Kafka topic](https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-kafka/README.md)
Further documentation:
+48 -2
View File
@@ -141,7 +141,7 @@ events:
region: us-east-2
```
The [AWS SQS module `README`](https://github.com/backstage/backstage/blob/master/plugins/events-backend-module-aws-sqs/README.md#configuration) has more details on the configuration options, the example above includes on the required options.
The [AWS SQS module `README`](https://github.com/backstage/backstage/blob/master/plugins/events-backend-module-aws-sqs/README.md#configuration) has more details on the configuration options, the example above includes only the required options.
### Events Setup using Google Pub/Sub module
@@ -179,7 +179,53 @@ events:
targetTopic: 'github.{{ event.attributes.x-github-event }}'
```
The [Google Pub/Sub module `README`](https://github.com/backstage/backstage/blob/master/plugins/events-backend-module-google-pubsub/README.md#configuration) has more details on the configuration options, the example above includes on the required options.
The [Google Pub/Sub module `README`](https://github.com/backstage/backstage/blob/master/plugins/events-backend-module-google-pubsub/README.md#configuration) has more details on the configuration options, the example above includes only the required options.
### Events Setup using Kafka module
Alternatively to using the HTTP endpoint you can use the Kafka module, here's how.
First we need to add the package:
```bash title="from your Backstage root directory"
yarn --cwd packages/backend add @backstage/plugin-events-backend-module-kafka
```
Then we need to add it to your backend:
```ts title="in packages/backend/src/index.ts"
backend.add(import('@backstage/plugin-events-backend'));
backend.add(import('@backstage/plugin-events-backend-module-github'));
/* highlight-add-start */
backend.add(import('@backstage/plugin-events-backend-module-kafka'));
/* highlight-add-end */
```
Finally you will want to configure it:
```yaml title="app-config.yaml
events:
modules:
kafka:
kafkaConsumingEventPublisher:
# Client ID used by Backstage to identify when connecting to the Kafka cluster.
clientId: your-client-id
# List of brokers in the Kafka cluster to connect to.
brokers:
- broker1
- broker2
topics:
# Replace with actual topic name as expected by subscribers
- topic: 'backstage.topic'
kafka:
# The Kafka topics to subscribe to.
topics:
- topic1
# The GroupId to be used by the topic consumers.
groupId: your-group-id
```
The [Kafka module `README`](https://github.com/backstage/backstage/blob/master/plugins/events-backend-module-kafka/README.md#configuration) has more details on the configuration options, the example above includes only the required options.
## Configuration
+5
View File
@@ -90,6 +90,7 @@ catalog:
initialDelay: { seconds: 30 }
frequency: { hours: 1 }
timeout: { minutes: 50 }
excludeSuspendedUsers: true
```
Directly under the `githubOrg` is a list of configurations, each entry is a structure with the following elements:
@@ -106,6 +107,8 @@ Directly under the `githubOrg` is a list of configurations, each entry is a stru
Reducing page sizes will result in more API calls and slightly longer sync times, but will prevent API resource limits for organizations with large number of teams and members.
- `excludeSuspendedUsers` (optional): Whether to exclude suspended users when querying organization users. Only for GitHub Enterprise instances. Will error if used against GitHub.com API.
### Events Support
The catalog module for GitHub Org comes with events support enabled.
@@ -129,6 +132,8 @@ 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)
- [via Google Pub/Sub](https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-google-pubsub/README.md)
- [via a Kafka topic](https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-kafka/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 `organization`,`team` and `membership` events.
+4
View File
@@ -43,6 +43,8 @@ You need to decide how you want to receive events from external sources like
- [via HTTP endpoint](https://github.com/backstage/backstage/blob/master/plugins/events-backend/README.md#configuration)
- [via an AWS SQS queue](https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-aws-sqs/README.md)
- [via Google Pub/Sub](https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-google-pubsub/README.md)
- [via a Kafka topic](https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-kafka/README.md)
Further documentation:
@@ -92,6 +94,8 @@ Additionally, you need to decide how you want to receive events from external so
- [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)
- [via Google Pub/Sub](https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-google-pubsub/README.md)
- [via a Kafka topic](https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-kafka/README.md)
Set up your provider
+4
View File
@@ -49,6 +49,8 @@ You need to decide how you want to receive events from external sources like
- [via HTTP endpoint](https://github.com/backstage/backstage/blob/master/plugins/events-backend/README.md#configuration)
- [via an AWS SQS queue](https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-aws-sqs/README.md)
- [via Google Pub/Sub](https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-google-pubsub/README.md)
- [via a Kafka topic](https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-kafka/README.md)
Further documentation:
@@ -101,6 +103,8 @@ Additionally, you need to decide how you want to receive events from external so
- [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)
- [via Google Pub/Sub](https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-google-pubsub/README.md)
- [via a Kafka topic](https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-kafka/README.md)
Set up your provider
+52
View File
@@ -149,11 +149,63 @@ notifications:
broadcastChannels: # Optional, if you wish to support broadcast notifications.
- C12345678
username: 'Backstage Bot' # Optional, defaults to the name of the Slack App.
concurrencyLimit: 20 # Optional, number of messages allowed per interval. Defaults to 10.
throttleInterval: 1m # Optional, Accepts ISO-8601 duration, ms-style ("1m", "30s"), or HumanDuration ({ minutes: 2 }). Defaults to 1 minute
```
Multiple instances can be added in the `slack` array, allowing you to have multiple configurations if you need to send
messages to more than one Slack workspace. Org-Wide App installation is not currently supported.
### Broadcast Channel Routing
For more granular control over where broadcast notifications are sent, you can use `broadcastRoutes` to route notifications to different Slack channels based on their origin and/or topic. This is useful when you want different types of notifications to go to different channels.
```yaml
notifications:
processors:
slack:
- token: xoxb-XXXXXXXXX
# Legacy option - used as fallback when no routes match
broadcastChannels:
- general-notifications
# Route broadcasts based on origin and/or topic
broadcastRoutes:
# Most specific: matches both origin AND topic
- origin: plugin:catalog
topic: alerts
channel: catalog-alerts
# Origin only: all notifications from this origin
- origin: plugin:catalog
channel: catalog-updates
# Topic only: all notifications with this topic (any origin)
- topic: security
channel: security-team
# Multiple channels: send to several channels at once
- origin: external:monitoring
channel:
- ops-team
- on-call-alerts
```
#### Route Matching Precedence
Routes are evaluated in the following order of priority:
1. **Origin + Topic match** (most specific) - A route that specifies both `origin` and `topic` will match first
2. **Origin-only match** - A route with only `origin` specified (no `topic`)
3. **Topic-only match** - A route with only `topic` specified (no `origin`)
4. **Default fallback** - If no routes match, falls back to `broadcastChannels`
The first matching route wins. If no routes match and no `broadcastChannels` are configured, the broadcast notification will not be sent to Slack.
#### Configuration Options
| Property | Type | Description |
| --------- | ---------------------- | ------------------------------------------------------------------------------------------ |
| `origin` | `string` | Optional. The notification origin to match (e.g., `plugin:catalog`, `external:my-service`) |
| `topic` | `string` | Optional. The notification topic to match (e.g., `alerts`, `updates`, `security`) |
| `channel` | `string` or `string[]` | Required. The Slack channel(s) to send to. Can be channel IDs, channel names, or user IDs |
### Entity Requirements
Entities must be annotated with the following annotation:
+1 -1
View File
@@ -177,7 +177,7 @@ When we say _Supporting_ a Node.js release, that means the following:
- New Backstage projects created with `@backstage/create-app` will have their `engines.node` version set accordingly.
- Dropping compatibility with unsupported releases is not considered a breaking change. This includes using new syntax or APIs, as well as bumping dependencies that drop support for these versions.
Based on the above Backstage supports Node.js 20 and 22 as of the `1.33.0` release.
Based on the above Backstage supports Node.js 22 and 24 as of the `1.46.0` release.
## TypeScript Releases
-2
View File
@@ -39,8 +39,6 @@ Out of the box, Backstage includes:
Backstage is a CNCF Incubation project after graduating from Sandbox. Read the announcement
[here](https://backstage.io/blog/2022/03/16/backstage-turns-two#out-of-the-sandbox-and-into-incubation).
<img src="https://backstage.io/img/cncf-white.svg" alt="CNCF logo" width="400" />
## Benefits
- For _engineering managers_, it allows you to maintain standards and best
+1 -1
View File
@@ -159,7 +159,7 @@ To install custom rules in a plugin, we need to use the [`PermissionsRegistrySer
```typescript title="packages/backend/src/modules/catalogPermissionRules.ts"
import { createBackendModule } from '@backstage/backend-plugin-api';
import { catalogPermissionExtensionPoint } from '@backstage/plugin-catalog-node/alpha';
import { isInSystemRule } from './permissionPolicyExtension';
import { isInSystemRule } from './permissionsPolicyExtension';
export default createBackendModule({
pluginId: 'catalog',
@@ -32,7 +32,7 @@ Creating the plugin...
### Reading entities from within your plugin
You can access the currently selected entity using the backstage api
[`useEntity`](../reference/plugin-catalog-react.useentity.md). For example,
[`useEntity`](https://backstage.io/api/stable/functions/_backstage_plugin-catalog-react.index.useEntity.html). For example,
```tsx
import { useEntity } from '@backstage/plugin-catalog-react';
+2 -2
View File
@@ -81,8 +81,8 @@ export const ExamplePage = examplePlugin.provide(
```
This is where the plugin is created and where it creates and exports extensions
that can be imported and used the app. See reference docs for
[`createPlugin`](../reference/core-plugin-api.createplugin.md) or introduction to
that can be imported and used in the app. See reference docs for
[`createPlugin`](https://backstage.io/api/stable/functions/_backstage_core-plugin-api.index.createPlugin.html) or introduction to
the new [Composability System](./composability.md).
## Components
+11 -5
View File
@@ -69,17 +69,23 @@ Once the release has been published edit the newly created release in the [GitHu
**This emergency release process is intended only for the Backstage
maintainers.**
Given one or more PRs towards master that we want to create a patch release for, run the following script from the repo root:
Given one or more PRs towards master that we want to create a patch release for, add them to the patch release queue by running the following command for each PR:
```bash
./scripts/patch-release-for-pr.js <pr-number> <pr-number-2> ...
yarn patch-pr <pr-number> <description>
```
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.
This creates a patch file in the `.patches/` directory (e.g., `.patches/pr-12345.txt`) containing the description of the fix. The [sync_patch-release.yml](https://github.com/backstage/backstage/blob/master/.github/workflows/sync_patch-release.yml) workflow will automatically detect these patch files and create or update a "Patch Release" 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.
The workflow will:
If the above process fails, you can fall back to the manual process documented below.
- Automatically create a patch release PR if one doesn't exist
- Update the existing PR if patch files are added, modified, or removed
- Close and delete the PR branch if all patch files are removed
Once the "Patch Release" PR has been approved and merged, the patch release will be automatically created. The patch files will be automatically removed from the master branch after the patch release is merged. From here the patch release process is the same as the usual release process, starting with the notification in the `#maintainers` channel on Discord.
If the above process fails, you can fall back to the manual process documented below, or run the `./scripts/patch-release-for-pr.js <pr-number> <pr-number-2> ...` script to manually create a patch release PR.
### Old Process
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+392
View File
@@ -0,0 +1,392 @@
# Release v1.46.0-next.1
Upgrade Helper: [https://backstage.github.io/upgrade-helper/?to=1.46.0-next.1](https://backstage.github.io/upgrade-helper/?to=1.46.0-next.1)
## @backstage/plugin-techdocs-addons-test-utils@2.0.0-next.1
### Major Changes
- 8d6709e: **BREAKING**: `TechDocsAddonTester.renderWithEffects()` no longer returns a screen; this means that you can no longer grab assertions such as `getByText` from its return value.
Newer versions of `@testing-library` recommends using the `screen` export for assertions - and removing this from the addon tester contract allows us to more freely iterate on which underlying version of the testing library is being used.
One notable effect of this, however, is that the `@testing-library` `screen` does NOT support assertions on the shadow DOM, which techdocs relies on. You will therefore want to add a dependency on [the `shadow-dom-testing-library` package](https://github.com/konnorrogers/shadow-dom-testing-library/) in your tests, and using its `screen` and its dedicated `*Shadow*` methods. As an example, if you keep doing `getByText` you will not get matches inside the shadow DOM - switch to `getByShadowText` instead.
```ts
import { screen } from 'shadow-dom-testing-library';
// ... render the addon ...
await TechDocsAddonTester.buildAddonsInTechDocs([<AnAddon />])
.withDom(<body>TEST_CONTENT</body>)
.renderWithEffects();
expect(screen.getByShadowText('TEST_CONTENT')).toBeInTheDocument();
```
### Patch Changes
- Updated dependencies
- @backstage/plugin-catalog-react@1.21.4-next.1
- @backstage/plugin-techdocs@1.16.1-next.1
## @backstage/ui@0.10.0-next.1
### Minor Changes
- 16543fa: **Breaking change** The `Cell` component has been refactored to be a generic wrapper component that accepts `children` for custom cell content. The text-specific functionality (previously part of `Cell`) has been moved to a new `CellText` component.
### Migration Guide
If you were using `Cell` with text-specific props (`title`, `description`, `leadingIcon`, `href`), you need to update your code to use `CellText` instead:
**Before:**
```tsx
<Cell
title="My Title"
description="My description"
leadingIcon={<Icon />}
href="/path"
/>
```
**After:**
```tsx
<CellText
title="My Title"
description="My description"
leadingIcon={<Icon />}
href="/path"
/>
```
For custom cell content, use the new generic `Cell` component:
```tsx
<Cell>{/* Your custom content */}</Cell>
```
### Patch Changes
- 50b7927: Fixed Checkbox indicator showing checkmark color when unchecked.
Affected components: Checkbox
- 5bacf55: Fixed `ButtonIcon` incorrectly applying `className` to inner elements instead of only the root element.
Affected components: ButtonIcon
- a20d317: Added row selection support with visual state styling for hover, selected, and pressed states. Fixed checkbox rendering to only show for multi-select toggle mode.
Affected components: Table, TableHeader, Row, Column
## @backstage/cli@0.34.6-next.1
### Patch Changes
- 7fbac5c: Updated to use new utilities from `@backstage/cli-common`.
- Updated dependencies
- @backstage/cli-node@0.2.16-next.1
- @backstage/cli-common@0.1.16-next.1
## @backstage/cli-common@0.1.16-next.1
### Patch Changes
- 5cfb2a4: Added new `run`, `runOutput`, and `runCheck` utilities to help run child processes in a safe and portable way.
## @backstage/cli-node@0.2.16-next.1
### Patch Changes
- 4e8c726: Updated to use new utilities from `@backstage/cli-common`.
- Updated dependencies
- @backstage/cli-common@0.1.16-next.1
## @backstage/codemods@0.1.53-next.1
### Patch Changes
- 688f070: Updated to use new utilities from `@backstage/cli-common`.
- Updated dependencies
- @backstage/cli-common@0.1.16-next.1
## @backstage/core-components@0.18.4-next.1
### Patch Changes
- 9a942a4: Fixed bug in the `LogViewer` component where shift + click always opened a new window instead of just changing the selection.
In addition, improved the `LogViewer` component by a few usability enhancements:
- Added support for multiple selections using cmd/ctrl + click
- Improved the generated hash that is added to the URL to also support ranges & multiple selections
- Added an hover effect & info tooltip to the "Copy to clipboard" button to indicate its functionality
- Added some color and a separator to the line numbers to improve readability
- 207c3c8: long words like urls now breaks to new line on warning panels instead of overflowing the container
- 5d52dab: Add i18n support for LogViewer search control
## @backstage/create-app@0.7.7-next.1
### Patch Changes
- Bumped create-app version.
- Updated dependencies
- @backstage/cli-common@0.1.16-next.1
## @backstage/dev-utils@1.1.18-next.1
### Patch Changes
- Updated dependencies
- @backstage/ui@0.10.0-next.1
- @backstage/core-components@0.18.4-next.1
- @backstage/plugin-catalog-react@1.21.4-next.1
## @backstage/repo-tools@0.16.1-next.1
### Patch Changes
- 688f070: Updated to use new utilities from `@backstage/cli-common`.
- d1e38a7: Properly create workspace in OS temporary directory for `generate-patch` command
- Updated dependencies
- @backstage/cli-node@0.2.16-next.1
- @backstage/cli-common@0.1.16-next.1
## @techdocs/cli@1.10.3-next.1
### Patch Changes
- 43629b1: Updated to use new utilities from `@backstage/cli-common`.
- Updated dependencies
- @backstage/cli-common@0.1.16-next.1
## @backstage/plugin-app-visualizer@0.1.26-next.1
### Patch Changes
- Updated dependencies
- @backstage/ui@0.10.0-next.1
- @backstage/core-components@0.18.4-next.1
## @backstage/plugin-catalog-backend-module-aws@0.4.18-next.1
### Patch Changes
- Updated dependencies
- @backstage/plugin-kubernetes-common@0.9.9-next.0
## @backstage/plugin-catalog-backend-module-gcp@0.3.15-next.1
### Patch Changes
- Updated dependencies
- @backstage/plugin-kubernetes-common@0.9.9-next.0
## @backstage/plugin-catalog-backend-module-github@0.11.3-next.1
### Patch Changes
- ed5a7a3: Introduce new configuration option to exclude suspended users from GitHub Enterprise instances.
When its set to true, suspended users wont be returned when querying the organization users for GitHub Enterprise instances.
Note that this option should be used only against GitHub Enterprise instances, the property does not exist in the github.com GraphQL schema, setting it will cause a schema validation error and the syncing of users will fail.
## @backstage/plugin-catalog-backend-module-github-org@0.3.17-next.1
### Patch Changes
- ed5a7a3: Introduce new configuration option to exclude suspended users from GitHub Enterprise instances.
When its set to true, suspended users wont be returned when querying the organization users for GitHub Enterprise instances.
Note that this option should be used only against GitHub Enterprise instances, the property does not exist in the github.com GraphQL schema, setting it will cause a schema validation error and the syncing of users will fail.
- Updated dependencies
- @backstage/plugin-catalog-backend-module-github@0.11.3-next.1
## @backstage/plugin-catalog-backend-module-unprocessed@0.6.7-next.1
### Patch Changes
- Updated dependencies
- @backstage/plugin-catalog-unprocessed-entities-common@0.0.12-next.0
## @backstage/plugin-catalog-react@1.21.4-next.1
### Patch Changes
- 6d39141: Fixed an issue where `EntityOwnerPicker` failed to filter options when the input text contained uppercase characters.
- Updated dependencies
- @backstage/core-components@0.18.4-next.1
## @backstage/plugin-catalog-unprocessed-entities@0.2.24-next.1
### Patch Changes
- df4d646: Moved types, API and client to the common package, allowing both frontend and
backend plugins to use the `CatalogUnprocessedEntitiesClient`.
The following types, clients and interfaces have been deprecated and should be
imported from the `@backstage/plugin-catalog-unprocessed-entities-common` instead:
`CatalogUnprocessedEntitiesApi`, `CatalogUnprocessedEntitiesApiResponse`, `UnprocessedEntity`,
`UnprocessedEntityCache`, `UnprocessedEntityError`, `CatalogUnprocessedEntitiesClient`.
All those types, clients and interfaces are re-exported temporarily in the
`@backstage/plugin-catalog-unprocessed-entities` package until cleaned up.
- Updated dependencies
- @backstage/core-components@0.18.4-next.1
- @backstage/plugin-catalog-unprocessed-entities-common@0.0.12-next.0
## @backstage/plugin-catalog-unprocessed-entities-common@0.0.12-next.0
### Patch Changes
- df4d646: Moved types, API and client to the common package, allowing both frontend and
backend plugins to use the `CatalogUnprocessedEntitiesClient`.
The following types, clients and interfaces have been deprecated and should be
imported from the `@backstage/plugin-catalog-unprocessed-entities-common` instead:
`CatalogUnprocessedEntitiesApi`, `CatalogUnprocessedEntitiesApiResponse`, `UnprocessedEntity`,
`UnprocessedEntityCache`, `UnprocessedEntityError`, `CatalogUnprocessedEntitiesClient`.
All those types, clients and interfaces are re-exported temporarily in the
`@backstage/plugin-catalog-unprocessed-entities` package until cleaned up.
## @backstage/plugin-kubernetes@0.12.14-next.1
### Patch Changes
- Updated dependencies
- @backstage/plugin-kubernetes-react@0.5.14-next.1
- @backstage/core-components@0.18.4-next.1
- @backstage/plugin-catalog-react@1.21.4-next.1
- @backstage/plugin-kubernetes-common@0.9.9-next.0
## @backstage/plugin-kubernetes-backend@0.20.5-next.1
### Patch Changes
- 8fa8d87: Add Kubernetes Plugin Secrets Accordion with masked secret datas
- Updated dependencies
- @backstage/plugin-kubernetes-common@0.9.9-next.0
- @backstage/plugin-kubernetes-node@0.3.7-next.1
## @backstage/plugin-kubernetes-cluster@0.0.32-next.1
### Patch Changes
- Updated dependencies
- @backstage/plugin-kubernetes-react@0.5.14-next.1
- @backstage/core-components@0.18.4-next.1
- @backstage/plugin-catalog-react@1.21.4-next.1
- @backstage/plugin-kubernetes-common@0.9.9-next.0
## @backstage/plugin-kubernetes-common@0.9.9-next.0
### Patch Changes
- 8fa8d87: Add Kubernetes Plugin Secrets Accordion with masked secret datas
## @backstage/plugin-kubernetes-node@0.3.7-next.1
### Patch Changes
- Updated dependencies
- @backstage/plugin-kubernetes-common@0.9.9-next.0
## @backstage/plugin-kubernetes-react@0.5.14-next.1
### Patch Changes
- f966a85: Enabled a pod terminal at GKE
- 8fa8d87: Add Kubernetes Plugin Secrets Accordion with masked secret datas
- Updated dependencies
- @backstage/core-components@0.18.4-next.1
- @backstage/plugin-kubernetes-common@0.9.9-next.0
## @backstage/plugin-mui-to-bui@0.2.2-next.1
### Patch Changes
- Updated dependencies
- @backstage/ui@0.10.0-next.1
## @backstage/plugin-scaffolder-react@1.19.4-next.1
### Patch Changes
- 5ca461e: Fixed bug where custom `review.name` values were incorrectly formatted by `startCase`, preserving them exactly as written.
- Updated dependencies
- @backstage/core-components@0.18.4-next.1
- @backstage/plugin-catalog-react@1.21.4-next.1
## @backstage/plugin-techdocs@1.16.1-next.1
### Patch Changes
- 592361e: The `techdocs` config is now marked as optional.
- Updated dependencies
- @backstage/core-components@0.18.4-next.1
- @backstage/plugin-catalog-react@1.21.4-next.1
## @backstage/plugin-techdocs-backend@2.1.3-next.1
### Patch Changes
- 592361e: The `techdocs` config is now marked as optional.
## @backstage/plugin-techdocs-module-addons-contrib@1.1.31-next.1
### Patch Changes
- 8d6709e: Updated tests to match test-utils change
- Updated dependencies
- @backstage/core-components@0.18.4-next.1
## example-app@0.2.116-next.1
### Patch Changes
- Updated dependencies
- @backstage/ui@0.10.0-next.1
- @backstage/core-components@0.18.4-next.1
- @backstage/plugin-techdocs-module-addons-contrib@1.1.31-next.1
- @backstage/plugin-catalog-react@1.21.4-next.1
- @backstage/plugin-scaffolder-react@1.19.4-next.1
- @backstage/plugin-catalog-unprocessed-entities@0.2.24-next.1
- @backstage/cli@0.34.6-next.1
- @backstage/plugin-techdocs@1.16.1-next.1
- @backstage/plugin-mui-to-bui@0.2.2-next.1
- @backstage/plugin-kubernetes@0.12.14-next.1
- @backstage/plugin-kubernetes-cluster@0.0.32-next.1
## example-app-next@0.0.30-next.1
### Patch Changes
- Updated dependencies
- @backstage/ui@0.10.0-next.1
- @backstage/core-components@0.18.4-next.1
- @backstage/plugin-techdocs-module-addons-contrib@1.1.31-next.1
- @backstage/plugin-catalog-react@1.21.4-next.1
- @backstage/plugin-scaffolder-react@1.19.4-next.1
- @backstage/plugin-catalog-unprocessed-entities@0.2.24-next.1
- @backstage/cli@0.34.6-next.1
- @backstage/plugin-techdocs@1.16.1-next.1
- @backstage/plugin-app-visualizer@0.1.26-next.1
- @backstage/plugin-kubernetes@0.12.14-next.1
- @backstage/plugin-kubernetes-cluster@0.0.32-next.1
## techdocs-cli-embedded-app@0.2.115-next.1
### Patch Changes
- Updated dependencies
- @backstage/ui@0.10.0-next.1
- @backstage/core-components@0.18.4-next.1
- @backstage/cli@0.34.6-next.1
- @backstage/plugin-techdocs@1.16.1-next.1
File diff suppressed because it is too large Load Diff
+129
View File
@@ -0,0 +1,129 @@
---
id: v1.46.0
title: v1.46.0
description: Backstage Release v1.46.0
---
These are the release notes for the v1.46.0 release of [Backstage](https://backstage.io/).
A huge thanks to the whole team of maintainers and contributors as well as the amazing Backstage Community for the hard work in getting this release developed and done.
## Highlights
To begin with, this release has a few important framework level updates.
### **BREAKING:** Updated supported Node.js versions to 22 and 24
This release moves up the supported Node.js versions to 22 and 24, according to our [versioning policy](https://backstage.io/docs/overview/versioning-policy#nodejs-releases). As part of this change, we are also setting the compilation targets to ES2023, which lines up with the supported Node.js versions.
The default TypeScript `target` compiler option is however left at ES2022. This is because older versions of TypeScript will error if they see an unsupported value, even if an override is set in your local `tsconfig.json`. You can still choose to set the TypeScript `target` to either `ES2023` or even `ES2024` in your own `tsconfig.json` if you prefer.
### **BREAKING:** Switched modules to `ES2020` and resolution mode to `bundler`
Now that the ecosystem has had some time to mature and adapt, we have finally switched over the default module resolution mode to `bundler` instead of `node`. The `module` setting was also changed to `ES2022`.
You _may_ need to bump some dependencies as part of this change, or fix imports in code. The most common source of this is that type checking will now consider the `exports` field in `package.json` when resolving imports. This in turn can break older versions of packages that had incompatible `exports` fields. Generally these issues will have already been fixed in the upstream packages, but if you depend on old versions or unmaintained packages, you may still notice some effects of this.
You might be tempted to use `--skipLibCheck` to hide issues due to this change, but it will weaken the type safety of your project. If you run into a large number of issues and want to keep the old behavior, you can reset the `moduleResolution` and `module` settings of your own `tsconfig.json` file to `node` and `ESNext` respectively. But keep in mind that the `node` option will be removed in future versions of TypeScript.
A future version of Backstage will make these new settings mandatory, as we move to rely on the `exports` field for type resolution in packages, rather than the `typesVersions` field.
### **BREAKING:** Moving toward updating `jest` and its DOM
The `jest` test framework used to be a builtin dependency of the Backstage CLI. In this release, it has been made into a peer dependency to allow for easy upgrades to newer versions as you see fit.
If you run tests using the Backstage CLI, you must therefore add Jest and its environment dependencies as `devDependencies` in your project root `package.json` when you upgrade.
You can choose to install either Jest 29 or Jest 30. The built-in Jest version before this change was Jest 29, however, we recommend that you switch to Jest 30. Upgrading will solve the `Could not parse CSS stylesheet` errors, allow you to use MSW v2 in web packages, and ensure that you remain compatible with future versions of the Backstage CLI. Support for Jest 29 is temporary, with the purpose of allowing you to upgrade at your own pace, but it will eventually be removed.
- **Jest 29**: Install `jest@^29` and `jest-environment-jsdom@^29` in your root `package.json`. No migration needed, but you may see `Could not parse CSS stylesheet` warnings/errors when testing components from `@backstage/ui` or other packages using CSS `@layer` declarations.
- **Jest 30**: Install `jest@^30`, `@types/jest@^30`, `@jest/environment-jsdom-abstract@^30`, and `jsdom@^27` in your root `package.json`. Fixes the stylesheet parsing warnings/errors, but requires migration steps.
See the [Jest 30 migration guide](https://backstage.io/docs/tutorials/jest30-migration) for detailed migration instructions.
### **BREAKING:** Now using correct configuration options for Valkey
If you are using Valkey as your backend cache provider, take note. It used to piggyback on the Redis configuration format, but that was not quite correct. So its config options have been updated to better match its capabilities.
So if you use Valkey, you need to upgrade your `app-config.yaml`:
```diff
backend:
cache:
store: valkey
connection: ...
client:
- namespace: 'my-app'
- keyPrefixSeparator: ':'
+ keyPrefix: 'my-app:'
- clearBatchSize: 1000
- useUnlink: false
```
Contributed by [@benjidotsh](https://github.com/benjidotsh) in [#31497](https://github.com/backstage/backstage/pull/31497)
### **BREAKING:** Techdocs addon test utils removed explicit `screen`
`TechdocsAddonTester.renderWithEffects()` used to return a `screen` that you could use for things like `getByText`. In order to support moving to newer versions of `@testing-library`, we have removed this, and you should import and use the normal `screen` from `@testing-library/react` instead.
However: that `screen` cant see inside the shadow DOM, which TechDocs uses. So if your tests need to look inside shadow DOM, you must install `shadow-dom-testing-library` and use its `screen` which provides special shadow-DOM queries, such as `getByShadowText` instead of `getByText.
Example:
```tsx
import { screen } from 'shadow-dom-testing-library';
// ... render the addon ...
await TechDocsAddonTester.buildAddonsInTechDocs([<AnAddon />])
.withDom(<body>TEST_CONTENT</body>)
.renderWithEffects();
expect(screen.getByShadowText('TEST_CONTENT')).toBeInTheDocument();
```
### **BREAKING:** Backstage-UI advances!
Again, Backstage-UI has a bunch of updates! One of them is breaking: If you were using the `Cell` component with text-specific props (`title` etc), you should now instead use the `CellText` component for that. Plain `Cell` is now meant to be used with generic child elements instead.
### Simplified route compatibility
If you are partway through a migration to the New Frontend System, you may enjoy the fact that the `useApp` and `useRouteRef` hooks now are forwards compatible with NFS. Along with the previous route reference changes this means that there is no longer a need to use `compatWrapper` from `@backstage/core-compat-api` to make code based on `@backstage/core-plugin-api` compatible with `@backstage/frontend-plugin-api` APIs.
### Support for Bitbucket Cloud OAuth
Support for Bitbucket Cloud OAuth has been added - which was much welcome. This introduces an alternative authentication method using a workspace OAuth consumer, alongside App Passwords (deprecated) and API tokens. OAuth does not require a bot or service account and avoids token expiry issues.
As part of this change, some breaking changes were made to low level auth getter functions, such that they now return a promise instead of a plain value.
Contributed by [@jksmth](https://github.com/jksmth) in [#31848](https://github.com/backstage/backstage/pull/31848)
### New Catalog actions
There are two new MCP-usable actions on the block for registering and unregistering entities: `catalog:register-entity` and `catalog:unregister-entity`.
Contributed by [@gabemontero](https://github.com/gabemontero) in [#32042](https://github.com/backstage/backstage/pull/32042)
### New `RepoOwnerPicker` for Scaffolder
A new field extension for selecting an organization or owner for a particular repository has been shipped! Currently, this only supports GitHub autocomplete, but contributions welcome in making this available for other providers!
Contributed by [@benjidotsh](https://github.com/benjidotsh) in [#32105](https://github.com/backstage/backstage/pull/32105)
## Security Fixes
This release does not contain any security fixes.
## Upgrade path
We recommend that you keep your Backstage project up to date with this latest release. For more guidance on how to upgrade, check out the documentation for [keeping Backstage updated](https://backstage.io/docs/getting-started/keeping-backstage-updated).
## Links and References
Below you can find a list of links and references to help you learn about and start using this new release.
- [Backstage official website](https://backstage.io/), [documentation](https://backstage.io/docs/), and [getting started guide](https://backstage.io/docs/getting-started/)
- [GitHub repository](https://github.com/backstage/backstage)
- Backstage's [versioning and support policy](https://backstage.io/docs/overview/versioning-policy)
- [Community Discord](https://discord.gg/backstage-687207715902193673) for discussions and support
- [Changelog](https://github.com/backstage/backstage/tree/master/docs/releases/v1.46.0-changelog.md)
- Backstage [Demos](https://backstage.io/demos), [Blog](https://backstage.io/blog), [Roadmap](https://backstage.io/docs/overview/roadmap) and [Plugins](https://backstage.io/plugins)
Sign up for our [newsletter](https://info.backstage.spotify.com/newsletter_subscribe) if you want to be informed about what is happening in the world of Backstage.
+11 -8
View File
@@ -610,7 +610,7 @@ With that in mind, here are some IDEs configurations to run backstage components
1. Click on "Edit Configurations" on top panel
2. In the modal dialog click on link "Edit configuration templates..." located in the bottom left corner.
3. "Configuration file": leave empty (`backstage-cli` adds the config)
4. "Node options": `--no-node-snapshot --experimental-vm-modules`
4. "Node options": ` --experimental-vm-modules`
5. "Jest package": `~/workspace/backstage/node_modules/@backstage/cli` - the location of the backstage cli package.
6. "Working directory": `~/workspace/backstage`
7. "Jest Options": `repo test --runInBand --watch=false`
@@ -621,20 +621,21 @@ With that in mind, here are some IDEs configurations to run backstage components
#### VS Code
1. Install the [Jest extension](https://marketplace.visualstudio.com/items?itemName=Orta.vscode-jest) for VS Code.
2. Update `settings.json` in the `.vscode` folder with:
```jsonc
{
"jest.jestCommandLine": "yarn test",
// In a large repo like the Backstage main repo you likely want to disable
// watch mode and the initial test run too, leaving just manual and perhaps
// on-save test runs in place.
"jest.autoRun": {
"watch": false,
"onSave": "test-src-file"
}
"jest.runMode": "on-save"
}
```
A complete launch configuration for VS Code debugging may look like this:
3. Add a launch configuration for VS Code in `launch.json` in the `.vscode` folder.
A complete configuration for debugging may look like this:
```jsonc
{
@@ -653,11 +654,13 @@ A complete launch configuration for VS Code debugging may look like this:
],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"disableOptimisticBPs": true,
"program": "${workspaceFolder}/node_modules/.bin/backstage-cli"
"program": "${workspaceFolder}/node_modules/@backstage/cli/bin/backstage-cli"
}
```
4. The configuration is not for manual runs from the "Run and Debug" view.
Instead use the Jest test explorer or the [test's gutter menu](https://github.com/jest-community/vscode-jest#how-to-trigger-a-test-run).
## Publishing
Package publishing is an optional part of the Backstage build system and not
+95
View File
@@ -0,0 +1,95 @@
---
id: jest30-migration
title: Migrating to Jest 30
description: A guide to migrating your project to Jest 30 and JSDOM 27
---
Starting with a recent version of `@backstage/cli`, `jest` is a peer dependency. If you run tests using Backstage CLI, you must add Jest and its environment dependencies as `devDependencies` in your project.
You can choose to install either Jest 29 or Jest 30. The built-in Jest version before this change was Jest 29, however, we recommend that you switch to Jest 30. Upgrading will solve the `Could not parse CSS stylesheet` errors, allow you to use MSW v2 in web packages, and ensure that you remain compatible with future versions of the Backstage CLI. Support for Jest 29 is temporary, with the purpose of allowing you to upgrade at your own pace, but it will eventually be removed.
- **Jest 29**:
```bash
# in your repository root, run:
yarn add --dev jest@^29 @types/jest@^29 jest-environment-jsdom@^29
```
Pros: No migration needed
Cons: You may see `Could not parse CSS stylesheet` warnings/errors when testing components from `@backstage/ui` or other packages using CSS `@layer` declarations
- **Jest 30**:
```bash
# in your repository root, run:
yarn add --dev jest@^30 @types/jest@^30 @jest/environment-jsdom-abstract@^30 jsdom@^27
```
Pros: Fixes the stylesheet parsing warnings/errors
Cons: Requires migration steps (see below) in your tests
## Migration Guide
The examples below are issues we encountered while migrating the Backstage repository. For a complete list of breaking changes, see the official documentation:
- [Jest 30 upgrade guide](https://jestjs.io/docs/upgrading-to-jest30)
- [JSDOM changelog](https://github.com/jsdom/jsdom/releases)
### Jest 30
**Asymmetric matchers with arrays**: `expect.objectContaining()` no longer works with arrays.
```diff
- expect(result).toEqual(expect.objectContaining([{ id: '123' }]));
+ expect(result).toEqual([{ id: '123' }]);
// or
+ expect(result).toEqual(expect.arrayContaining([{ id: '123' }]));
```
**Array length assertions**: `expect.objectContaining({ length: N })` no longer works.
```diff
- expect(fn).toHaveBeenCalledWith(expect.objectContaining({ length: 2 }));
+ expect(fn).toHaveBeenCalledWith(expect.any(Array));
+ expect(fn.mock.calls[0][0]).toHaveLength(2);
```
**Deprecated matcher aliases removed**: Replace with canonical names.
```diff
- expect(fn).toBeCalled();
+ expect(fn).toHaveBeenCalled();
```
**Snapshots**: Regenerate snapshots as the header format has changed.
```bash
yarn test --no-watch -u
```
### JSDOM 27
**window.location is non-configurable**: You can no longer mock location via `Object.defineProperty`.
```diff
- Object.defineProperty(window, 'location', { value: { href: '' } });
+ // Option 1: Use history API
+ history.replaceState({}, '', '/new-path');
+ // Option 2: Spy on navigation methods
+ const spy = jest.spyOn(component, 'navigate');
```
**CSS color values**: Colors may be returned as RGB instead of named colors.
```diff
- expect(element.style.color).toBe('red');
+ expect(element.style.color).toBe('rgb(255, 0, 0)');
```
**Error format changes**: Error messages and stack traces may have different formatting.
#### If you run into `Cannot read properties of null (reading 'constructor')`
Certain Backstage UI-components (e.g. Button) have a combination of CSS that triggers this error in tests. The solution is to make sure you have at least v0.9.25 of `@acemir/cssom`.
@@ -94,15 +94,15 @@ export const AwesomeUsersTable = () => {
This section describes the steps to wrap your API client in a [Utility API](../api/utility-apis.md), which are:
- use [`createApiRef`](../reference/core-plugin-api.createapiref.md) to create a
new [`ApiRef`](../reference/core-plugin-api.apiref.md)
- register an [`ApiFactory`](../reference/core-plugin-api.apifactory.md) with
- use [`createApiRef`](https://backstage.io/api/stable/functions/_backstage_frontend-plugin-api.createApiRef.html) to create a
new [`ApiRef`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ApiRef.html)
- register an [`ApiFactory`](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.ApiFactory.html) with
your plugin using
[`createApiFactory`](../reference/core-plugin-api.createapifactory.md). This
[`createApiFactory`](https://backstage.io/api/stable/functions/_backstage_frontend-plugin-api.createApiFactory.html). This
will wrap your API implementation, associate your `ApiRef` with your
implementation and tell backstage how to instantiate it
- finally, you can use your API in your components by calling
[`useApi`](../reference/core-plugin-api.useapi.md)
[`useApi`](https://backstage.io/api/stable/functions/_backstage_frontend-plugin-api.useApi.html)
### Defining the API client interface
@@ -187,8 +187,8 @@ export class MyAwesomeApiClient implements MyAwesomeApi {
```
> Check out the docs for more information on the
> [DiscoveryApi](../reference/core-plugin-api.discoveryapi.md) or the
> [FetchApi](../reference/core-plugin-api.fetchapi.md)
> [DiscoveryApi](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.DiscoveryApi.html) or the
> [FetchApi](https://backstage.io/api/stable/types/_backstage_frontend-plugin-api.FetchApi.html)
### Bundling your ApiRef with your plugin
@@ -233,7 +233,7 @@ export const myCustomPlugin = createPlugin({
### Using the API in your components
Now you should be able to access your API using the backstage hook
[`useApi`](../reference/core-plugin-api.useapi.md) from within your plugin code.
[`useApi`](https://backstage.io/api/stable/functions/_backstage_frontend-plugin-api.useApi.html) from within your plugin code.
```ts title="plugins/my-awesome-plugin/src/components/AwesomeUsersTable.tsx"
import { useApi } from '@backstage/core-plugin-api';