Merge branch 'master' into aadadminconsent

Signed-off-by: Alex Crome <afscrome@users.noreply.github.com>
This commit is contained in:
Alex Crome
2023-10-26 21:53:25 +01:00
committed by GitHub
1797 changed files with 72821 additions and 16668 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

Before

Width:  |  Height:  |  Size: 293 KiB

After

Width:  |  Height:  |  Size: 293 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 67 KiB

+47
View File
@@ -406,3 +406,50 @@ providerFactories: {
ghe: providers.github.create(),
},
```
## Configuring token issuers
By default, the Backstage authentication backend generates and manages its own signing keys automatically for any issued
Backstage tokens. However, these keys have a short lifetime and do not persist after instance restarts.
Alternatively, users can provide their own public and private key files to sign issued tokens. This is beneficial in
scenarios where the token verification implementation aggressively caches the list of keys, and doesn't attempt to fetch
new ones even if they encounter an unknown key id. To enable this feature add the following configuration to your config
file:
```yaml
auth:
keyStore:
provider: 'static'
static:
keys:
# Must be declared at least once and the first one will be used for signing
- keyId: 'primary'
publicKeyFile: /path/to/public.key
privateKeyFile: /path/to/private.key
algorithm: # Optional, algorithm used to generate the keys, defaults to ES256
# More keys can be added so with future key rotations caches already know about it
- keyId: ...
```
The private key should be stored in the PKCS#8 format. The public key should be stored in the SPKI format.
You can generate the public/private key pair, using openssl and the ES256 algorithm by performing the following
steps:
Generate a private key using the ES256 algorithm
```sh
openssl ecparam -name prime256v1 -genkey -out private.ec.key
```
Convert it to PKCS#8 format
```sh
openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in private.ec.key -out private.key
```
Extract the public key
```sh
openssl ec -inform PEM -outform PEM -pubout -in private.key -out public.key
```
+7 -2
View File
@@ -51,15 +51,20 @@ auth:
microsoft:
development:
clientId: ${AZURE_CLIENT_ID}
clientSecret: ${AZURE_CLIENT_ID}
clientSecret: ${AZURE_CLIENT_SECRET}
tenantId: ${AZURE_TENANT_ID}
domainHint: ${AZURE_TENANT_ID}
```
The Microsoft provider is a structure with three configuration keys:
The Microsoft provider is a structure with three mandatory configuration keys:
- `clientId`: Application (client) ID, found on App Registration > Overview
- `clientSecret`: Secret, found on App Registration > Certificates & secrets
- `tenantId`: Directory (tenant) ID, found on App Registration > Overview
- `domainHint` (optional): Typically the same as `tenantId`.
Leave blank if your app registration is multi tenant.
When specified, this reduces login friction for users with accounts in multiple tenants by automatically filtering away accounts from other tenants.
For more details, see [Home Realm Discovery](https://learn.microsoft.com/en-us/azure/active-directory/manage-apps/home-realm-discovery-policy)
## Adding the provider to the Backstage frontend
@@ -23,7 +23,7 @@ import scaffolderPlugin from '@backstage/plugin-scaffolder-backend';
const backend = createBackend();
// Install desired features
backend.add(import('@backstage/plugin-catalog-backend'));
backend.add(import('@backstage/plugin-catalog-backend/alpha'));
// Features can also be installed using an explicit reference
backend.add(scaffolderPlugin());
@@ -24,9 +24,9 @@ import { createBackend } from '@backstage/backend-defaults'; // Omitted in the e
const backend = createBackend();
backend.add(import('@backstage/plugin-app-backend'));
backend.add(import('@backstage/plugin-catalog-backend'));
backend.add(import('@backstage/plugin-scaffolder-backend'));
backend.add(import('@backstage/plugin-app-backend/alpha'));
backend.add(import('@backstage/plugin-catalog-backend/alpha'));
backend.add(import('@backstage/plugin-scaffolder-backend/alpha'));
backend.add(
import('@backstage/plugin-catalog-backend-module-scaffolder-entity-model'),
);
@@ -126,8 +126,8 @@ You can now trim down the `src/index.ts` files to only include the plugins and m
```ts
const backend = createBackend();
backend.add(import('@backstage/plugin-app-backend'));
backend.add(import('@backstage/plugin-catalog-backend'));
backend.add(import('@backstage/plugin-app-backend/alpha'));
backend.add(import('@backstage/plugin-catalog-backend/alpha'));
backend.add(
import('@backstage/plugin-catalog-backend-module-scaffolder-entity-model'),
);
@@ -139,7 +139,7 @@ And `backend-b`, don't forget to clean up dependencies in `package.json` as well
```ts
const backend = createBackend();
backend.add(import('@backstage/plugin-scaffolder-backend'));
backend.add(import('@backstage/plugin-scaffolder-backend/alpha'));
backend.start();
```
@@ -177,11 +177,10 @@ custom API, so we use a helper function to transform that particular one.
To make additions as mentioned above to the environment, you will start to get
into the weeds of how the backend system wiring works. You'll need to have a
service reference and a service factory that performs the actual creation of
your service. Please see [the services
article](../architecture/03-services.md#defining-a-service) to learn how to
create a service ref and its default factory. You can place that code directly
in the index file for now if you want, or near the actual implementation class
in question.
your service. Please see [the services article](../architecture/03-services.md)
to learn how to create a service ref and its default factory. You can place that
code directly in the index file for now if you want, or near the actual implementation
class in question.
In this example, we'll assume that your added environment field is named
`example`, and the created ref is named `exampleServiceRef`.
@@ -233,7 +232,7 @@ be used in its new form.
```ts title="packages/backend/src/index.ts"
const backend = createBackend();
/* highlight-add-next-line */
backend.add(import('@backstage/plugin-app-backend'));
backend.add(import('@backstage/plugin-app-backend/alpha'));
```
If you need to override the app package name, which otherwise defaults to `"app"`,
@@ -248,7 +247,7 @@ A basic installation of the catalog plugin looks as follows.
```ts title="packages/backend/src/index.ts"
const backend = createBackend();
/* highlight-add-start */
backend.add(import('@backstage/plugin-catalog-backend'));
backend.add(import('@backstage/plugin-catalog-backend/alpha'));
backend.add(
import('@backstage/plugin-catalog-backend-module-scaffolder-entity-model'),
);
@@ -296,7 +295,7 @@ const catalogModuleCustomExtensions = createBackendModule({
/* highlight-add-end */
const backend = createBackend();
backend.add(import('@backstage/plugin-catalog-backend'));
backend.add(import('@backstage/plugin-catalog-backend/alpha'));
backend.add(
import('@backstage/plugin-catalog-backend-module-scaffolder-entity-model'),
);
@@ -390,7 +389,7 @@ A basic installation of the scaffolder plugin looks as follows.
```ts title="packages/backend/src/index.ts"
const backend = createBackend();
/* highlight-add-next-line */
backend.add(import('@backstage/plugin-scaffolder-backend'));
backend.add(import('@backstage/plugin-scaffolder-backend/alpha'));
```
If you have other customizations made to `plugins/scaffolder.ts`, such as adding
@@ -429,7 +428,7 @@ const scaffolderModuleCustomExtensions = createBackendModule({
/* highlight-add-end */
const backend = createBackend();
backend.add(import('@backstage/plugin-scaffolder-backend'));
backend.add(import('@backstage/plugin-scaffolder-backend/alpha'));
/* highlight-add-next-line */
backend.add(scaffolderModuleCustomExtensions());
```
+1 -1
View File
@@ -10,6 +10,6 @@ description: The Backend System
## Status
The new backend system is in alpha, and only a small number of plugins have been migrated so far. It is possible to try it out, but it is not recommended to use this new system in production yet.
The new backend system is in alpha, but many plugins have already been migrated. We recommend all plugins to migrate to the new system, and you can also try it out in your own production deployments.
You can find an example backend setup in [the `backend-next` package](https://github.com/backstage/backstage/tree/master/packages/backend-next).
+5 -3
View File
@@ -107,7 +107,9 @@ $ export AWS_SECRET_ACCESS_KEY=.... (second secret value)
## Configuring the Pulumi CLI
Second, install the [Pulumi CLI](https://www.pulumi.com/docs/get-started/install/).
Second, install the [Pulumi CLI](https://www.pulumi.com/docs/get-started/install/) - `backstage-deploy` uses it to
simplify the management of cloud resources (Pulumi allows us to simply specify the desired "target cloud state", and
Pulumi will intelligently create/modify/delete resources to reach that state. Nice!).
Then we need to execute the following commands, to set Pulumi up:
@@ -126,9 +128,9 @@ By using `pulumi login --local` we are making sure that Pulumi stores our state
## Deploying your instance on Lightsail
:::warning
:::tip
Make sure that [Docker](https://docs.docker.com/) is running before you start this section.
Make sure that [Docker](https://docs.docker.com/) is running on your machine before you start this section.
:::
@@ -0,0 +1,222 @@
# Declarative Integrated Search Plugin
> **Disclaimer:**
> Declarative integration is in an experimental stage and is not recommended for production.
This is a guide for experimenting with `Search` in a declarative integrated Backstage front-end application.
## Main Concepts
Using declarative integration, you can customize your Backstage instance without writing code, see this [RFC](https://github.com/backstage/backstage/issues/18372) for more information.
In the new frontend system, everything that extends Backstage's core features is called an extension, so an extension can be anything from an API to a page component.
Extensions produces output artifacts and these artifacts are inputs consumed by other extensions:
![search extensions example](../../assets/search/search-extensions-example.drawio.svg)
In the image above, a `SearchResultItem` extension outputs a component and this component is injected as input to the `SearchPage` "items" attachment point. The `SearchPage` in turn uses the search result items to compose a search page element and outputs a route path and the page element so they are used as inputs attached to the `CoreRoutes` extension. Finally, the `CoreRoutes` renders the page element when the location matches the search page path.
The basic concepts briefly mentioned are crucial to understanding how the declarative version of the `Search` plugin works.
## Search Plugin
The search plugin is a collection of extensions that implement the search feature in Backstage.
### Installation
Only one step is required to start using the `Search` plugin within declarative integration, so all you have to do is to install the `@backstage/plugin-catalog` and `@backstage/plugin-search` packages, (e.g., [app-next](https://github.com/backstage/backstage/tree/master/packages/app-next)):
```sh
yarn add @backstage/plugin-catalog @backstage/plugin-search
```
The `Search` plugin depends on the `Catalog API`, that's the reason we have to install the ` @backstage/plugin-catalog` package too.
### Extensions
The `Search` plugin provides the following [extensions preset](https://github.com/backstage/backstage/blob/3f4a44aef39bd8dbf5098e60b6fdf66fd754c6d9/plugins/search/src/alpha.tsx#L246):
- **SearchApi**: Outputs a concrete implementation for the `Search API` that is attached as an input to the `Core` apis holder;
- **SearchPage**: Outputs a component that represents the advanced `Search` page interface, this extension expects `Search` result items components as inputs to use them for rendering results in a custom way;
- **SearchNavItem**: It is an extension that outputs a data that represents a `Search` item in the main application sidebar, in other words, it inputs a sidebar item to the `Core` nav extension.
### Configurations
The `Search` extensions are configurable via `app-config.yaml` file in the `app.extensions` field using the extension id as the configuration key:
_Example disabling the search page extension_
```yaml
# app-config.yaml
app:
extensions:
- plugin.search.page: false # ✨
```
_Example setting the search sidebar item label_
```yaml
# app-config.yaml
app:
extensions:
- plugin.search.nav.index: # ✨
config:
label: 'Search Page'
```
> **Known limitations:**
> It is currently not possible to open modals in sidebar items and also configure a different icon via configuration file, but it is already on the maintainers' radar.
### Customizations
Plugin developers can use the `createSearchResultItemExtension` factory provided by the `@backstage/plugin-search-react` for building their own custom `Search` result item extensions.
_Example creating a custom `TechDocsSearchResultItemExtension`_
```tsx
// plugins/techdocs/alpha.tsx
import { createSearchResultListItemExtension } from '@backstage/plugin-search-react/alpha';
/** @alpha */
export const TechDocsSearchResultListItemExtension =
createSearchResultListItemExtension({
id: 'techdocs',
configSchema: createSchemaFromZod(z =>
z.object({
noTrack: z.boolean().default(false),
lineClamp: z.number().default(5),
}),
),
predicate: result => result.type === 'techdocs',
component: async ({ config }) => {
const { TechDocsSearchResultListItem } = await import(
'./components/TechDocsSearchResultListItem'
);
return props => <TechDocsSearchResultListItem {...props} {...config} />;
},
});
```
In the snippet above, a plugin developer is providing a custom component for rendering search results of type "techdocs". The custom result item extension will be enabled by default once the `@backstage/plugin-techdocs` package is installed, that means adopters don't have to enable the extension manually via configuration file.
When a Backstage adopter doesn't want to use the custom `TechDocs` search result item after installing the `TechDocs` plugin, they could disable it via Backstage configuration file:
```yaml
# app-config.yaml
app:
extensions:
- plugin.search.result.item.techdocs: false # ✨
```
Because a configuration schema was provided to the extension factory, Backstage adopters will be able to customize `TechDocs` search results **line clamp** that defaults to 3 and also **disable automatic analytics events tracking**:
```yaml
# app-config.yaml
app:
extensions:
- plugin.search.result.item.techdocs:
config: # ✨
noTrack: true
lineClamp: 3
```
[comment]: <> (TODO: Extract this explanation to a more central place in the future)
The `createSearchResultItemExtension` function returns a Backstage's extension representation as follows:
```ts
{
"$$type": "@backstage/Extension", // [1]
"id": "plugin.search.result.item.techdocs", // [2]
"at": "plugin.search.page/items", // [3]
"inputs": {} // [4]
"output": { // [5]
"item": {
"$$type": "@backstage/ExtensionDataRef",
"id": "plugin.search.result.item.data",
"config": {}
}
},
"configSchema": { // [6]
"schema": {
"type": "object",
"properties": {
"noTrack": {
"type": "boolean",
"default": false
},
"lineClamp": {
"type": "number",
"default": 5
}
},
"additionalProperties": false,
"$schema": "http://json-schema.org/draft-07/schema#"
}
},
"disabled": false, // [7]
}
```
In this object, you can see exactly what will happen once the custom extension is installed:
- **[1] $$type**: declares that the object represents an extension;
- **[2] id**: Is a unique identification for the extension, the `plugin.search.result.item.techdocs` is the key used to configure the extension in the `app-config.yaml` file;
- **[3] at**: It represents the extension attachment point, so the value `plugin.search.page/items` says that the `TechDocs`'s search result item output will be injected as input on the "items" attachment expected by the search page extension;
- **[4] inputs**: in this case is an empty object because this extension doesn't expect inputs;
- **[5] output**: Object representing the artifact produced by the `TechDocs` result item extension, on the example, it is a react component reference;
- **[6] configSchema**: represents the `TechDocs` search result item configuration definition, this is the same schema that adopters will use for customizing the extension via `app-config.yaml` file;
- **[7] disable**: Says that the result item extension will be enable by default when the `TechDocs` plugin is installed in the app.
To complete the development cycle for creating a custom search result item extension, we should provide the extension via `TechDocs` plugin:
```tsx
// plugins/techdocs/alpha.tsx
import { createPlugin } from "@backstage/frontend-plugin-api";
// plugins should be always exported as default
export default createPlugin({
id: 'techdocs'
extensions: [TechDocsSearchResultItemExtension]
})
```
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:
```tsx
// plugins/techdocs/alpha.tsx
import { createPlugin } from '@backstage/frontend-plugin-api';
import { createSearchResultListItemExtension } from '@backstage/plugin-search-react/alpha';
/** @alpha */
export const TechDocsSearchResultListItemExtension =
createSearchResultListItemExtension({
id: 'techdocs',
configSchema: createSchemaFromZod(z =>
z.object({
noTrack: z.boolean().default(false),
lineClamp: z.number().default(5),
}),
),
predicate: result => result.type === 'techdocs',
component: async ({ config }) => {
const { TechDocsSearchResultListItem } = await import(
'./components/TechDocsSearchResultListItem'
);
return props => <TechDocsSearchResultListItem {...props} {...config} />;
},
});
/** @alpha */
export default createPlugin({
// plugins should be always exported as default
id: 'techdocs',
extensions: [TechDocsSearchResultListItemExtension],
});
```
### Future Enhancement Opportunities
Backstage maintainers are currently working on the extension replacement feature, and with this release, adopters will also be able to replace extensions provided by plugins, so stay tuned for future updates to this documentation.
The first version of the `SearchPage` extension makes room for the `Search` plugin maintainers to convert filters into extensions as well in the future, if you also would like to collaborate with them on this idea, don't hesitate to open an issue and submit a pull request, your contribution is more than welcome!
+27 -8
View File
@@ -114,18 +114,18 @@ of the `SearchType` component.
> Check out the documentation around [integrating search into plugins](../../plugins/integrating-search-into-plugins.md#create-a-collator) for how to create your own collator.
## How to customize fields in the Software Catalog index
## How to customize fields in the Software Catalog or TechDocs index
Sometimes you will might want to have ability to control
which data passes to search index in catalog collator, or to customize data for specific kind.
You can easily do that by passing `entityTransformer` callback to `DefaultCatalogCollatorFactory`.
You can either just simply amend default behaviour, or even to write completely new document
(which should follow some required basic structure though).
Sometimes, you might want to have the ability to control which data passes into the search index
in the catalog collator or customize data for a specific kind. You can easily achieve this
by passing an `entityTransformer` callback to the `DefaultCatalogCollatorFactory`. This behavior
is also possible for the `DefaultTechDocsCollatorFactory`. You can either simply amend the default behavior
or even write an entirely new document (which should still follow some required basic structure).
> `authorization` and `location` cannot be modified via a `entityTransformer`, `location` can be modified only through `locationTemplate`.
```ts title="packages/backend/src/plugins/search.ts"
const entityTransformer: CatalogCollatorEntityTransformer = (
const catalogEntityTransformer: CatalogCollatorEntityTransformer = (
entity: Entity,
) => {
if (entity.kind === 'SomeKind') {
@@ -146,7 +146,26 @@ indexBuilder.addCollator({
discovery: env.discovery,
tokenManager: env.tokenManager,
/* highlight-add-next-line */
entityTransformer,
entityTransformer: catalogEntityTransformer,
}),
});
const techDocsEntityTransformer: TechDocsCollatorEntityTransformer = (
entity: Entity,
) => {
return {
// add more fields to the index
...defaultTechDocsCollatorEntityTransformer(entity),
tags: entity.metadata.tags,
};
};
indexBuilder.addCollator({
collator: DefaultTechDocsCollatorFactory.fromConfig(env.config, {
discovery: env.discovery,
tokenManager: env.tokenManager,
/* highlight-add-next-line */
entityTransformer: techDocsEntityTransformer,
}),
});
```
@@ -44,6 +44,20 @@ When multiple `catalog-info.yaml` files with the same `metadata.name` property
are discovered, one will be processed and all others will be skipped. This
action is logged for further investigation.
### Local File (`type: file`) Configurations
In addition to url locations, you can use the `file` location type to bring in content from the local file system. You should only use this for local development, test setups and example data, not for production data.
You are also not able to use placeholders in them like `$text`. You can however reference other files relative to the current file. See the full [catalog example data set here](https://github.com/backstage/backstage/tree/master/packages/catalog-model/examples) for an extensive example.
Here is an example pulling in the `all.yaml` file from the examples folder. Note the use of `../../` to go up two levels from the current execution path of the backend. This is typically `packages/backend/`.
```yaml
catalog:
locations:
- type: file
target: ../../examples/all.yaml
```
### Integration Processors
Integrations may simply provide a mechanism to handle `url` location type for an
@@ -447,6 +447,9 @@ want to have an isomorphic package that houses these types. Within the Backstage
main repo the package naming pattern of `<plugin>-common` is used for isomorphic
packages, and you may choose to adopt this pattern as well.
You can generate an isomorphic plugin package by running:`yarn new --select plugin-common`
or you can run `yarn new` and then select "plugin-common" from the list of options
There's at this point no existing templates for generating isomorphic plugins
using the `@backstage/cli`. Perhaps the simplest wat to get started right now is
to copy the contents of one of the existing packages in the main repository,
@@ -110,10 +110,11 @@ parameters:
arrayObjects:
title: Array with custom objects
type: array
minItems: 0
ui:options:
addable: false
orderable: false
removable: false
addable: true
orderable: true
removable: true
items:
type: object
properties:
+4 -4
View File
@@ -65,7 +65,7 @@ page in your `App.tsx`:
// packages/app/src/App.tsx
import { TechDocsReaderPage } from '@backstage/plugin-techdocs';
import { TechDocsAddons } from '@backstage/plugin-techdocs-react/alpha';
import { TechDocsAddons } from '@backstage/plugin-techdocs-react';
import { ReportIssue } from '@backstage/plugin-techdocs-module-addons-contrib';
// ...
@@ -99,7 +99,7 @@ is very similar; instead of adding the `<TechDocsAddons>` registry under a
import { EntityLayout } from '@backstage/plugin-catalog';
import { EntityTechdocsContent } from '@backstage/plugin-techdocs';
import { TechDocsAddons } from '@backstage/plugin-techdocs-react/alpha';
import { TechDocsAddons } from '@backstage/plugin-techdocs-react';
import { ReportIssue } from '@backstage/plugin-techdocs-module-addons-contrib';
// ...
@@ -146,7 +146,7 @@ an Addon, follow these steps:
import {
createTechDocsAddonExtension,
TechDocsAddonLocations,
} from '@backstage/plugin-techdocs-react/alpha';
} from '@backstage/plugin-techdocs-react';
import { CatGifComponent, CatGifComponentProps } from './addons';
// ...
@@ -179,7 +179,7 @@ provided by the Addon framework.
// plugins/your-plugin/src/addons/MakeAllImagesCatGifs.tsx
import React, { useEffect } from 'react';
import { useShadowRootElements } from '@backstage/plugin-techdocs-react/alpha';
import { useShadowRootElements } from '@backstage/plugin-techdocs-react';
// This is a normal react component; in order to make it an Addon, you would
// still create and provide it via your plugin as described above. The only
+1
View File
@@ -95,6 +95,7 @@ Options:
--preview-app-bundle-path <PATH_TO_BUNDLE> Preview documentation using a web app other than the included one.
--preview-app-port <PORT> Port where the preview will be served.
Can only be used with "--preview-app-bundle-path". (default: "3000")
-c, --mkdocs-config-file-name <FILENAME> Yaml file to use as config by mkdocs.
-v --verbose Enable verbose output. (default: false)
-h, --help display help for command
```
+33
View File
@@ -525,6 +525,39 @@ techdocs:
This way, all iframes where the host in the src attribute is in the
`sanitizer.allowedIframeHosts` list will be displayed.
## How to render PlantUML diagram in TechDocs
PlantUML allows you to create diagrams from plain text language. Each diagram description begins with the keyword - (@startXYZ and @endXYZ, depending on the kind of diagram). For UML Diagrams, Keywords @startuml & @enduml should be used. Further details for all types of diagrams can be found at [PlantUML Language Reference Guide](https://plantuml.com/guide).
### UML Diagram Details:-
#### Embedded PlantUML Diagram Example
Here, the markdown file itself contains the diagram description.
````md
```plantuml
@startuml
title Login Sequence
ComponentA->ComponentB: Login Request
note right of ComponentB: ComponentB logs message
ComponentB->ComponentA: Login Response
@enduml
```
````
#### Referenced PlantUML Diagram Example
Here, the markdown file refers to another file (`*.puml` or `*.pu`) which contains the diagram description.
````md
```plantuml
!include umldiagram.puml
```
````
Note: To refer external diagram files, we need to include the diagrams directory in the path. Please refer [`Dockerfile`](https://github.com/backstage/techdocs-container/blob/main/Dockerfile) for details.
## How to add Mermaid support in TechDocs
To add `Mermaid` support in TechDocs, you can use [`kroki`](https://kroki.io)
+30 -20
View File
@@ -130,13 +130,14 @@ export default async function createPlugin(
builder.addProcessor(new ScaffolderEntitiesProcessor());
/* highlight-add-start */
const githubOrgProvider = GithubOrgEntityProvider.fromConfig(env.config, {
id: 'production',
orgUrl: 'https://github.com/backstage',
logger: env.logger,
schedule: env.scheduler.createScheduledTaskRunner({
frequency: { minutes: 60 },
timeout: { minutes: 15 },
}),
id: 'production',
orgUrl: 'https://github.com/backstage',
logger: env.logger,
schedule: env.scheduler.createScheduledTaskRunner({
frequency: { minutes: 60 },
timeout: { minutes: 15 },
}),
});
env.eventBroker.subscribe(githubOrgProvider);
builder.addEntityProvider(githubOrgProvider);
/* highlight-add-end */
@@ -254,23 +255,32 @@ configured such an email in their own account. The API will only return these
values when using GitHub App authentication and with the correct app permission
allowing access to emails.
You can decorate the `defaultUserTransformer` to replace the org email in the
You can decorate the default `userTransformer` to replace the org email in the
returned identity.
```typescript
async (user, ctx): Promise<UserEntity | undefined> => {
const entity = await defaultUserTransformer(user, ctx);
if (entity && user.organizationVerifiedDomainEmails?.length) {
entity.spec.profile!.email = user.organizationVerifiedDomainEmails[0];
}
return entity;
},
```ts title="packages/backend/src/plugins/catalog.ts"
const githubOrgProvider = GithubOrgEntityProvider.fromConfig(env.config, {
id: 'production',
orgUrl: 'https://github.com/backstage',
logger: env.logger,
schedule: env.scheduler.createScheduledTaskRunner({
frequency: { minutes: 60 },
timeout: { minutes: 15 },
}),
/* highlight-add-start */
userTransformer: async (user, ctx) => {
const entity = await defaultUserTransformer(user, ctx);
if (entity && user.organizationVerifiedDomainEmails?.length) {
entity.spec.profile!.email = user.organizationVerifiedDomainEmails[0];
}
return entity;
},
/* highlight-add-end */
});
```
Once you have imported the emails you can resolve users in your sign-in in
resolver using the catalog entity search via email
Once you have imported the emails you can resolve users in your [sign-in
resolver](../../auth/github/provider.md) using the catalog entity search via email
```typescript title="packages/backend/src/plugins/auth.ts"
ctx.signInWithCatalogUser({
+23 -59
View File
@@ -484,30 +484,29 @@ of the build system, including the bundling, tests, builds, and type checking.
Loaders are always selected based on the file extension. The following is a list
of all supported file extensions:
| Extension | Exports | Purpose |
| ----------- | --------------- | -------------------------------------------------------------------------------------- |
| `.ts` | Script Module | TypeScript |
| `.tsx` | Script Module | TypeScript and XML |
| `.js` | Script Module | JavaScript |
| `.jsx` | Script Module | JavaScript and XML |
| `.mjs` | Script Module | ECMAScript Module |
| `.cjs` | Script Module | CommonJS Module |
| `.json` | JSON Data | JSON Data |
| `.yml` | JSON Data | YAML Data |
| `.yaml` | JSON Data | YAML Data |
| `.css` | classes | Style sheet |
| `.eot` | URL Path | Font |
| `.ttf` | URL Path | Font |
| `.woff2` | URL Path | Font |
| `.woff` | URL Path | Font |
| `.bmp` | URL Path | Image |
| `.gif` | URL Path | Image |
| `.jpeg` | URL Path | Image |
| `.jpg` | URL Path | Image |
| `.png` | URL Path | Image |
| `.svg` | URL Path | Image |
| `.md` | URL Path | Markdown File |
| `.icon.svg` | React Component | SVG converted into a [Material UI SvgIcon](https://mui.com/material-ui/icons/#svgicon) |
| Extension | Exports | Purpose |
| --------- | ------------- | ------------------ |
| `.ts` | Script Module | TypeScript |
| `.tsx` | Script Module | TypeScript and XML |
| `.js` | Script Module | JavaScript |
| `.jsx` | Script Module | JavaScript and XML |
| `.mjs` | Script Module | ECMAScript Module |
| `.cjs` | Script Module | CommonJS Module |
| `.json` | JSON Data | JSON Data |
| `.yml` | JSON Data | YAML Data |
| `.yaml` | JSON Data | YAML Data |
| `.css` | classes | Style sheet |
| `.eot` | URL Path | Font |
| `.ttf` | URL Path | Font |
| `.woff2` | URL Path | Font |
| `.woff` | URL Path | Font |
| `.bmp` | URL Path | Image |
| `.gif` | URL Path | Image |
| `.jpeg` | URL Path | Image |
| `.jpg` | URL Path | Image |
| `.png` | URL Path | Image |
| `.svg` | URL Path | Image |
| `.md` | URL Path | Markdown File |
## Jest Configuration
@@ -675,38 +674,3 @@ To add subpath exports to an existing package, simply add the desired `"exports"
```bash
yarn backstage-cli migrate package-exports
```
## Experimental Type Build
> Note: Experimental type builds are deprecated and will be removed in the future. They have been replaced by [subpath exports](#subpath-exports).
The Backstage CLI has an experimental feature where multiple different type definition files can be generated for different release stages. The release stages are marked in the [TSDoc](https://tsdoc.org/) for each individual export, using either `@public`, `@alpha`, or `@beta`. Rather than just building a single `index.d.ts` file, the build process will instead output `index.d.ts`, `index.beta.d.ts`, and `index.alpha.d.ts`. Each of these files will have exports from more unstable release stages stripped, meaning that `index.d.ts` will omit all exports marked with `@alpha` or `@beta`, while `index.beta.d.ts` will omit all exports marked with `@alpha`.
This feature is aimed at projects that publish to package registries and wish to maintain different levels of API stability within each package. There is no need to use this within a single monorepo, as it has no effect due to only applying to built and published packages.
In order for the experimental type build to work, `@microsoft/api-extractor` must be installed in your project, as it is an optional peer dependency of the Backstage CLI. There are then three steps that need to be taken for each package where you want to enable this feature:
- Add the `--experimental-type-build` flag to the `"build"` script of the package.
- Add either one or both of `"alphaTypes"` and `"betaTypes"` to the `"publishConfig"` of the package:
```json
"publishConfig": {
...
"types": "dist/index.d.ts",
"alphaTypes": "dist/index.alpha.d.ts",
"betaTypes": "dist/index.beta.d.ts"
},
```
- Add either one or both of `"alpha"` and `"beta"` to the `"files"` of the package:
```json
"files": [
"dist",
"alpha",
"beta"
]
```
Once this setup is complete, users of the published packages will only be able to access the stable API via the main package entry point, for example `@acme/my-plugin`. Exports marked with `@alpha` or `@beta` will only be available via the `/alpha` entry point, for example `@acme/my-plugin/alpha`, and exports marked with `@beta` will only be available via `/beta`. This does not apply within the monorepo that contains the package. There all exports still have to be imported via the main entry point.
Note that these different entry points are only separated during type checking. At runtime they all share the same code which contains the exports from all releases stages.
An example of this setup can be seen in the [`@backstage/catalog-model`](https://github.com/backstage/backstage/blob/da0675bf9f28ed1460f03635a22d3c26abd14707/packages/catalog-model/package.json#L14) package, which has enabled `alpha` type exports. With this setup, exports marked as `@alpha` are only available for import via `@backstage/catalog-model/alpha`. The `@backstage/catalog-model` package currently does not have any exports marked as `@beta`, or a `/beta` entry point.
+41
View File
@@ -0,0 +1,41 @@
## OpenAPI Validation using Test Cases
This is primarily performed by `backstage-repo-tools schema openapi test`. Any errors found in the generated specs can be either
1. Fixed manually, this is usually relevant for request body or response body changes.
2. Fixed automatically with `backstage-repo-tools schema openapi test --update`.
3. Fixing the test case. This can happen where a response is mocked as
```ts
it('should return the right value', () => {
// We will assume that this is the actual response and update the spec accordingly.
// Ideally, this should be a fully populated return value.
const entity: Entity = {} as any;
app.get('/test', () => {
return entity;
});
const response = await request(app).get('/test');
expect(response.body).toEqual(entity);
});
```
will cause an invalid spec validation. The return value doesn't have all properties as defined in the type. Try to avoid this if possible. Something better would be,
```ts
it('should return the right value', () => {
// We will assume that this is the actual response and update the spec accordingly.
// Ideally, this should be a fully populated return value.
const entity: Entity = {
apiVersion: 'a1',
kind: 'k1',
metadata: { name: 'n1' },
};
app.get('/test', () => {
return entity;
});
const response = await request(app).get('/test');
expect(response.body).toEqual(entity);
});
```
Additionally, for more advanced use cases, you can run `yarn optic capture {PATH_TO_OPENAPI_FILE} --update interactive` and go through the prompts on the screen. Under the hood, the test validation + updating is done by [Optic](https://github.com/opticdev/optic), a great project around supporting OpenAPI specs and development. You can find additional options [here](https://www.useoptic.com/docs/verify-openapi).
+3
View File
@@ -323,8 +323,11 @@ backend:
cache:
store: redis
connection: redis://user:pass@cache.example.com:6379
useRedisSets: true
```
The useRedisSets flag is explained [here](https://github.com/jaredwray/keyv/tree/main/packages/redis#useredissets).
Contributions supporting other cache stores are welcome!
## Containerization
@@ -349,7 +349,7 @@ import { createRouter } from './service/router';
/**
* The example TODO list backend plugin.
*
* @alpha
* @public
*/
export const exampleTodoListPlugin = createBackendPlugin({
pluginId: 'exampleTodoList',
+11 -3
View File
@@ -8,7 +8,7 @@ A Backstage Plugin adds functionality to Backstage.
## Create a Plugin
To create a new plugin, make sure you've run `yarn install` and installed
To create a new frontend plugin, make sure you've run `yarn install` and installed
dependencies, then run the following on your command line (a shortcut to
invoking the
[`backstage-cli new --select plugin`](../local-dev/cli-commands.md#new))
@@ -18,7 +18,7 @@ from the root of your project.
yarn new --select plugin
```
![](../assets/getting-started/create-plugin_output.png)
![Example of output when creating a new plugin](../assets/getting-started/create-plugin_output.png)
This will create a new Backstage Plugin based on the ID that was provided. It
will be built and added to the Backstage App automatically.
@@ -27,7 +27,7 @@ will be built and added to the Backstage App automatically.
> should be able to see the default page for your new plugin directly by
> navigating to `http://localhost:3000/my-plugin`.
![](../assets/my-plugin_screenshot.png)
![Example of new plugin running in browser](../assets/plugins/my-plugin_screenshot.png)
You can also serve the plugin in isolation by running `yarn start` in the plugin
directory. Or by using the yarn workspace command, for example:
@@ -39,3 +39,11 @@ yarn workspace @backstage/plugin-my-plugin start # Also supports --check
This method of serving the plugin provides quicker iteration speed and a faster
startup and hot reloads. It is only meant for local development, and the setup
for it can be found inside the plugin's `dev/` directory.
### Other Plugin Library Package Types
There are other plugin library package types that you can chose from. To be able to
select the type when you create a new plugin just run: `yarn new`. You'll then be asked
what type of plugin you wish to create like this:
![List of available plugin types to pick from](../assets/plugins/create-plugin_types.png)
+1 -1
View File
@@ -12,7 +12,7 @@ development tool as a plugin in Backstage. By following strong
[design guidelines](../dls/design.md) we ensure the overall user experience
stays consistent between plugins.
![plugin](../assets/my-plugin_screenshot.png)
![plugin](../assets/plugins/my-plugin_screenshot.png)
## Creating a plugin
@@ -22,7 +22,7 @@ Imagine you have a plugin that is responsible for storing FAQ snippets in a data
The search platform provides an interface (`DocumentCollatorFactory` from package `@backstage/plugin-search-common`) that allows you to do exactly that. It works by registering each of your entries as a "document" that later represents one search result each.
> You can always look at a working example, e.g. [StackOverflowQuestionsCollatorFactory](https://github.com/backstage/backstage/blob/master/plugins/stack-overflow-backend/src/search/StackOverflowQuestionsCollatorFactory.ts), if you are unsure or want to follow best practices.
> You can always look at a working example, e.g. [StackOverflowQuestionsCollatorFactory](https://github.com/backstage/backstage/blob/master/plugins/search-backend-module-stack-overflow-collator/src/collators/StackOverflowQuestionsCollatorFactory.ts), if you are unsure or want to follow best practices.
#### 1. Install collator interface dependencies
+8 -7
View File
@@ -36,13 +36,14 @@ Example:
```yaml
# in app-config.yaml
proxy:
/simple-example: http://simple.example.com:8080
'/larger-example/v1':
target: http://larger.example.com:8080/svc.v1
headers:
Authorization: ${EXAMPLE_AUTH_HEADER}
# ...or interpolating a value into part of a string,
# Authorization: Bearer ${EXAMPLE_AUTH_TOKEN}
endpoints:
/simple-example: http://simple.example.com:8080
'/larger-example/v1':
target: http://larger.example.com:8080/svc.v1
headers:
Authorization: ${EXAMPLE_AUTH_HEADER}
# ...or interpolating a value into part of a string,
# Authorization: Bearer ${EXAMPLE_AUTH_TOKEN}
```
Each key under the proxy configuration entry is a route to match, below the
+38 -44
View File
@@ -18,11 +18,11 @@ Running all tests:
yarn test
Running an individual test (e.g. `MyComponent.test.js`):
Running an individual test (e.g. `MyComponent.test.tsx`):
yarn test MyComponent
To run both `MyComponent.test.js` and `MyControl.test.js` suite of tests:
To run both `MyComponent.test.tsx` and `MyControl.test.tsx` suite of tests:
yarn test MyCo
@@ -32,9 +32,9 @@ working on.
## Naming Test Files
Tests should be named `[filename].test.js`.
Tests should be named `[filename].test.ts`, or `[filename].test.tsx` if it contains JSX (as is the case for a lot of React tests, e.g. components).
For example, the tests for **`Link.js`** exist in the file **`Link.test.js`**.
For example, the tests for **`Link.tsx`** exist in the file **`Link.test.tsx`**.
## Third-Party Dependencies
@@ -183,9 +183,9 @@ data then it actually does it. this way both tests fail if the data loading part
breaks and the next developer immediately know the problem is that the data
loading is broken, not that the loading indicator is broken.
# Examples
## Examples
## Utility Functions
### Utility Functions
A utility function is a function with no side effects. It takes in arguments and
returns a result or displays an error or console message, like so:
@@ -241,12 +241,12 @@ it('Works with midCharIx', () => {
});
```
## Non-React Classes
### Non-React Classes
Testing a JavaScript object which is _not_ a React component follows a lot of
the same principles as testing objects in other languages.
### API Testing Principles
#### API Testing Principles
Testing an API involves verifying four things:
@@ -255,7 +255,7 @@ Testing an API involves verifying four things:
3. Server response is translated into an expected JavaScript object.
4. Server errors are handled gracefully.
### Mocking API Calls
#### Mocking API Calls
[Mocking in Jest](https://facebook.github.io/jest/docs/en/mock-functions.html)
involves wrapping existing functions (like an API call function) with an
@@ -263,52 +263,46 @@ alternative.
For example:
**`./MyApi.js`**
**`./MyApi.ts`**
```ts
export {
fetchSomethingFromServer: () => {
// Live production call to a URI. Must be avoided during testing!
return fetch('blah');
}
};
```
**`./__mocks__/MyApi.js`**
```ts
export {
fetchSomethingFromServer: () => {
// Simulate a production call, but avoid jest and just use a promise
return Promise.resolve('some result object simulating server data here');
}
export async function fetchSomethingFromServer() {
// Live production call to a URI. Must be avoided during testing!
return fetch('blah');
}
```
**`./MyApi.test.js`**
**`./__mocks__/MyApi.ts`**
```ts
/* eslint-disable import/first */
export async function fetchSomethingFromServer() {
// Simulate a production call response
return 'some result object simulating server data here';
}
```
jest.mock('./MyApi'); // Instruct Jest to swap all future imports of './MyApi.js' to './__mocks__/MyApi.js'
**`./MyApi.test.ts`**
import MyApi from './MyApi'; // Will actually return the contents of the file in the __mocks__ folder now
```ts
// This import will actually return the contents of the file in the
// __mocks__ folder now, due to the jest.mock line below
import { fetchSomethingFromServer } from './MyApi';
it('loads data', done => {
MyApi.fetchSomethingFromServer().then(result => {
expect(result).toBe('some result object simulating server data here');
done();
});
// This instructs Jest to swap all imports of './MyApi.ts' to
// './__mocks__/MyApi.ts' - this gets automatically hoisted to the top
// of the file
jest.mock('./MyApi');
it('loads data', async () => {
await expect(fetchSomethingFromServer()).resolves.toBe(
'some result object simulating server data here',
);
});
```
Note: make sure you disable the eslint `'import/first'` rule at the top of the
file since technically you are not allowed by the default settings to have an
import after the `jest.mock` call.
### React Components
## React Components
### Working with the React Lifecycle
#### Working with the React Lifecycle
The [React lifecycle](https://reactjs.org/docs/state-and-lifecycle.html) is
asynchronous.
@@ -317,7 +311,7 @@ When you call `setState` or update the `props` of a component, there are several
asynchronous stages that must occur before a rerender. Note the following
example:
```jsx
```tsx
class MyComponent extends Component {
load() {
this.setState({loading: true});
@@ -350,7 +344,7 @@ For more information:
- [React lifecycle](https://reactjs.org/docs/state-and-lifecycle.html)
### Accessing `store`, `theme`, routing, browser history, etc.
#### Accessing `store`, `theme`, routing, browser history, etc
The Backstage application has several core providers at its root. To run your
test wrapped in a "sample" Backstage application, you can use our utility
@@ -369,6 +363,6 @@ functions:
Note: wrapping in the test application **requires** you to do a `find()` or
`dive()` since the wrapped component is now the application.
# Debugging Jest Tests
## Debugging Jest Tests
You can find it [here](https://backstage.io/docs/local-dev/cli-build-system#debugging-jest-tests)
+1 -1
View File
@@ -40,7 +40,7 @@ Congratulations on the release! There should be now a post in the [`#announcemen
Additional steps for the main line release
- [Switch Release Mode](#switching-release-modes) to exit pre-release mode. This can be done at any time after the last Next Line Release.
- Check [`.changeset/pre.json`](https://github.com/backstage/backstage/blob/master/.changeset/pre.json) if the `mode` is set to `exit`. If you encounter `mode: "pre"` it indicates a next line release.
- Check `.changeset/pre.json` <!-- do not link to pre.json, it breaks the build when it doesn't exist --> if the `mode` is set to `exit`. If you encounter `mode: "pre"` it indicates a next line release.
- Check [`Version Packages` Pull Request](https://github.com/backstage/backstage/pulls?q=is%3Aopen+is%3Apr+in%3Atitle+%22Version+Packages)
- Check for mentions of "major" & "breaking" and if they are expected in the current release
- Verify the version we are shipping is correct
+1 -1
View File
@@ -12,7 +12,7 @@ A huge thanks to the whole team of maintainers and contributors as well as the a
### <title>
<short description>. Contributed by [@<user>](https://github.com/<user>) [#<pr>](https://github.com/backstage/backstage/pull/<pr>)
<short description>. Contributed by [@<user>](https://github.com/<user>) in [#<pr>](https://github.com/backstage/backstage/pull/<pr>)
## Security Fixes
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -4,7 +4,7 @@
### Minor Changes
- 7077dbf131: The new backend start command that used to be enabled by setting `EXPERIMENTAL_BACKEND_START` is now the default. To revert to the old behavior, set `LEGACY_BACKEND_START` instead.
- 7077dbf131: **BREAKING** The new backend start command that used to be enabled by setting `EXPERIMENTAL_BACKEND_START` is now the default. To revert to the old behavior set `LEGACY_BACKEND_START`, which is recommended if you haven't migrated to the new backend system.
This new command is no longer based on Webpack, but instead uses Node.js loaders to transpile on the fly. Rather than hot reloading modules the entire backend is now restarted on change, but the SQLite database state is still maintained across restarts via a parent process.
@@ -297,9 +297,9 @@
- de42eebaaf: Bumped dev dependencies `@types/node` and `mock-fs`.
- 04a3f65e15: Bump Docker base images to `node:18-bullseye-slim` to fix compatibility issues raised during image build.
- 04a3f65e15: Bump Docker base images to `node:18-bookworm-slim` to fix node compatibility issues raised during image build.
You can apply these change to your own `Dockerfile` by replacing `node:16-bullseye-slim` with `node:18-bullseye-slim`
You can apply these change to your own `Dockerfile` by replacing `node:16-bullseye-slim` with `node:18-bookworm-slim`
- 5eacd5d213: The E2E test setup based on Cypress has been replaced with one based on [Playwright](https://playwright.dev/). Migrating existing apps is not required as this is a standalone setup, only do so if you also want to switch from Cypress to Playwright.
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+86
View File
@@ -0,0 +1,86 @@
---
id: v1.19.0
title: v1.19.0
description: Backstage Release v1.19.0
---
These are the release notes for the v1.19.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
### Node.js v18 + v20
The supported versions of Node.js are now v18 and v20. Be sure to update the `engine` field in your root `package.json` accordingly and update your Dockerfile base images, for example to `node:18-bookworm-slim`.
### New default `start` command for backends
Backend packages now use the new `package start` implementation by default. This new version uses module loaders rather than a Webpack build for transpilation. The largest difference from the old version is that the backend process is now restarted on change, rather than using Webpack hot module reloads. When using SQLite the database state is serialized and stored in the parent process across restart, which requires a [migration to the new backend system](https://backstage.io/docs/backend-system/building-backends/migrating). If you have yet to migrate to the new system it is recommended that you set the `LEGACY_BACKEND_START` environment variable when starting the backend to keep the old behavior.
### **BREAKING**: Allow passing undefined `labelSelector` to `KubernetesFetcher`
`KubernetesFetch` no longer auto-adds `labelSelector` when an empty string is passed.
This is only applicable if you have a custom ObjectProvider implementation, as build-in `KubernetesFanOutHandler` already does this.
Contributed by [@szubster](https://github.com/szubster) in [#20541](https://github.com/backstage/backstage/pull/20541)
### **DEPRECATION**: Catalog GraphQL Backend Package
This package has been deprecated, consider using [@frontside/backstage-plugin-graphql-backend](https://www.npmjs.com/package/@frontside/backstage-plugin-graphql-backend) instead.
### **DEPRECATION**: `.icon.svg` Extension Support
Support for the `.icon.svg` extension has been deprecated and will be removed in a future release. Please migrate existing usage to either inline the SVG elements in a `<SvgIcon>` component from MUI, or switch to a regular `.svg` asset import.
### Insightful Homepage
You can now create an Insightful homepage to show your users their recent and top visited activity in Backstage. Add [this](https://github.com/backstage/backstage/tree/master/plugins/home#page-visit-homepage-component-homepagetopvisited--homepagerecentlyvisited) plugin to track your users recent navigation history in your Backstage database and display it in the Backstage Homepage using the customizable Recent and Top visits components (`<HomePageTopVisited />` and `<HomePageRecentlyVisited />`)and the extensible Visits API interface. This feature is released with an example that extends the Visits API with LocalStorage as an alternative storage solution for user visit activity.
### New plugin: Kubernetes Clusters
This plugin lets you view Kubernetes clusters as an admin.
### New feature: New Pinniped Auth Provider Module
This module provides a Pinniped auth provider implementation for the auth backend.
Contributed by [@RubenV-dev](https://github.com/RubenV-dev) in [#19846](https://github.com/backstage/backstage/pull/19846)
## More Movement Toward the New Backend System
Since the last release, a lot of contributions have been made toward migrating features to support [the new backend system](https://backstage.io/docs/backend-system/).
The following backend plugins were migrated:
- jenkins
- nomad
- sonarqube
- playlist
The Kubernetes backend broadened its backend system feature set, with a new extension point. For the catalog backend, some new modules were added, including GitHub org and Microsoft/Azure.
If you would like to help out with these efforts, check out [this issue](https://github.com/backstage/backstage/issues/18301)!
## Security Fixes
Some improvements were made in the configuration schemas, ensuring that no secret fields could be read outside of a backend context.
The `lerna` package in newly scaffolded Backstage repositories is now of version >7 which has 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.19.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.
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1299,7 +1299,7 @@
- d3fea4ae0a: Internal fixes to avoid implicit usage of globals
- 3280711113: Updated dependency `msw` to `^0.49.0`.
- 9516b0c355: Added support for sending virtual pageviews on `search` events in order to enable
Site Search functionality in GA. For more information consult [README](/plugins/analytics-module-ga/README.md#enabling-site-search)
Site Search functionality in GA. For more information consult [README](https://github.com/backstage/backstage/blob/master/plugins/analytics-module-ga/README.md#enabling-site-search)
- Updated dependencies
- @backstage/core-plugin-api@1.2.0
- @backstage/core-components@0.12.1
+1 -1
View File
@@ -525,7 +525,7 @@
### Patch Changes
- 9516b0c355: Added support for sending virtual pageviews on `search` events in order to enable
Site Search functionality in GA. For more information consult [README](/plugins/analytics-module-ga/README.md#enabling-site-search)
Site Search functionality in GA. For more information consult [README](https://github.com/backstage/backstage/blob/master/plugins/analytics-module-ga/README.md#enabling-site-search)
- Updated dependencies
- @backstage/core-plugin-api@1.2.0-next.2
- @backstage/core-components@0.12.1-next.2
-2
View File
@@ -4,8 +4,6 @@ title: Migration to Yarn 3
description: Guide for how to migrate a Backstage project to use Yarn 3
---
> NOTE: We do not yet recommend all projects to migrate to Yarn 3. Only do so if you have specific reasons for it.
While Backstage projects created with `@backstage/create-app` use [Yarn 1](https://classic.yarnpkg.com/) by default, it
is possible to switch them to instead use [Yarn 3](https://yarnpkg.com/). Tools like `yarn backstage-cli versions:bump` will
still work, as they recognize both lockfile formats.