docs/releases/v1.6.0-changelog.md
validateEntity method that calls /validate-entity endpoint.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.1fe6823bb5: Updated dependency eslint-plugin-jest to ^27.0.0.
Note that this major update to the Jest plugin contains some breaking changes. This means that some of your tests may start seeing some new lint errors. Read about them here.
These are mostly possible to fix automatically. You can try to run yarn backstage-cli repo lint --fix in your repo root to have most or all of them
corrected.
8d886dd33e: The create-plugin and create commands have both been deprecated in favor of a new new command. The new command is functionally identical to create, but the new naming makes it possible to use as yarn script, since yarn create is reserved.
cc63eb8611: Sort entries in skeleton.tar.gz for better docker layer caching
548053614a: Deprecated the plugin:diff command. If you wish to keep running similar checks in your project we recommend using bespoke scripts. A useful utility for such scripts is @manypkg/get-packages, which helps you enumerate all packages in a monorepo.
513b4dd4ef: The versions:bump command will now update dependency ranges in package.json, even if the new version is within the current range.
221e951298: Added support for custom certificate for webpack dev server.
934cc34563: Avoid validating the backend configuration schema when loading static configuration for building the frontend.
3d4f5daadf: Remove use of deprecated trimLeft/trimRight
817f3196f6: Added a new migrate react-router-deps command to aid in the migration to React Router v6 stable.
742cb4f3d7: Fix issue when using .jsx files inside tests
e7600bdb04: Tweaked workspace packaging to not rewrite existing package.json files.
6ae0f6a719: Switch out sucrase for swc for transpilation.
sucrase is a little more relaxed when it comes to supporting the ways of mocking in jest. You might have to make some changes to your tests to meet the jest standard and spec if your tests seems to start failing.
Mocks that look like this are invalid, and they will throw a reference error in line with the jest documentation here on example 3
const mockCommandExists = jest.fn();
jest.mock('command-exists', () => mockCommandExists);
You might need to update these mocks to look a little like the following to defer the call to the jest.fn() spy until the mock is called.
const mockCommandExists = jest.fn();
jest.mock(
'command-exists',
() =>
(...args: any[]) =>
commandExists(...args),
);
Also, imports are immutable. So it means that you might get some errors when trying to use jest.spyOn with starred imports. You might see an error like this:
TypeError: Cannot redefine property: executeFrameHandlerStrategy
at Function.defineProperty (<anonymous>)
20 | import { AuthResolverContext } from '../types';
21 |
> 22 | const mockFrameHandler = jest.spyOn(
| ^
23 | helpers,
24 | 'executeFrameHandlerStrategy',
25 | ) as unknown as jest.MockedFunction<
This happens when you try to do import * as something from './something' and then jest.spyOn(something, 'test). You will need to add a jest.mock call to mock out the required starred import to return jest.fn() functions from the start. Something like this fixes the above test:
jest.mock('../../helpers', () => ({
executeFrameHandlerStrategy: jest.fn(),
}));
You can also remove any occurrence of hot(App) and any import of react-hot-loader if you're using the that package locally, as all this has now been replaced with React Refresh which you will get out of the box with the new CLI.
Note If you're experiencing difficulties with running tests after the migration, please reach out to us on Discord to see if we can help, or raise an issue. But in the meantime you can switch back to the existing behaviour by using the following config in your root package.json.
"jest": {
"transform": {
"\\.(js|jsx|ts|tsx|mjs|cjs)$": "@backstage/cli/config/jestSucraseTransform.js",
"\\.(bmp|gif|jpg|jpeg|png|frag|xml|svg|eot|woff|woff2|ttf)$": "@backstage/cli/config/jestFileTransform.js",
"\\.(yaml)$": "jest-transform-yaml"
}
}
1cb078ad9f: Fixed a misconfiguration where all modules where treated as ESM by the React Refresh plugin for Webpack.
1fd4f2746f: Removed internal dependencies on Lerna. It is now no longer necessary to have Lerna installed in a project to use all features of the Backstage CLI.
667d917488: Updated dependency msw to ^0.47.0.
87ec2ba4d6: Updated dependency msw to ^0.46.0.
bf5e9030eb: Updated dependency msw to ^0.45.0.
33fbd9f9a4: Updated dependency @types/minimatch to ^5.0.0.
68c2697077: Added a new backstage-cli repo clean command that cleans the repo root and runs the clean script in all packages.
7d47def9c4: Added dependency on @types/jest v27. The @types/jest dependency has also been removed from the plugin template and should be removed from any of your own internal packages. If you wish to override the version of @types/jest or jest, use Yarn resolutions.
a7e82c9b01: Updated versions:bump command to be compatible with Yarn 3.
Updated dependencies
817f3196f6: Updated React Router dependencies to be peer dependencies.
f9ec4e46e3: When using React Router v6 stable, it is now possible for components within the Route element tree to have path props, although they will be ignored.
7d47def9c4: Removed dependency on @types/jest.
744fea158b: Added getSystemIcons() function to the AppContext available through useApp that will pull a list of all the icons that have been registered in the App.
667d917488: Updated dependency msw to ^0.47.0.
87ec2ba4d6: Updated dependency msw to ^0.46.0.
bf5e9030eb: Updated dependency msw to ^0.45.0.
8448b53dd6: Clarify that the WebStorage observable returns JsonValue items.
70299c99d5: Updated FlatRoutes to be compatible with React Router v6 stable.
e9d40ebf54: If you'd like to send analytics events to multiple implementations, you may now
do so using the MultipleAnalyticsApi implementation provided by this package.
import { MultipleAnalyticsApi } from '@backstage/core-app-api';
import {
analyticsApiRef,
configApiRef,
storageApiRef,
identityApiRef,
} from '@internal/backstage/core-plugin-api';
import { CustomAnalyticsApi } from '@internal/analytics';
import { VendorAnalyticsApi } from '@vendor/analytics';
createApiFactory({
api: analyticsApiRef,
deps: { configApi: configApiRef, identityApi: identityApiRef, storageApi: storageApiRef },
factory: ({ configApi, identityApi, storageApi }) =>
MultipleAnalyticsApi.fromApis([
VendorAnalyticsApi.fromConfig(configApi, { identityApi }),
CustomAnalyticsApi.fromConfig(configApi, { identityApi, storageApi }),
]),
}),
Updated dependencies
Routes and Route element, as this is not compatible with React Router v6 stable.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.2fc41ebf07: Removed the previously deprecated class AtlassianAuthProvider. Please use providers.atlassian.create(...) instead.
a291688bc5: Renamed the RedirectInfo type to OAuthStartResponse
8600855fbf: The auth0 integration is updated to use the passport-auth0 library. The configuration under auth.providers.auth0.\* now supports an optional audience parameter; providing that allows you to connect to the correct API to get permissions, access tokens, and full profile information.
msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.6c1c59b96e: Added README card EntityAzureReadmeCard for Azure Devops.
To get the README component working you'll need to do the following two steps:
First we need to add the @backstage/plugin-azure-devops package to your frontend app:
yarn add --cwd packages/app @backstage/plugin-azure-devops
Second we need to add the EntityAzureReadmeCard extension to the entity page in your app:
// In packages/app/src/components/catalog/EntityPage.tsx
import {
EntityAzureReadmeCard,
isAzureDevOpsAvailable,
} from '@backstage/plugin-azure-devops';
// As it is a card, you can customize it the way you prefer
// For example in the Service section
const overviewContent = (
<Grid container spacing={3} alignItems="stretch">
<EntitySwitch>
<EntitySwitch.Case if={isAzureDevOpsAvailable}>
<Grid item md={6}>
...
</Grid>
<Grid item md={6}>
<EntityAzureReadmeCard maxHeight={350} />
</Grid>
</EntitySwitch.Case>
</EntitySwitch>
</Grid>
);
Notes:
EntitySwitch.Case above from step 2 to all the entity sections you want to see Readme in. For example if you wanted to see Readme when looking at Website entities then you would need to add this to the websiteEntityPage section.if prop is optional on the EntitySwitch.Case, you can remove it if you always want to see the tab even if the entity being viewed does not have the needed annotationmaxHeight property on the EntityAzureReadmeCard will set the maximum screen size you would like to see, if not set it will default to 100%@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.6c1c59b96e: Added README card EntityAzureReadmeCard for Azure Devops.
To get the README component working you'll need to do the following two steps:
First we need to add the @backstage/plugin-azure-devops package to your frontend app:
yarn add --cwd packages/app @backstage/plugin-azure-devops
Second we need to add the EntityAzureReadmeCard extension to the entity page in your app:
// In packages/app/src/components/catalog/EntityPage.tsx
import {
EntityAzureReadmeCard,
isAzureDevOpsAvailable,
} from '@backstage/plugin-azure-devops';
// As it is a card, you can customize it the way you prefer
// For example in the Service section
const overviewContent = (
<Grid container spacing={3} alignItems="stretch">
<EntitySwitch>
<EntitySwitch.Case if={isAzureDevOpsAvailable}>
<Grid item md={6}>
...
</Grid>
<Grid item md={6}>
<EntityAzureReadmeCard maxHeight={350} />
</Grid>
</EntitySwitch.Case>
</EntitySwitch>
</Grid>
);
Notes:
EntitySwitch.Case above from step 2 to all the entity sections you want to see Readme in. For example if you wanted to see Readme when looking at Website entities then you would need to add this to the websiteEntityPage section.if prop is optional on the EntitySwitch.Case, you can remove it if you always want to see the tab even if the entity being viewed does not have the needed annotationmaxHeight property on the EntityAzureReadmeCard will set the maximum screen size you would like to see, if not set it will default to 100%refresh function to the Connection of the entity providers.git-url-parse version to ^13.0.0hasAnnotation permission rulemsw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.CatalogProcessingExtensionPoint now accepts multiple providers and processors at once.EntityProviderConnection to be able to schedule refreshes from entity providers.catalogServiceRef for obtaining a CatalogClient in the new backend system.CatalogProcessingExtensionPoint now accepts multiple providers and processors at once.e44c0b3811: New features:
@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.README.md for more details!README.md for more details!README.md for more details!async validation for the next version of the plugincreate/nextgit-url-parse version to ^13.0.0EntityPickerallowedOwners@types/jest.EntityTagPicker field. Add the showCounts option to enable this. Also support configuring helperText.msw to ^0.47.0.msw to ^0.46.0.json-schema-library to ^7.0.0.msw to ^0.45.0.ea2eee9e6a: Add the option for a homepage when using the github:publish action
8872cc735d: Fixed a bug in plugin-scaffolder-backend where it ignores the skip migration database options.
To use this new implementation you need to create the instance of DatabaseTaskStore using the PluginDatabaseManager instead of Knex;
import { DatabaseManager, getRootLogger, loadBackendConfig } from '@backstage/backend-common';
import { DatabaseTaskStore } from '@backstage/plugin-scaffolder-backend';
const config = await loadBackendConfig({ argv: process.argv, logger: getRootLogger() });
const databaseManager = DatabaseManager.fromConfig(config, { migrations: { skip: true } });
const databaseTaskStore = await DatabaseTaskStore.create(databaseManager);
7db9613671: Added projectId for gitlab projects to be displayed in the gitlab:publish output
d1f7ba58e3: Added repositoryId output when create a repository in Azure
1ff817b3f0: add entity metadata to the template info type
git-url-parse version to ^13.0.0msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.publish:file action, use the template editor to test templates instead.ctx.isDryRun when running actions in dry run mode. Also always log action inputs for debugging purposes when running in dry run mode.scaffolderPlugin to be used with experimental backend system.IdentityApi change to use getIdentity instead of authenticate for retrieving the logged in users identity.8872cc735d: Fixed a bug in search-backend-module-pg where it ignores the skip migration database options when using the database.
To use this new implementation you need to create the instance of DatabaseDocumentStore using the PluginDatabaseManager instead of Knex;
import { DatabaseManager, getRootLogger, loadBackendConfig } from '@backstage/backend-common';
import { DatabaseDocumentStore } from '@backstage/plugin-search-backend-module-pg';
const config = await loadBackendConfig({ argv: process.argv, logger: getRootLogger() });
const databaseManager = DatabaseManager.fromConfig(config, { migrations: { skip: true } });
const databaseDocumentStore = await DatabaseDocumentStore.create(databaseManager);
97f2b8f3fd: The <SearchResult/> component now accepts a optional query prop to request results from the search api:
Note: If a query prop is not defined, the results will by default be consumed from the context.
Example:
import React, { useState, useCallback } from 'react';
import { Grid, List, Paper } from '@material-ui/core';
import { Page, Header, Content, Lifecycle } from '@backstage/core-components';
import {
DefaultResultListItem,
SearchBarBase,
SearchResult,
} from '@backstage/plugin-search-react';
const SearchPage = () => {
const [query, setQuery] = useState({
term: '',
types: [],
filters: {},
});
const handleChange = useCallback(
(term: string) => {
setQuery(prevQuery => ({ ...prevQuery, term }));
},
[setQuery],
);
return (
<Page themeId="home">
<Header title="Search" subtitle={<Lifecycle alpha />} />
<Content>
<Grid container direction="row">
<Grid item xs={12}>
<Paper>
<SearchBarBase debounceTime={100} onChange={handleChange} />
</Paper>
</Grid>
<Grid item xs>
<SearchResult query={query}>
{({ results }) => (
<List>
{results.map(({ document }) => (
<DefaultResultListItem
key={document.location}
result={document}
/>
))}
</List>
)}
</SearchResult>
</Grid>
</Grid>
</Content>
</Page>
);
};
Additionally, a search page can also be composed using these two new results layout components:
// Example rendering results as list
<SearchResult>
{({ results }) => (
<SearchResultListLayout
resultItems={results}
renderResultItem={({ type, document }) => {
switch (type) {
case 'custom-result-item':
return (
<CustomResultListItem
key={document.location}
result={document}
/>
);
default:
return (
<DefaultResultListItem
key={document.location}
result={document}
/>
);
}
}}
/>
)}
</SearchResult>
// Example rendering results as groups
<SearchResult>
{({ results }) => (
<>
<SearchResultGroupLayout
icon={<CustomIcon />}
title="Custom"
link="See all custom results"
resultItems={results.filter(
({ type }) => type === 'custom-result-item',
)}
renderResultItem={({ document }) => (
<CustomResultListItem key={document.location} result={document} />
)}
/>
<SearchResultGroupLayout
icon={<DefaultIcon />}
title="Default"
resultItems={results.filter(
({ type }) => type !== 'custom-result-item',
)}
renderResultItem={({ document }) => (
<DefaultResultListItem key={document.location} result={document} />
)}
/>
</>
)}
</SearchResult>
A SearchResultList and SearchResultGroup components were also created for users who have search pages with multiple queries, both are specializations of SearchResult and also accept a query as a prop as well:
// Example using the <SearchResultList />
const SearchPage = () => {
const query = {
term: 'example',
};
return (
<SearchResultList
query={query}
renderResultItem={({ type, document, highlight, rank }) => {
switch (type) {
case 'custom':
return (
<CustomResultListItem
key={document.location}
icon={<CatalogIcon />}
result={document}
highlight={highlight}
rank={rank}
/>
);
default:
return (
<DefaultResultListItem
key={document.location}
result={document}
/>
);
}
}}
/>
);
};
// Example using the <SearchResultGroup /> for creating a component that search and group software catalog results
import React, { useState, useCallback } from 'react';
import { MenuItem } from '@material-ui/core';
import { JsonValue } from '@backstage/types';
import { CatalogIcon } from '@backstage/core-components';
import { CatalogSearchResultListItem } from '@backstage/plugin-catalog';
import {
SearchResultGroup,
SearchResultGroupTextFilterField,
SearchResultGroupSelectFilterField,
} from @backstage/plugin-search-react;
import { SearchQuery } from '@backstage/plugin-search-common';
const CatalogResultsGroup = () => {
const [query, setQuery] = useState<Partial<SearchQuery>>({
types: ['software-catalog'],
});
const filterOptions = [
{
label: 'Lifecycle',
value: 'lifecycle',
},
{
label: 'Owner',
value: 'owner',
},
];
const handleFilterAdd = useCallback(
(key: string) => () => {
setQuery(prevQuery => {
const { filters: prevFilters, ...rest } = prevQuery;
const newFilters = { ...prevFilters, [key]: undefined };
return { ...rest, filters: newFilters };
});
},
[],
);
const handleFilterChange = useCallback(
(key: string) => (value: JsonValue) => {
setQuery(prevQuery => {
const { filters: prevFilters, ...rest } = prevQuery;
const newFilters = { ...prevFilters, [key]: value };
return { ...rest, filters: newFilters };
});
},
[],
);
const handleFilterDelete = useCallback(
(key: string) => () => {
setQuery(prevQuery => {
const { filters: prevFilters, ...rest } = prevQuery;
const newFilters = { ...prevFilters };
delete newFilters[key];
return { ...rest, filters: newFilters };
});
},
[],
);
return (
<SearchResultGroup
query={query}
icon={<CatalogIcon />}
title="Software Catalog"
link="See all software catalog results"
filterOptions={filterOptions}
renderFilterOption={({ label, value }) => (
<MenuItem key={value} onClick={handleFilterAdd(value)}>
{label}
</MenuItem>
)}
renderFilterField={(key: string) => {
switch (key) {
case 'lifecycle':
return (
<SearchResultGroupSelectFilterField
key={key}
label="Lifecycle"
value={query.filters?.lifecycle}
onChange={handleFilterChange('lifecycle')}
onDelete={handleFilterDelete('lifecycle')}
>
<MenuItem value="production">Production</MenuItem>
<MenuItem value="experimental">Experimental</MenuItem>
</SearchResultGroupSelectFilterField>
);
case 'owner':
return (
<SearchResultGroupTextFilterField
key={key}
label="Owner"
value={query.filters?.owner}
onChange={handleFilterChange('owner')}
onDelete={handleFilterDelete('owner')}
/>
);
default:
return null;
}
}
renderResultItem={({ document, highlight, rank }) => (
<CatalogSearchResultListItem
key={document.location}
result={document}
highlight={highlight}
rank={rank}
/>
)}
/>
);
};
18f60427f2: Provides search autocomplete functionality through a SearchAutocomplete component.
A SearchAutocompleteDefaultOption can also be used to render options with icons, primary texts, and secondary texts.
Example:
import React, { ChangeEvent, useState, useCallback } from 'react';
import useAsync from 'react-use/lib/useAsync';
import { Grid, Paper } from '@material-ui/core';
import { Page, Content } from '@backstage/core-components';
import { SearchAutocomplete, SearchAutocompleteDefaultOption} from '@backstage/plugin-search-react';
const OptionsIcon = () => <svg />
const SearchPage = () => {
const [inputValue, setInputValue] = useState('');
const options = useAsync(async () => {
// Gets and returns autocomplete options
}, [inputValue])
const useCallback((_event: ChangeEvent<{}>, newInputValue: string) => {
setInputValue(newInputValue);
}, [setInputValue])
return (
<Page themeId="home">
<Content>
<Grid container direction="row">
<Grid item xs={12}>
<Paper>
<SearchAutocomplete
options={options}
inputValue={inputValue}
inputDebounceTime={100}
onInputChange={handleInputChange}
getOptionLabel={option => option.title}
renderOption={option => (
<SearchAutocompleteDefaultOption
icon={<OptionIcon />}
primaryText={option.title}
secondaryText={option.text}
/>
)}
/>
</Paper>
</Grid>
</Grid>
{'/* Filters and results are omitted */'}
</Content>
</Page>
);
};
ca8d5a6eae: We noticed a repeated check for the existence of a parent context before creating a child search context in more the one component such as Search Modal and Search Bar and to remove code duplication we extract the conditional to the context provider, now you can use it passing an inheritParentContextIfAvailable prop to the SearchContextProvider.
Note: This added property does not create a local context if there is a parent context and in this case, you cannot use it together with initialState, it will result in a type error because the parent context is already initialized.
f7e99ac1d8: Added the possibility to display check results of different types on a single scorecard.
getScorecardsDefinition method from the TechInsightsApi interface. Added the getCheckResultRenderers method that returns rendering components for given types.CheckResultRenderer type now exposes the component factory method that creates a React component used to display a result of a provided check result.TechInsightsClient constructor accepts now the optional renderers parameter that can be used to inject a custom renderer.title parameter in the EntityTechInsightsScorecardContent and EntityTechInsightsScorecardCard components is now mandatory.jsonRulesEngineCheckResultRenderer used to render json-rules-engine check results is exported.BooleanCheck component that can be used to render other check results types is also exported.If you were overriding the getScorecardsDefinition method to adjust the rendering of check results, you should now provide a custom renderer using renderers parameter in the TechInsightsClient class.
See the README for more details.
@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.projectId config option to GCP Cloud Storage techdocs publisher. This will allow users to override the project ID, instead of implicitly using the same one as found in a credentials bundle.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.projectId config option to GCP Cloud Storage techdocs publisher. This will allow users to override the project ID, instead of implicitly using the same one as found in a credentials bundle.git-url-parse version to ^13.0.0@backstage/plugin-user-settings-backend to store user related
settings in the database.@types/jest.ApiRef.defaultFactory internal.ServiceFactory formats.ServiceRegistry to not initialize factories more than once.ServiceFactory.399286d7dd: Workaround support for swc instead of sucrase
eadf56bbbf: Bump git-url-parse version to ^13.0.0
c3c90280be: Added a keep-alive refresh loop to the DatabaseManager, keeping the connection
pool up.
c3c90280be: The options part of DatabaseManager.fromConfig now accepts an optional logger
field.
3d4f5daadf: Remove use of deprecated trimLeft/trimRight
bf3cc134eb: Implemented KubernetesContainerRunner: a ContainerRunner implementation that leverages Jobs on a kubernetes cluster
const kubeConfig = new KubeConfig();
kubeConfig.loadFromDefault();
const options: KubernetesContainerRunnerOptions = {
kubeConfig,
// namespace where Jobs will be created
namespace: 'default',
// Jobs name will be prefixed with this name
name: 'my-runner',
// An existing Kubernetes volume that will be used
// as base for mounts
mountBase: {
volumeName: 'workdir',
// Every mount must start with the base path
// see example below
basePath: '/workdir',
},
// Define a Pod template for the Jobs. It has to include
// a volume definition named as the mountBase volumeName
podTemplate: {
spec: {
containers: [],
volumes: [
{
name: 'workdir',
persistentVolumeClaim: {
claimName: 'workdir-claim',
},
},
],
},
},
};
const containerRunner = new KubernetesContainerRunner(options);
const runOptions: RunContainerOptions = {
imageName: 'golang:1.17',
args: ['echo', 'hello world'],
mountDirs: {
'/workdir/app': '/app',
},
};
containerRunner.runContainer(runOptions);
e3b1993788: Added port ranges in allowed hosts:
reading:
allow:
- host: *.examples.org:900-1000
2f52e74b49: Got rid of usages of the uppercase String type
60b85d8ade: Updated dependency helmet to ^6.0.0.
Please note that these policies are no longer applied by default:
helmet.contentSecurityPolicy no longer sets block-all-mixed-content directive by default helmet.expectCt is no longer set by default. It can, however, be explicitly enabled. It will be removed in Helmet 7.
667d917488: Updated dependency msw to ^0.47.0.
87ec2ba4d6: Updated dependency msw to ^0.46.0.
bf5e9030eb: Updated dependency msw to ^0.45.0.
709f468330: The branch command has been added to the isomorphic-git wrapper.
0c780278e0: Fix for entries being skipped or incomplete when reading large zip archives.
96689fbdcb: Workaround for a rare race condition in tests.
Updated dependencies
ServiceFactory formats.ServiceFactory.ApiRef.defaultFactory internal.createBackendPlugin and createBackendModule to properly forward lack of options.'plugin' or 'root' scope. Service factories have been updated to provide dependency instances directly rather than factory functions.ServiceFactory type and removed AnyServiceFactory.createServiceFactory method has been updated to return a higher-order factory that can accept options.ServiceRef you can now also include a defaultFactory, which will be used to construct instances of the service in case there is no explicit factory defined.ServiceFactory formats.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.ServiceFactory.@types/jest.@types/jest.@types/jest.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.HeaderActionMenu and expose default Table icons via Table.icons@types/jest.RoutedTabs component has been updated to be compatible with React Router v6 stable.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.getSystemIcons() function to the AppContext available through useApp that will pull a list of all the icons that have been registered in the App.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.6ff94d60d5: Removed usage of the deprecated diff command in the root package.json.
To make this change in an existing app, make the following change in the root package.json:
- "diff": "lerna run diff --",
c1f1a4c760: The Backstage packages and plugins have all been updated to support React Router v6 stable. The create-app template has not been migrated yet, but if you want to migrate your own app or plugins, check out the migration guide.
e83de28e36: Fix typo in the documentation
7d47def9c4: Removed dependency on @types/jest.
208d6780c9: The packages/backend/Dockerfile received a couple of updates, it now looks as follows:
FROM node:16-bullseye-slim
# Install sqlite3 dependencies. You can skip this if you don't use sqlite3 in the image,
# in which case you should also move better-sqlite3 to "devDependencies" in package.json.
RUN apt-get update && \
apt-get install -y --no-install-recommends libsqlite3-dev python3 build-essential && \
rm -rf /var/lib/apt/lists/* && \
yarn config set python /usr/bin/python3
# From here on we use the least-privileged `node` user to run the backend.
USER node
WORKDIR /app
# This switches many Node.js dependencies to production mode.
ENV NODE_ENV production
# Copy repo skeleton first, to avoid unnecessary docker cache invalidation.
# The skeleton contains the package.json of each package in the monorepo,
# and along with yarn.lock and the root package.json, that's enough to run yarn install.
COPY --chown=node:node yarn.lock package.json packages/backend/dist/skeleton.tar.gz ./
RUN tar xzf skeleton.tar.gz && rm skeleton.tar.gz
RUN yarn install --frozen-lockfile --production --network-timeout 300000 && rm -rf "$(yarn cache dir)"
# Then copy the rest of the backend bundle, along with any other files we might want.
COPY --chown=node:node packages/backend/dist/bundle.tar.gz app-config*.yaml ./
RUN tar xzf bundle.tar.gz && rm bundle.tar.gz
CMD ["node", "packages/backend", "--config", "app-config.yaml", "--config", "app-config.production.yaml"]
The two notable changes are that a USER node instruction has been added and the ordering of instructions has been changed accordingly. This means that the app will now be running using the least-privileged node user. In order for this to work we now need to make sure that all app files are owned by the node user, which we do by adding the --chown=node:node option to the COPY instructions.
The second change is the addition of ENV NODE_ENV production, which ensured that all Node.js modules run in production mode. If you apply this change to an existing app, note that one of the more significant changes is that this switches the log formatting to use the default production format, JSON. Rather than your log lines looking like this:
2022-08-10T11:36:05.478Z catalog info Performing database migration type=plugin
They will now look like this:
{"level":"info","message":"Performing database migration","plugin":"catalog","service":"backstage","type":"plugin"}
If you wish to keep the existing format, you can override this change by applying the following change to packages/backend/src/index.ts:
getRootLogger,
+ setRootLogger,
+ createRootLogger,
+ coloredFormat,
useHotMemoize,
...
ServerTokenManager,
} from '@backstage/backend-common';
...
async function main() {
+ setRootLogger(createRootLogger({ format: coloredFormat }));
+
const config = await loadBackendConfig({
49416194e8: Adds IdentityApi configuration to create-app scaffolding templates.
To migrate to the new IdentityApi, edit the packages/backend/src/index.ts adding the following import:
import { DefaultIdentityClient } from '@backstage/plugin-auth-node';
Use the factory function to create an IdentityApi in the makeCreateEnv function and return it from the
function as follows:
function makeCreateEnv(config: Config) {
...
const identity = DefaultIdentityClient.create({
discovery,
});
...
return {
...,
identity
}
}
Backend plugins can be upgraded to work with this new IdentityApi.
Add identity to the RouterOptions type.
export interface RouterOptions {
...
identity: IdentityApi;
}
Then you can use the IdentityApi from the plugin.
export async function createRouter(
options: RouterOptions,
): Promise<express.Router> {
const { identity } = options;
router.get('/user', async (req, res) => {
const user = await identity.getIdentity({ request: req });
...
8d886dd33e: Added yarn new as one of the scripts installed by default, which calls backstage-cli new. This script replaces create-plugin, which you can now remove if you want to. It is kept in the create-app template for backwards compatibility.
The remove-plugin command has been removed, as it has been removed from the Backstage CLI.
To apply these changes to an existing app, make the following change to the root package.json:
- "remove-plugin": "backstage-cli remove-plugin"
+ "new": "backstage-cli new --scope internal"
c3c90280be: The options part of DatabaseManager.fromConfig now accepts an optional logger
field. You may want to supply that logger in your backend initialization code to
ensure that you can get relevant logging data when things happen related to the
connection pool.
In packages/backend/src/index.ts:
function makeCreateEnv(config: Config) {
const root = getRootLogger();
...
- const databaseManager = DatabaseManager.fromConfig(config);
+ const databaseManager = DatabaseManager.fromConfig(config, { logger: root });
a578558180: Updated the root package.json to use the new backstage-cli repo clean command.
To apply this change to an existing project, make the following change to the root package.json:
- "clean": "backstage-cli clean && lerna run clean",
+ "clean": "backstage-cli repo clean",
c0a08fd08c: Added EntityLinksCard to the system EntityPage.
For an existing installation where you want to display the links card for entity pages of kind system you should make the following adjustment to packages/app/src/components/catalog/EntityPage.tsx
const systemPage = (
...
<Grid item md={6} xs={12}>
<EntityCatalogGraphCard variant="gridItem" height={400} />
</Grid>
+ <Grid item md={4} xs={12}>
+ <EntityLinksCard />
+ </Grid>
- <Grid item md={6}>
+ <Grid item md={8}>
<EntityHasComponentsCard variant="gridItem" />
</Grid>
...
);
Updated dependencies
@types/jest.react-hot-loader, since the @backstage/cli now uses swc with React Refresh instead.@types/jest.git-url-parse version to ^13.0.0@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.bitbucketServer integration where token did not take precedence over supplied username and password which is described in the documentation.allowedInstallationOwners to your apps configuration to gain the most benefit from these performance changes.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.git-url-parse version to ^13.0.0@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.d669d89206: Minor API signatures cleanup
60b85d8ade: Updated dependency helmet to ^6.0.0.
Please note that these policies are no longer applied by default:
helmet.contentSecurityPolicy no longer sets block-all-mixed-content directive by default helmet.expectCt is no longer set by default. It can, however, be explicitly enabled. It will be removed in Helmet 7.
667d917488: Updated dependency msw to ^0.47.0.
87ec2ba4d6: Updated dependency msw to ^0.46.0.
bf5e9030eb: Updated dependency msw to ^0.45.0.
8872cc735d: Fixed a bug where the database option to skip migrations was ignored.
Updated dependencies
IdentityClient is now deprecated. Please migrate to IdentityApi and DefaultIdentityClient instead. The authenticate function on DefaultIdentityClient is also deprecated. Please use getIdentity instead.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.3f739be9d9: Minor API signatures cleanup
667d917488: Updated dependency msw to ^0.47.0.
87ec2ba4d6: Updated dependency msw to ^0.46.0.
bf5e9030eb: Updated dependency msw to ^0.45.0.
cb1cfc018b: createRouter now requires an additional reader: UrlReader argument
export default async function createPlugin(
env: PluginEnvironment,
): Promise<Router> {
return createRouter({
logger: env.logger,
config: env.config,
+ reader: env.reader,
});
}
Remember to check if you have already provided these settings previously.
# app-config.yaml
azureDevOps:
host: dev.azure.com
token: my-token
organization: my-company
# app-config.yaml
integrations:
azure:
- host: dev.azure.com
token: ${AZURE_TOKEN}
ef9ab322de: Minor API signatures cleanup
Updated dependencies
@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.Router from the RoutedTabs children.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.GitHubEntityProvider to use against GitHub EnterprisescheduleFn initialization in GitHubEntityProvider.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.searchStream method in LDAP client awaits the callbacksMicrosoftGraphEntityProvider that ignored the userExpand and groupExpand configuration parametersqueryMode from the microsoftGraphOrg configmsw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.git-url-parse version to ^13.0.0@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.EntityTagPicker. You can enable this by adding the showCounts property@types/jest.'@backstage plugin-cicd-statistics-module-gitlab'; -> '@backstage/plugin-cicd-statistics-module-gitlab';@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.CostInsightsHeadercomponent now uses group names if availablemsw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.react-query:3 to @tanstack/react-query:4@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.pullRequestLimit prop to EntityTeamPullRequestsCard and EntityTeamPullRequestsContent to limit the number of PRs shown per repository. Excluding this prop will default the number of pull requests shown to 10 per repository (the existing functionality).@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.d669d89206: Minor API signatures cleanup
60b85d8ade: Updated dependency helmet to ^6.0.0.
Please note that these policies are no longer applied by default:
helmet.contentSecurityPolicy no longer sets block-all-mixed-content directive by default helmet.expectCt is no longer set by default. It can, however, be explicitly enabled. It will be removed in Helmet 7.
667d917488: Updated dependency msw to ^0.47.0.
87ec2ba4d6: Updated dependency msw to ^0.46.0.
bf5e9030eb: Updated dependency msw to ^0.45.0.
Updated dependencies
@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.msw to ^0.47.0.msw to ^0.46.0.jenkins to ^1.0.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.8902c2e39d: chore: Exporting KubernetesClientProvider and everything in kubernetes-auth-translator as requested in issue #10457
a57d29d572: Adds skipMetricsLookup to the kubernetes-backend schema
0768d6dece: add new kubernetes backend endpoints to kubernetes backend client
60b85d8ade: Updated dependency helmet to ^6.0.0.
Please note that these policies are no longer applied by default:
helmet.contentSecurityPolicy no longer sets block-all-mixed-content directive by default helmet.expectCt is no longer set by default. It can, however, be explicitly enabled. It will be removed in Helmet 7.
Updated dependencies
@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.UserProfileCard that is enabled when the backstage.io/edit-url is present, this matches how the GroupProfileCard worksmsw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.IdentityApi change to use getIdentity instead of authenticate for retrieving the logged in users identity.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.817f3196f6: Updated React Router dependencies to be peer dependencies.
7d47def9c4: Removed dependency on @types/jest.
817f3196f6: DEPRECATION: The PermissionedRoute component has been deprecated in favor of the new RequirePermission component. This is because the usage pattern of PermissionedRoute is not compatible with React Router v6 stable.
Embed the type from react-router instead of exporting it directly.
Updated dependencies
msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.@types/jest.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.inheritParentContextIfAvailable search context property in SearchModal instead of manually checking if a parent context exists, this conditional statement was previously duplicated in more than one component like in SearchBar as well and is now only done in SearchContextProvider.aws-os-connection to ^0.2.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.maxPage option on the collator.techdocsAnnotationFactName fact.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.git-url-parse version to ^13.0.0@types/jest.TechDocsReaderPage to be compatible with React Router v6 stable.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.SearchAutocomplete component in the TechDocsSearch component to maintain consistency across search experiences and avoid code duplication.TechDocs reader page.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.git-url-parse version to ^13.0.0@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.UserSettingsStorage implementation of the StorageApi for use as
drop-in replacement for the WebStorage, in conjunction with the newly created
@backstage/plugin-user-settings-backend.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.3f739be9d9: Minor API signatures cleanup
148568b5c2: Switched to using node-fetch instead of cross-fetch as is standard for our backend packages
60b85d8ade: Updated dependency helmet to ^6.0.0.
Please note that these policies are no longer applied by default:
helmet.contentSecurityPolicy no longer sets block-all-mixed-content directive by default helmet.expectCt is no longer set by default. It can, however, be explicitly enabled. It will be removed in Helmet 7.
667d917488: Updated dependency msw to ^0.47.0.
87ec2ba4d6: Updated dependency msw to ^0.46.0.
bf5e9030eb: Updated dependency msw to ^0.45.0.
Updated dependencies
@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.