docs/releases/v1.37.0-changelog.md
Upgrade Helper: https://backstage.github.io/upgrade-helper/?to=1.37.0
@backstage/backend-common, please migrate to the new backend system.DefaultTechDocsCollatorFactory. Use the @backstage/plugin-search-backend-module-techdocs for this instead. Finally, deprecated DocsBuildStrategy and TechDocsDocument were removed, use the versions in @backstage/plugin-techdocs-node instead.12f8e01: BREAKING: The default DiscoveryApi implementation has been switched to use FrontendHostDiscovery, which adds support for the discovery.endpoints configuration.
This is marked as a breaking change because it will cause any existing discovery.endpoints configuration to be picked up and used, which may break existing setups.
For example, consider the following configuration:
app:
baseUrl: https://backstage.acme.org
backend:
baseUrl: https://backstage.internal.acme.org
discovery:
endpoints:
- target: https://catalog.internal.acme.org/api/{{pluginId}}
plugins: [catalog]
This will now cause requests from the frontend towards the catalog plugin to be routed to https://catalog.internal.acme.org/api/catalog, but this might not be reachable from the frontend. To fix this, you should update the discovery.endpoints configuration to only override the internal URL of the plugin:
discovery:
endpoints:
- target:
internal: https://catalog.internal.acme.org/api/{{pluginId}}
plugins: [catalog]
5b70679: BREAKING: ESLint warnings no longer trigger system exit codes like errors do.
Set the max number of warnings to -1 during linting to enable the gradual adoption of new ESLint rules. To restore the previous behavior, include the --max-warnings 0 flag in the backstage-cli <repo|package> lint command.
migrate and version:* commands into a new migrate module.esbuild from 0.24.2 to 0.25.0index entries in the typesVersions map, which could cause /index to be added when automatically adding imports.test commands to a separate module.lint to the new module system.info commands to a separate module.--scope option for the new command that could cause plugins to have backstage-backstage-plugin in their name.$file, $env, and $include. Any other key that begins with a `# @backstage/config-loader will now be passed through as is.@types/minimist to devDependenciesFetchApi will now also take configuration under discovery.endpoints into consideration when deciding whether to include credentials or not.discovery.endpoints configuration no longer requires both internal and external target when using the object form, instead falling back to the default.@backstage/ExtensionOverrides and @backstage/BackstagePlugin types.cbe6177: Improved route path normalization when converting existing route elements in converLegacyApp, for example handling trailing /* in paths.
d34e0e5: Added a new convertLegacyAppOptions helper that converts many of the options passed to createApp in the old frontend system to a module with app overrides for the new system. The supported options are apis, icons, plugins, components, and themes.
For example, given the following options for the old createApp:
import { createApp } from '@backstage/app-deafults';
const app = createApp({
apis,
plugins,
icons: {
custom: MyIcon,
},
components: {
SignInPage: MySignInPage,
},
themes: [myTheme],
});
They can be converted to the new system like this:
import { createApp } from '@backstage/frontend-deafults';
import { convertLegacyAppOptions } from '@backstage/core-compat-api';
const app = createApp({
features: [
convertLegacyAppOptions({
apis,
plugins,
icons: {
custom: MyIcon,
},
components: {
SignInPage: MySignInPage,
},
themes: [myTheme],
}),
],
});
e7fab55: Added the entityPage option to convertLegacyApp, which you can read more about in the app migration docs.
18faf65: The convertLegacyApp has received the following changes:
null routes will now be ignored.converted-orphan-routes plugin instead.app/root extension.compatWrapper.Updated dependencies
SimpleStepper back button now works with activeStep property set higher than 0fffe3c0: Added classNames prop to the Page component
df3b9f0: Fixed a bug in the SidebarSubmenuItem within the core-components package that caused the dropdown button to be misaligned in the sidebar and the button text to appear in uppercase due to the default <Button> behavior. Also added an example dropdown menu to the app for reference.
48aab13: Add i18n support for scaffolder-react plugin
0a0ced6: Avoid Layout Shift for DismissableBanner when using a storageApi with latency (e.g. user-settings-backend)
Properly handle the unknown state of the storageApi. There's a trade-off: this may lead to some Layout Shift if the banner has not been dismissed, but once it has been dismissed, you won't have any.
Updated dependencies
5.8.abcdf44: BREAKING: The returned object from createSpecializedApp no longer contains a createRoot() method, and it instead now contains apis and tree.
You can replace existing usage of app.createRoot() with the following:
const root = tree.root.instance?.getData(coreExtensionData.reactElement);
8250ffe: BREAKING: Dropped support for the removed opaque @backstage/ExtensionOverrides and @backstage/BackstagePlugin types.
extensionFactoryMiddleware to either createApp() or createSpecializedApp().createFrontendFeatureLoader() function, as well as a FrontendFeatureLoader interface, to gather several frontend plugins, modules or feature loaders in a single exported entrypoint and load them, possibly asynchronously. This new feature, very similar to the createBackendFeatureLoader() already available on the backend, supersedes the previous CreateAppFeatureLoader type which has been deprecated.createFrontendFeatureLoader() function, as well as a FrontendFeatureLoader interface, to gather several frontend plugins, modules or feature loaders in a single exported entrypoint and load them, possibly asynchronously. This new feature, very similar to the createBackendFeatureLoader() already available on the backend, supersedes the previous CreateAppFeatureLoader type which has been deprecated.@backstage/ExtensionOverrides and @backstage/BackstagePlugin types.extensionFactoryMiddleware to either createApp() or createSpecializedApp().createSpecializedApp.createApp is now exposed via the discoverAvailableFeatures and resolveAsyncFeatures functions respectively.createFrontendFeatureLoader() function, as well as a FrontendFeatureLoader interface, to gather several frontend plugins, modules or feature loaders in a single exported entrypoint and load them, possibly asynchronously. This new feature, very similar to the createBackendFeatureLoader() already available on the backend, supersedes the previous CreateAppFeatureLoader type which has been deprecated.ExtensionOverrides and FrontendFeature types.createExtensionDataRef where the ID is passed directly.DialogApi, which can be used to show dialogs in the React tree that can collect input from the user.ExtensionMiddlewareFactory type.createFrontendPlugin is now sorted alphabetically by ID in the TypeScript type.ExtensionBoundary.lazyComponent helper in addition to the existing ExtensionBoundary.lazy helper.setupRequestMockHandlers which was replaced by registerMswTestHooks.initialRouteEntries option to renderInTestApp.renderInTestApp helper now provides a default mock config with mock values for both app.baseUrl and backend.baseUrl.createSpecializedApp.32be48c: BREAKING: Removed support for the old backend system.
As part of this change the plugin export from /alpha as been removed. If you are currently importing @backstage/plugin-app-backend/alpha, please update your import to @backstage/plugin-app-backend.
247a40b: Now a custom entity page header can be passed as input to the default entity page.
a3d93ca: The default layout of the entity page can now optionally be customized with 3 card types: info, peek and full.
info are rendered in a fixed area on the right;peek are rendered on top of the main content area;full and cards with undefined type are rendered as they were before, in the main content area, below the peek cards.If you want to keep the layout as it was before, you don't need to do anything. But if you want to experiment with the card types and see how they render, here is an example setting the about card to be rendered as an info card:
app:
extensions:
# Entity page cards
+ - entity-card:catalog/about:
+ config:
+ type: info # or peek or full
93533bd: The order in which group tabs appear on the entity page has been changed.
Previously, entity contents determined the order in which groups were rendered, so a group was rendered as soon as its first entity content was detected.
Groups are now rendered first by default based on their order in the app-config.yaml file:
app:
extensions:
- page:catalog/entity:
+ config:
+ groups:
+ # this will be the first tab of the default entity page
+ - deployment:
+ title: Deployment
+ # this will be the second tab of the default entiy page
+ - documentation:
+ title: Documentation
If you wish to place a normal tab before a group, you must add the tab to a group and place the group in the order you wish it to appear on the entity page (groups that contains only one tab are rendered as normal tabs).
app:
extensions:
- page:catalog/entity:
config:
groups:
+ # Example placing the overview tab first
+ - overview:
+ title: Overview
- deployment:
title: Deployment
# this will be the second tab of the default entiy page
- documentation:
title: Documentation
- entity-content:catalog/overview:
+ config:
+ group: 'overview'
06d1226: Allow providing kind parameters to replace the default Component kind for SubComponents card
31731b0: Internal refactor to avoid expiry-map dependency.
ba9649a: Update the default entity page extension component to support grouping multiple entity content items in the same tab.
Disable all default groups:
# app-config.yaml
app:
extensions:
# Pages
+ - page:catalog/entity:
+ config:
+ groups: []
Create a custom list of :
# app-config.yaml
app:
extensions:
# Pages
+ - page:catalog/entity:
+ config:
+ groups:
+ # This array of groups completely replaces the default groups
+ - custom:
+ title: 'Custom'
Updated dependencies
@backstage/plugin-catalog-backend to prevent duplicate path keys in entity search if only casing is different.PermissionsRegistryService.catalog.useUrlReadersSearch config.refreshByRefreshKeys89db8b8: BREAKING The optional branch configuration parameter now defaults to the default branch of the project (where HEAD points to).
This parameter was previously using master as the default value. In most cases this change should be transparent as Gerrit defaults to using master.
This change also allow to specify a custom catalogPath in the catalog.providers.gerrit configuration.
If not set, it defaults to catalog-info.yaml files at the root of repositories. This default was the value before this change.
With the changes made in the GerritUrlReader, catalogPath allows to use minimatch's glob-patterns.
catalog:
providers:
gerrit:
all: # identifies your dataset / provider independent of config changes
host: gerrit.company.com
query: 'state=ACTIVE&type=CODE'
+ # This will search for catalog manifests anywhere in the repositories
+ catalogPath: '**/catalog-info.{yml,yaml}'
7f57365: Add support for a new entity predicate syntax when defining filters related to the blueprints exported via /alpha for the new frontend system. For more information, see the entity filters documentation.
ba9649a: Add a new defaultGroup parameter to the EntityContentBlueprint, here are usage examples:
Set a default group while creating the extension:
const entityKubernetesContent = EntityContentBlueprint.make({
name: 'kubernetes',
params: {
defaultPath: '/kubernetes',
defaultTitle: 'Kubernetes',
+ defaultGroup: 'deployment',
filter: 'kind:component,resource',
loader: () =>
import('./KubernetesContentPage').then(m =>
compatWrapper(<m.KubernetesContentPage />),
),
},
});
Disassociate an entity content from a default group:
# app-config.yaml
app:
extensions:
# Entity page content
- - entity-content:kubernetes/kubernetes
+ - entity-content:kubernetes/kubernetes:
+ config:
+ group: false
Associate an entity content with a different default or custom group than the one defined in code when the extension was created:
# app-config.yaml
app:
extensions:
# Entity page content
- - entity-content:kubernetes/kubernetes
+ - entity-content:kubernetes/kubernetes:
+ config:
+ group: custom # associating this extension with a custom group id, the group should have previously been created via entity page configuration
247a40b: Introduces a new EntityHeaderBlueprint that allows you to override the default entity page header.
import { EntityHeaderBlueprint } from '@backstage/plugin-catalog-react/alpha';
EntityHeaderBlueprint.make({
name: 'my-default-header',
params: {
loader: () =>
import('./MyDefaultHeader').then(m => <m.MyDefaultHeader />),
},
});
a3d93ca: Introduces a new EntityContentLayoutBlueprint that creates custom entity content layouts.
The layout components receive card elements and can render them as they see fit. Cards is an array of objects with the following properties:
JSx.Element;"peek" | "info" | "full" | undefined;Creating a custom overview tab layout:
import {
EntityContentLayoutProps,
EntityContentLayoutBlueprint,
} from '@backstage/plugin-catalog-react/alpha';
// ...
function StickyEntityContentOverviewLayout(props: EntityContentLayoutProps) {
const { cards } = props;
const classes = useStyles();
return (
<Grid container spacing={3}>
<Grid
className={classes.infoArea}
xs={12}
md={4}
item
>
<Grid container spacing={3}>
{cards
.filter(card => card.type === 'info')
.map((card, index) => (
<Grid key={index} xs={12} item>
{card.element}
</Grid>
))}
</Grid>
</Grid>
<Grid xs={12} md={8} item>
<Grid container spacing={3}>
{cards
.filter(card => card.type === 'peek')
.map((card, index) => (
<Grid key={index} className={classes.card} xs={12} md={6} item>
{card.element}
</Grid>
))}
{cards
.filter(card => !card.type || card.type === 'full')
.map((card, index) => (
<Grid key={index} className={classes.card} xs={12} md={6} item>
{card.element}
</Grid>
))}
</Grid>
</Grid>
</Grid>
);
}
export const customEntityContentOverviewStickyLayoutModule = createFrontendModule({
pluginId: 'app',
extensions: [
EntityContentLayoutBlueprint.make({
name: 'sticky',
params: {
// (optional) defaults the `() => false` filter function
defaultFilter: 'kind:template'
loader: async () => StickyEntityContentOverviewLayout,
},
}),
],
Disabling the custom layout:
# app-config.yaml
app:
extensions:
- entity-content-layout:app/sticky: false
Overriding the custom layout filter:
# app-config.yaml
app:
extensions:
- entity-content-layout:app/sticky:
config:
# This layout will be used only with component entities
filter: 'kind:component'
d78bb71: Added hidden prop to EntityTagPicker, EntityAutocompletePicker and UserListPicker.
Added initialFilter prop to EntityTagPicker to set an initial filter for the picker.
Added alwaysKeepFilters prop to UserListPicker to prevent filters from resetting when no entities match the initial filters.
a3d93ca: Add an optional type parameter to EntityCard extensions. A card's type determines characteristics such as its expected size and where it will be rendered by the entity content layout.
Initially the following three types are supported:
peek: small vertical cards that provide information at a glance, for example recent builds, deployments, and service health.info: medium size cards with high priority and frequently used information such as common actions, entity metadata, and links.full: Large cards that are more feature rich with more information, typically used by plugins that don't quite need the full content view and want to show a card instead.Defining a default type when creating a card:
const myCard = EntityCardBlueprint.make({
name: 'myCard',
params: {
+ type: 'info',
loader: import('./MyCard).then(m => { default: m.MyCard }),
},
});
Changing the card type via app-config.yaml file:
app:
extensions:
+ - entity-card:myPlugin/myCard:
+ config:
+ type: info
addHttpPostBodyParser to events extension to allow body parse customization. This feature will enhance flexibility in handling HTTP POST requests in event-related operations.ServerPermissionClient can no longer be instantiated with a tokenManager and must instead be instantiated with an auth service. If you are still on the legacy backend system, use createLegacyAuthAdapters() from @backstage/backend-common to create a compatible auth service.PermissionResourceRef to createPermissionRule.createPermissionIntegrationRouter and related types, which has been replaced by PermissionRegistryService. For more information, including how to migrate existing plugins, see the service docs.2d8b0e4: BREAKING: Removed support for the old backend system.
As part of this change the plugin export from /alpha as been removed. If you are currently importing @backstage/plugin-proxy-backend/alpha, please update your import to @backstage/plugin-proxy-backend.
ui:disabled for disabling the input field of all the pickers.page:scaffolder extension to accept formFields input, matching the updated FormFieldBlueprint.createTemplateAction type, and convert catalog:fetch action to new way of defining actions.esbuild from 0.24.2 to 0.25.0@backstage/backend-common usages1a58846: DEPRECATION: We've deprecated the old way of defining actions using createTemplateAction with raw JSONSchema and type parameters, as well as using zod through an import. You can now use the new format to define createTemplateActions with zod provided by the framework. This change also removes support for logStream in the context as well as moving the logger to an instance of LoggerService.
Before:
createTemplateAction<{ repoUrl: string }, { test: string }>({
id: 'test',
schema: {
input: {
type: 'object',
required: ['repoUrl'],
properties: {
repoUrl: { type: 'string' },
},
},
output: {
type: 'object',
required: ['test'],
properties: {
test: { type: 'string' },
},
},
},
handler: async ctx => {
ctx.logStream.write('blob');
},
});
// or
createTemplateAction({
id: 'test',
schema: {
input: z.object({
repoUrl: z.string(),
}),
output: z.object({
test: z.string(),
}),
},
handler: async ctx => {
ctx.logStream.write('something');
},
});
After:
createTemplateAction({
id: 'test',
schema: {
input: {
repoUrl: d => d.string(),
},
output: {
test: d => d.string(),
},
},
handler: async ctx => {
// you can just use ctx.logger.log('...'), or if you really need a log stream you can do this:
const logStream = new PassThrough();
logStream.on('data', chunk => {
ctx.logger.info(chunk.toString());
});
},
});
@backstage/backend-common usagescreateTemplateAction kinds@backstage/backend-common usagesprefix_length property.indexPrefix configuration through the app-config.yaml@backstage/backend-common, please migrate to the new backend system.@backstage/backend-common, please migrate to the new backend system.e202017: BREAKING: Removed support for the old backend system.
As part of this change the plugin export from /alpha as been removed. If you are currently importing @backstage/plugin-user-settings-backend/alpha, please update your import to @backstage/plugin-user-settings-backend.
e293b66: The default auditor service implementation will now log low severity events with debug level instead of info.
f422984: Remove unused dependencies
ecb9bab: Explicitly stringify extra logger fields with JSON.stringify to prevent [object Object] errors.
12f8e01: The discovery.endpoints configuration no longer requires both internal and external target when using the object form, instead falling back to the default.
89db8b8: GerritUrlReader is now able to search files matching a given pattern URL (using minimatch glob patterns).
This allows the Gerrit Discovery to find all Backstage manifests inside a repository using the **/catalog-info.yaml pattern.
Updated dependencies
@types/jest to devDependencies.BootErrorPage app component.getGitilesAuthenticationUrl. This enables its usage by the GerritUrlReader.@types/jest to devDependencies.DialogApi.7956beb: Marked the remaining exports related to createRouter and the old backend system as deprecated.
For more information about migrating to the new backend system, see the migration guide.
Support for the old backend system will be removed in the next release of this plugin.
b6702ea: Deprecated getDefaultOwnershipEntityRefs in favor of the new .resolveOwnershipEntityRefs(...) method in the AuthResolverContext.
The following code in a custom sign-in resolver:
import { getDefaultOwnershipEntityRefs } from '@backstage/plugin-auth-backend';
// ...
const ent = getDefaultOwnershipEntityRefs(entity);
Can be replaced with the following:
const { ownershipEntityRefs: ent } = await ctx.resolveOwnershipEntityRefs(
entity,
);
Updated dependencies
auth.microsoft.signIn.resolvers config def to include the userIdMatchingUserEntityAnnotation resolver.README.mdREADME.mdREADME.mdAuthResolverContext.resolveOwnershipEntityRefs as a way of accessing the default ownership resolution logic in sign-in resolvers, replacing getDefaultOwnershipEntityRefs from @backstage/plugin-auth-backend.config.d.ts for ldapOrg being incorrect. The documentation says a single
object or an array are accepted, but the definition only allows an object.catalog.providers.microsoftGraphOrg.target config def to be optional as this has a default value.addHttpPostBodyParser to events extension to allow body parse customization. This feature will enhance flexibility in handling HTTP POST requests in event-related operations.KUBERNETES_ANNOTATION and KUBERNETES_LABEL_SELECTOR_QUERY_ANNOTATION annotations from kubernetes-commonKUBERNETES_ANNOTATION and KUBERNETES_LABEL_SELECTOR_QUERY_ANNOTATION annotations from kubernetes-commonbackstage.io/kubernetes-id and backstage.io/kubernetes-label-selector annotations as constantsbitbucketCloud:branchRestriction:create to allow users to create bitbucket cloud branch restrictions in templatesjsonschema@backstage/backend-common usages@backstage/backend-common usages@backstage/backend-common usagesundefined to some parameters for createOrUpdateEnvironment as these values are not always supported in different plans of GitHub@backstage/backend-common@backstage/backend-common usages@backstage/backend-common usageslifecycle property to the spec field of Template entities.ScaffolderFormFieldsApi and formFieldsApiRef as these are being replaced with a different solution.flatted to 3.3.3.TechDocsAddonsBlueprint extension to allow adding of techdocs addons.TechDocsAddonsBlueprint extension to allow adding of techdocs addons.TechDocsAddonsBlueprint extension to allow adding of techdocs addons.