Merge branch 'backstage:master' into patch-2

This commit is contained in:
Valentin Grégoire
2025-06-06 09:06:54 +02:00
committed by GitHub
765 changed files with 19614 additions and 7881 deletions
+22
View File
@@ -203,6 +203,28 @@ or the
[`AwsEKSClusterProcessor`](https://backstage.io/docs/reference/plugin-catalog-backend-module-aws.awseksclusterprocessor/)
to automatically update the set of clusters tracked by Backstage.
For this method to work any entity that would be using this `Resource` to help drive the Kubernetes details in the Catalog's Entity pages needs to have a `dependsOn` relationship setup. Here's a quick example:
```yaml
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
annotations:
backstage.io/kubernetes-id: dice-roller
backstage.io/kubernetes-namespace: default
name: dice-roller
description: It rolls dice
tags:
- go
spec:
type: service
lifecycle: production
owner: guest
dependsOn: ['resource:my-cluster']
```
This example assumes it's using the default namespace, if that's not the case for you then make sure to include it like this: `resource:my-namespace/my-cluster`.
#### `config`
This cluster locator method will read cluster information from your app-config
@@ -182,7 +182,7 @@ export default createPlugin({
})
```
Here is the `plugins/techdocs/alpha.tsx` final version, and you can also take a look at the [actual implementation](https://github.com/backstage/backstage/blob/master/plugins/techdocs/src/alpha.tsx) of a custom `TechDocs` search result item:
Here is the `plugins/techdocs/alpha/index.tsx` final version, and you can also take a look at the [actual implementation](https://github.com/backstage/backstage/blob/master/plugins/techdocs/src/alpha/index.tsx) of a custom `TechDocs` search result item:
```tsx
// plugins/techdocs/alpha.tsx
@@ -115,6 +115,20 @@ the TechDocs in the TechDocs page or needing multiple builds of the same docs.
This is for situations where you have complex systems where they share a single repo, and likely a single TechDoc location.
### backstage.io/techdocs-entity-path
```yaml
# Example:
metadata:
annotations:
backstage.io/techdocs-entity: component:default/example
backstage.io/techdocs-entity-path: /path/to/this/component
```
The value of this annotation informs of the path to this component's TechDocs within an external entity that owns the TechDocs.
In conjunction with [backstage.io/techdocs-entity](#backstageiotechdocs-entity) this allows for deep linking into the TechDocs of
another entity, not just linking to the root of another entities TechDocs.
### backstage.io/view-url, backstage.io/edit-url
```yaml
+29
View File
@@ -942,6 +942,35 @@ metadata:
backstage.io/techdocs-entity: system:default/example
```
### Deep linking into TechDocs
The `backstage.io/techdocs-entity-path` annotation can be use to deep link into a specific page within the components TechDocs.
This can be used in conjunction with `backstage.io/techdocs-entity` or standalone.
```yaml
apiVersion: backstage.io/v1alpha1
kind: System
metadata:
name: example
namespace: default
title: Example
description: This is the parent entity
annotations:
backstage.io/techdocs-ref: dir:.
---
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: example-platfrom
title: Example Application Platform
namespace: default
description: This is the child entity
annotations:
backstage.io/techdocs-entity: system:default/example
backstage.io/techdocs-entity-path: /path/to/component/docs
```
## How to resolve broken links from moved or renamed pages in your documentation site
TechDocs supports using the [mkdocs-redirects](https://github.com/mkdocs/mkdocs-redirects/tree/master) plugin to create a redirect map for any TechDocs site. This allows broken links from renamed or moved pages in your site to be redirected to their specified replacement.
@@ -77,3 +77,98 @@ app:
```
Note that you do not need to manually exclude packages that you also import explicitly in code, since plugin instances are deduplicated by the app. You will never end up with duplicate plugin installations except if they are in fact two different plugin instances with different IDs.
## Plugin Info Resolution
When a plugin is installed in an app it may provide sources of information about the plugin that can be useful to end users and admins. This includes things like what version of a plugin is running, what team owns the plugin, and who to contact for support. You can read more about how the plugins provide this information in the [plugins `info` option section](./15-plugins.md#info).
By default the app will pick a few common fields from `package.json` files, and assume that the opaque manifests are `catalog-info.yaml` files that some information can be gathered from too. This information will then be available via the `info()` method on plugin instances, returning a structure of the `FrontendPluginInfo` type.
### Extending Plugin Info
The default plugin info is intended as a base to build upon. As part of setting up an app you can both customize the way that the plugin info is resolved, as well as extend the `FrontendPluginInfo` type to include more information.
In order to extend the `FrontendPluginInfo` type you use [TypeScript module augmentation](https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation). This makes it possible to extend the `FrontendPluginInfo` interface with additional fields, which you can then add custom resolution logic for as well as access within the app. For example, you might add a `slackChannel` field as follows:
```ts
declare module '@backstage/frontend-plugin-api' {
interface FrontendPluginInfo {
/**
* The slack channel to use for support requests for this plugin.
*/
slackChannel?: string;
}
}
```
### Customizing Plugin Info Resolution
With the new `slackChannel` field in place, we now need to provide a custom resolver that knows how to extract this information from the plugin information sources. This is done by passing a custom `pluginInfoResolver` to `createApp`, which in our example is declared like this:
```ts title="pluginInfoResolver.ts"
import { createPluginInfoResolver } from '@backstage/frontend-plugin-api';
// It is recommended to keep the above module augmentation in this file too
export const pluginInfoResolver: FrontendPluginInfoResolver = async ctx => {
// In our particular example app we assume that all plugin manifests are catalog-info.yaml files
const manifest = (await ctx.manifest?.()) as Entity | undefined;
// Call the default resolver to populate common fields
const { info } = await ctx.defaultResolver({
packageJson: await ctx.packageJson(),
manifest: manifest,
});
// In this example the catalog model has been extended with a metadata.slackChannel field
const slackChannel = manifest?.metadata?.slackChannel?.toString();
if (slackChannel) {
info.slackChannel = slackChannel;
info.links = [
...(info.links ?? []),
{
title: 'Slack Channel',
url: `https://our-workspace.enterprise.slack.com/archives/${slackChannel}`,
},
];
}
return { info };
};
```
And included in the app as follows:
```ts title="App.tsx"
import { pluginInfoResolver } from './pluginInfoResolver';
const app = createApp({
pluginInfoResolver,
// ... other options
});
```
### Overriding Plugin Info
Another way to customize the plugin info is to use the `app.pluginOverrides` static configuration key. These overrides are applied after the plugin info has been resolved as a final step before making it available to users. These overrides are particularly useful to override information in third-party plugins. For example, if your organization has an individual team that is responsible for the maintenance of the Software Catalog, you might configure the following override:
```yaml
app:
pluginOverrides:
- match:
pluginId: catalog
info:
ownerEntityRefs: [catalog-owners]
```
You can match on both the `pluginId` and/or `packageName` of the plugin, although the `packageName` will only be supported if the plugin provides an loader for the `package.json` file. Using `/<pattern>/` you are also able to use a regex pattern for this matching. For example, if you wanted to override the owner for all plugins from the `@acme` namespace, you could do the following:
```yaml
app:
pluginOverrides:
- match:
packageName: /@acme/.*/
info:
ownerEntityRefs: [acme-owners]
```
@@ -53,6 +53,35 @@ These are the routes that the plugin exposes to the app. The `routes` option dec
This is a list of feature flag declarations that your plugin provides to the app. This makes sure that the feature flags are correctly registered and can be toggled in the app. To read a feature flag you can use the feature flags [Utility API](../architecture/33-utility-apis.md), accessible via `featureFlagsApiRef`.
### `info` option
This options is used to provide loaders for different sources of information about the plugin that may be useful to users and admins. The two available loaders are `packageJson` and `manifest`, and a plugin can use either or both as needed. The resulting information is available via the `info()` method on the plugin instance once it is installed in an app, but it is up to each app to decide how to derive the information from the provided sources.
The `info.packageJson` loader **MUST** be used by all plugins that are implemented within their own package, and it should load the `package.json` file for the plugin package. Typical usage looks like this:
```ts
export default createFrontendPlugin({
pluginId: 'my-plugin',
info: {
packageJson: () => import('../package.json'),
},
extensions: [...],
});
```
The `info.manifest` loader is used to point to an opaque plugin manifest. This **MUST ONLY** be used by plugins that are intended for use within a single organization. Plugins that are published to an open package registry should **NOT** use this loader. The loader is useful for adding additional internal metadata associated with the plugin, and it is up to the Backstage app to decide how these manifests are parsed and used. The default manifest parser in an app created with `createApp` from `@backstage/frontend-defaults` is able to parse the default `catalog-info.yaml` format and built-in fields such as `metadata.links` and `spec.owner`.
Typical usage looks like this:
```ts
export default createFrontendPlugin({
pluginId: '...',
info: {
manifest: () => import('../catalog-info.yaml'),
},
});
```
## Installing a Plugin in an App
A plugin instance is considered a frontend feature and can be installed directly in any Backstage frontend app. See the [app documentation](./10-app.md) for more information about the different ways in which you can install new features in an app.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 263 KiB

File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -65,7 +65,8 @@ In your `.vscode/launch.json`, add a new entry with the following,
"runtimeExecutable": "yarn", // Specifies the runtime to execute the application. In this case, it uses `yarn` to run the script.
"args": ["start", "--inspect"], // Arguments passed to the `yarn` command. Here, it runs `yarn start` with the `--inspect` flag to enable debugging.
"skipFiles": ["<node_internals>/**"], // Tells the debugger to skip stepping into Node.js internal files during debugging.
"console": "integratedTerminal" // Specifies that the debugger should use the integrated terminal for input/output.
"console": "integratedTerminal", // Specifies that the debugger should use the integrated terminal for input/output.
"experimentalNetworking": "off" // Since Node.js 22.15.0 an additional parameter --experimental-network-inspection is added but currently not supported by Yarn
}
]
}
+40 -4
View File
@@ -4,7 +4,7 @@ title: Setup OpenTelemetry
description: Tutorial to setup OpenTelemetry metrics and traces exporters in Backstage
---
Backstage uses [OpenTelemetery](https://opentelemetry.io/) to instrument its components by reporting traces and metrics.
Backstage uses [OpenTelemetry](https://opentelemetry.io/) to instrument its components by reporting traces and metrics.
This tutorial shows how to setup exporters in your Backstage backend package. For demonstration purposes we will use a Prometheus exporter, but you can adjust your solution to use another one that suits your needs; see for example the article on [OTLP exporters](https://opentelemetry.io/docs/instrumentation/js/exporters/).
@@ -26,7 +26,7 @@ yarn --cwd packages/backend add \
In your `packages/backend/src` folder, create an `instrumentation.js` file.
```typescript title="in packages/backend/src/instrumentation.js"
```js title="in packages/backend/src/instrumentation.js"
// Prevent from running more than once (due to worker threads)
const { isMainThread } = require('node:worker_threads');
@@ -52,6 +52,42 @@ if (isMainThread) {
You probably won't need all of the instrumentation inside `getNodeAutoInstrumentations()` so make sure to
check the [documentation](https://www.npmjs.com/package/@opentelemetry/auto-instrumentations-node) and tweak it properly.
### Views
The default histogram buckets for OpenTelemetry are in milliseconds, but the histograms that are created for Catalog processing emit metrics in second. You might want to adjust this to what fits your need. To do this you can use the [Views feature](https://opentelemetry.io/docs/concepts/signals/metrics/#views) like this:
```js
const prometheus = new PrometheusExporter();
const sdk = new NodeSDK({
metricReader: prometheus,
views: [
new View({
instrumentName: 'catalog.test',
aggregation: new ExplicitBucketHistogramAggregation([
0.01, 0.1, 0.5, 1, 5, 10, 25, 50, 100, 500, 1000,
]),
}),
],
});
```
The above will make all the histogram buckets use the same config. If you would like to take a more targeted approach you can do this:
```js
const prometheus = new PrometheusExporter();
const sdk = new NodeSDK({
metricReader: prometheus,
views: [
new View({
instrumentName: 'catalog.test',
aggregation: new ExplicitBucketHistogramAggregation([
0, 0.01, 0.05, 0.1, 0.25, 0.5, 1, 2, 5, 10, 30, 60, 120, 300, 1000,
]),
}),
],
});
```
## Local Development Setup
It's important to setup the NodeSDK and the automatic instrumentation **before**
@@ -67,13 +103,13 @@ For local development, you can add the required flag in your `packages/backend/p
...
```
You can now start your Backstage instance as usual, using `yarn start`.
You can now start your Backstage instance as usual, using `yarn start` and you'll be able to see your metrics at: <http://localhost:9464/metrics>
## Production Setup
In your `.dockerignore`, add this line:
```
```text
!packages/backend/src/instrumentation.js
```