Merge branch 'master' of https://github.com/backstage/backstage into marley/7678-pull-request-dashboard

This commit is contained in:
Marley Powell
2021-11-29 10:15:43 +00:00
258 changed files with 14419 additions and 918 deletions
-6
View File
@@ -1,6 +0,0 @@
---
'@backstage/errors': patch
---
Deprecate `parseErrorResponse` in favour of `parseErrorResponseBody`. Deprecate `data` field inside `ErrorResponse` in favour of `body`.
Rename the error name for unknown errors from `unknown` to `error`.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/integration': patch
---
Narrow the types returned by the request option functions, to only the specifics that they actually do return. The reason for this change is that a full `RequestInit` is unfortunate to return because it's different between `cross-fetch` and `node-fetch`.
-6
View File
@@ -1,6 +0,0 @@
---
'@backstage/plugin-tech-insights-backend': patch
'@backstage/plugin-tech-insights-backend-module-jsonfc': patch
---
Update README docs to use correct function/parameter names
+51
View File
@@ -0,0 +1,51 @@
---
'@backstage/create-app': patch
---
Incorporate usage of the tokenManager into the backend created using `create-app`.
In existing backends, update the `PluginEnvironment` to include a `tokenManager`:
```diff
// packages/backend/src/types.ts
...
import {
...
+ TokenManager,
} from '@backstage/backend-common';
export type PluginEnvironment = {
...
+ tokenManager: TokenManager;
};
```
Then, create a `ServerTokenManager`. This can either be a `noop` that requires no secret and validates all requests by default, or one that uses a secret from your `app-config.yaml` to generate and validate tokens.
```diff
// packages/backend/src/index.ts
...
import {
...
+ ServerTokenManager,
} from '@backstage/backend-common';
...
function makeCreateEnv(config: Config) {
...
// CHOOSE ONE
// TokenManager not requiring a secret
+ const tokenManager = ServerTokenManager.noop();
// OR TokenManager requiring a secret
+ const tokenManager = ServerTokenManager.fromConfig(config);
...
return (plugin: string): PluginEnvironment => {
...
- return { logger, cache, database, config, reader, discovery };
+ return { logger, cache, database, config, reader, discovery, tokenManager };
};
}
```
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-scaffolder': patch
---
Bump `react-jsonschema-form`
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-jenkins': patch
---
Fix Jenkins project table pagination.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-auth-backend': patch
---
Switched to using the standardized JSON error responses for all provider endpoints.
+19
View File
@@ -0,0 +1,19 @@
---
'@backstage/config-loader': patch
'@backstage/plugin-auth-backend': patch
'@backstage/plugin-badges-backend': patch
'@backstage/plugin-bitrise': patch
'@backstage/plugin-catalog-backend': patch
'@backstage/plugin-catalog-backend-module-msgraph': patch
'@backstage/plugin-code-coverage-backend': patch
'@backstage/plugin-fossa': patch
'@backstage/plugin-jenkins-backend': patch
'@backstage/plugin-scaffolder-backend': patch
'@backstage/plugin-scaffolder-backend-module-cookiecutter': patch
'@backstage/plugin-sonarqube': patch
'@backstage/plugin-tech-insights-backend': patch
'@backstage/plugin-techdocs-backend': patch
'@backstage/plugin-todo-backend': patch
---
Align on usage of `cross-fetch` vs `node-fetch` in frontend vs backend packages, and remove some unnecessary imports of either one of them
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/cli': patch
---
Switch the default test coverage provider from the jest default one to `'v8'`, which provides much better coverage information when using the default Backstage test setup. This is considered a bug fix as the current coverage information is often very inaccurate.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-kubernetes': patch
---
Implement support for formatting OpenShift dashboard url links
+28
View File
@@ -0,0 +1,28 @@
---
'@backstage/plugin-techdocs-backend': minor
---
**BREAKING** `DefaultTechDocsCollator` has a new required option `tokenManager`. See the create-app changelog for how to create a `tokenManager` and add it to the `PluginEnvironment`. It can then be passed to the collator in `createPlugin`:
```diff
// packages/backend/src/plugins/search.ts
...
export default async function createPlugin({
...
+ tokenManager,
}: PluginEnvironment) {
...
indexBuilder.addCollator({
defaultRefreshIntervalSeconds: 600,
collator: DefaultTechDocsCollator.fromConfig(config, {
discovery,
logger,
+ tokenManager,
}),
});
...
}
```
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-permission-node': minor
---
New package containing common permission and authorization utilities for backend plugins. For more information, see the [authorization PRFC](https://github.com/backstage/backstage/pull/7761).
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/cli': patch
---
Disable ES transforms in tests transformed by the `jestSucraseTransform.js`. This is not considered a breaking change since all code is already transpiled this way in the development setup.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/create-app': patch
---
DefaultTechDocsCollator is now included in the search backend, and the Search Page updated with the SearchType component that includes the techdocs type
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/backend-common': patch
---
Create a `TokenManager` interface and `ServerTokenManager` implementation to generate and validate server tokens for authenticated backend-to-backend API requests.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-catalog-backend': patch
---
Providing an empty values array in an EntityFilter will now return no matches.
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/cli': patch
'@techdocs/cli': patch
---
Bump react-dev-utils to v12
-34
View File
@@ -1,34 +0,0 @@
---
'@backstage/backend-common': patch
'@backstage/cli': patch
'@backstage/core-app-api': patch
'@backstage/create-app': patch
'@backstage/techdocs-common': patch
'@backstage/plugin-auth-backend': patch
'@backstage/plugin-azure-devops-backend': patch
'@backstage/plugin-badges-backend': patch
'@backstage/plugin-bazaar-backend': patch
'@backstage/plugin-catalog-backend': patch
'@backstage/plugin-code-coverage-backend': patch
'@backstage/plugin-github-actions': patch
'@backstage/plugin-jenkins-backend': patch
'@backstage/plugin-proxy-backend': patch
'@backstage/plugin-rollbar-backend': patch
'@backstage/plugin-search-backend': patch
'@backstage/plugin-techdocs': patch
'@backstage/plugin-techdocs-backend': patch
---
Change default port of backend from 7000 to 7007.
This is due to the AirPlay Receiver process occupying port 7000 and preventing local Backstage instances on MacOS to start.
You can change the port back to 7000 or any other value by providing an `app-config.yaml` with the following values:
```
backend:
listen: 0.0.0.0:7123
baseUrl: http://localhost:7123
```
More information can be found here: https://backstage.io/docs/conf/writing
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-permission-common': minor
---
Accept configApi rather than enabled flag in PermissionClient constructor.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/core-plugin-api': patch
---
Tweaked the logged deprecation warning for `createRouteRef` to hopefully make it more clear.
-6
View File
@@ -1,6 +0,0 @@
---
'@backstage/plugin-config-schema': patch
'@backstage/plugin-scaffolder': patch
---
Fixed a missing `await` when throwing server side errors
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-scaffolder-backend': patch
---
Fix bug where there was error log lines written when failing to `JSON.parse` things that were not `JSON` values.
-7
View File
@@ -1,7 +0,0 @@
---
'@backstage/core-plugin-api': patch
---
Deprecated `register` option of `createPlugin` and the `outputs` methods of the plugin instance.
Introduces the `featureFlags` property to define your feature flags instead.
-42
View File
@@ -1,42 +0,0 @@
---
'@backstage/plugin-catalog-backend': minor
---
**BREAKING** EntitiesSearchFilter fields have changed.
EntitiesSearchFilter now has only two fields: `key` and `value`. The `matchValueIn` and `matchValueExists` fields are no longer are supported. Previous filters written using the `matchValueIn` and `matchValueExists` fields can be rewritten as follows:
Filtering by existence of key only:
```diff
filter: {
{
key: 'abc',
- matchValueExists: true,
},
}
```
Filtering by key and values:
```diff
filter: {
{
key: 'abc',
- matchValueExists: true,
- matchValueIn: ['xyz'],
+ values: ['xyz'],
},
}
```
Negation of filters can now be achieved through a `not` object:
```
filter: {
not: {
key: 'abc',
values: ['xyz'],
},
}
```
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-catalog-backend': patch
---
Index User entities by displayName to be able to search by full name. Added displayName (if present) to the 'text' field in the indexed document.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-catalog-backend': patch
---
Added Azure DevOps discovery processor
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-auth-backend': patch
---
Expose catalog lib in plugin-auth-backend, i.e `CatalogIdentityClient` class is exposed now.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-catalog-backend': patch
---
Detect a duplicate entities when adding locations through dry run
-6
View File
@@ -1,6 +0,0 @@
---
'@backstage/create-app': patch
'@backstage/plugin-scaffolder-backend': patch
---
Bump gitbeaker to the latest version
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/cli': patch
---
Update the default routes to use id instead of title
-63
View File
@@ -1,63 +0,0 @@
---
'@backstage/core-app-api': patch
'@backstage/test-utils': patch
---
The `ApiRegistry` from `@backstage/core-app-api` class has been deprecated and will be removed in a future release. To replace it, we have introduced two new helpers that are exported from `@backstage/test-utils`, namely `TestApiProvider` and `TestApiRegistry`.
These two new helpers are more tailored for writing tests and development setups, as they allow for partial implementations of each of the APIs.
When migrating existing code it is typically best to prefer usage of `TestApiProvider` when possible, so for example the following code:
```tsx
render(
<ApiProvider
apis={ApiRegistry.from([
[identityApiRef, mockIdentityApi as unknown as IdentityApi]
])}
>
{...}
</ApiProvider>
)
```
Would be migrated to this:
```tsx
render(
<TestApiProvider apis={[[identityApiRef, mockIdentityApi]]}>
{...}
</TestApiProvider>
)
```
In cases where the `ApiProvider` is used in a more standalone way, for example to reuse a set of APIs across multiple tests, the `TestApiRegistry` can be used instead. Note that the `TestApiRegistry` only has a single static factory method, `.from()`, and it is slightly different from the existing `.from()` method on `ApiRegistry` in that it doesn't require the API pairs to be wrapped in an outer array.
Usage that looks like this:
```ts
const apis = ApiRegistry.with(
identityApiRef,
mockIdentityApi as unknown as IdentityApi,
).with(configApiRef, new ConfigReader({}));
```
OR like this:
```ts
const apis = ApiRegistry.from([
[identityApiRef, mockIdentityApi as unknown as IdentityApi],
[configApiRef, new ConfigReader({})],
]);
```
Would be migrated to this:
```ts
const apis = TestApiRegistry.from(
[identityApiRef, mockIdentityApi],
[configApiRef, new ConfigReader({})],
);
```
If your app is still using the `ApiRegistry` to construct the `apis` for `createApp`, we recommend that you move over to use the new method of supplying API factories instead, using `createApiFactory`.
+17
View File
@@ -0,0 +1,17 @@
---
'@backstage/plugin-scaffolder': patch
---
Add group filtering to the scaffolder page so that individuals can surface specific templates to end users ahead of others, or group templates together. This can be accomplished by passing in a `groups` prop to the `ScaffolderPage`
```
<ScaffolderPage
groups={[
{
title: "Recommended",
filter: entity =>
entity?.metadata?.tags?.includes('recommended') ?? false,
},
]}
/>
```
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-api-docs': patch
---
Adjusted some styles in the OpenAPI definition, for elements which were barely readable in dark mode.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/core-components': patch
---
Pin sidebar by default for easier navigation
+27
View File
@@ -0,0 +1,27 @@
---
'@backstage/plugin-catalog-backend': minor
---
**BREAKING** `DefaultCatalogCollator` has a new required option `tokenManager`. See the create-app changelog for how to create a `tokenManager` and add it to the `PluginEnvironment`. It can then be passed to the collator in `createPlugin`:
```diff
// packages/backend/src/plugins/search.ts
...
export default async function createPlugin({
...
+ tokenManager,
}: PluginEnvironment) {
...
indexBuilder.addCollator({
defaultRefreshIntervalSeconds: 600,
collator: DefaultCatalogCollator.fromConfig(config, {
discovery,
+ tokenManager,
}),
});
...
}
```
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-cost-insights': patch
---
Supply featureFlags using featureFlag config option.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-graphiql': patch
---
Letting GraphiQL use headers
+7
View File
@@ -18,6 +18,13 @@
/plugins/techdocs-backend @backstage/techdocs-core
/plugins/ilert @backstage/reviewers @yacut
/plugins/home @backstage/techdocs-core
/plugins/azure-devops @backstage/reviewers @marleypowell @awanlin
/plugins/azure-devops-backend @backstage/reviewers @marleypowell @awanlin
/plugins/azure-devops-common @backstage/reviewers @marleypowell @awanlin
/tech-insights-backend @backstage/reviewers @xantier @iain-b
/tech-insights-backend-module-jsonfc @backstage/reviewers @xantier @iain-b
/tech-insights-tech-insights-common @backstage/reviewers @xantier @iain-b
/tech-insights-tech-insights-node @backstage/reviewers @xantier @iain-b
/packages/embedded-techdocs-app @backstage/techdocs-core
/packages/search-common @backstage/techdocs-core
/packages/techdocs-cli @backstage/techdocs-core
-21
View File
@@ -1,21 +0,0 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 60
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- pinned
- security
- plugin
- help wanted
- good first issue
- rfc
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false
+30
View File
@@ -0,0 +1,30 @@
name: 'Stale workflow'
on:
workflow_dispatch:
schedule:
- cron: '*/10 * * * *' # run every 10 minutes as it also removes labels.
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@main
id: stale
with:
stale-issue-message: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
days-before-issue-stale: 60
days-before-issue-close: 7
exempt-issue-labels: 'pinned,security,plugin,help wanted,good first issue,rfc'
stale-issue-label: stale
stale-pr-message: >
This PR has been automatically marked as stale because it has not had
recent activity from the author. It will be closed if no further activity occurs.
If you are the author and the PR has been closed, feel free to re-open the PR and continue the contribution!
days-before-pr-stale: 7
days-before-pr-close: 3
exempt-pr-labels: reviewer-approved,awaiting-review
stale-pr-label: stale
operations-per-run: 100
+5
View File
@@ -23,6 +23,11 @@ app:
title: '#backstage'
backend:
# Used for enabling authentication, secret is shared by all backend plugins
# See backend-to-backend-auth.md in the docs for information on the format
# auth:
# keys:
# - secret: ${BACKEND_SECRET}
baseUrl: http://localhost:7007
listen:
port: 7007
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

+13 -3
View File
@@ -154,13 +154,17 @@ import { DefaultCatalogCollator } from '@backstage/plugin-catalog-backend';
export default async function createPlugin({
logger,
discovery,
tokenManager,
}: PluginEnvironment) {
const searchEngine = new LunrSearchEngine({ logger });
const indexBuilder = new IndexBuilder({ logger, searchEngine });
indexBuilder.addCollator({
defaultRefreshIntervalSeconds: 600,
collator: new DefaultCatalogCollator({ discovery }),
collator: new DefaultCatalogCollator({
discovery,
tokenManager,
}),
});
const { scheduler } = await indexBuilder.build();
@@ -285,7 +289,10 @@ const indexBuilder = new IndexBuilder({ logger, searchEngine });
indexBuilder.addCollator({
defaultRefreshIntervalSeconds: 600,
collator: new DefaultCatalogCollator({ discovery }),
collator: new DefaultCatalogCollator({
discovery,
tokenManager,
}),
});
indexBuilder.addCollator({
@@ -303,6 +310,9 @@ its `defaultRefreshIntervalSeconds` value, like this:
```typescript {3}
indexBuilder.addCollator({
defaultRefreshIntervalSeconds: 600,
collator: new DefaultCatalogCollator({ discovery }),
collator: new DefaultCatalogCollator({
discovery,
tokenManager,
}),
});
```
+2 -1
View File
@@ -2,7 +2,7 @@
id: how-to-guides
title: Search "HOW TO" guides
sidebar_label: "HOW TO" guides
description: Search "HOW TO" guides
description: Search "HOW TO" guides
---
## How to implement your own Search API
@@ -74,6 +74,7 @@ indexBuilder.addCollator({
collator: DefaultTechDocsCollator.fromConfig(config, {
discovery,
logger,
tokenManager,
}),
});
```
@@ -53,3 +53,30 @@ You can do so by including the following lines in the last step of your
RUN apt-get update && apt-get install -y python3 python3-pip
RUN pip3 install cookiecutter
```
### Customizing the ScaffolderPage with Grouping and Filtering
Once you have more than a few software templates you may want to customize your
`ScaffolderPage` by grouping and surfacing certain templates together. You can
accomplish this by creating `groups` and passing them to your `ScaffolderPage`
like below
```
<ScaffolderPage
groups={[
{
title: "Recommended",
filter: entity =>
entity?.metadata?.tags?.includes('recommended') ?? false,
},
]}
/>
```
This code will group all templates with the 'recommended' tag together at the
top of the page above any other templates not filtered by this group or others.
You can also further customize groups by passing in a `titleComponent` instead
of a `title` which will be a component to use as the header instead of just the
default `ContentHeader` with the `title` set as it's value.
![Grouped Templates](../../assets/software-templates/grouped-templates.png)
+68
View File
@@ -0,0 +1,68 @@
---
id: backend-to-backend-auth
title: Backend-to-Backend Authentication
description:
Guide for authenticating API requests between Backstage plugin backends
---
This tutorial describes the steps needed to handle _backend-to-backend
authentication_, which allows plugin backends to determine whether a given
request originates from a legitimate Backstage backend by verifying a token
signed with a shared secret. This system has limited use for now, but will be
needed to support the upcoming framework for permissions and authorization (see
[the PRFC on the topic](https://github.com/backstage/backstage/pull/7761) for
more details).
Backends have no concept of a Backstage identity, so instead they use a token
generated using a shared key stored in config. You can generate a unique key for
your app in a terminal, and set the `BACKEND_SECRET` environment variable to the
resulting value.
```bash
node -p 'require("crypto").randomBytes(24).toString("base64")'
```
Requests originating from a backend plugin can be authenticated by decorating
them with a backend token. Backend tokens can be generated using a
`TokenManager`, which can be passed to plugin backends via the
`PluginEnvironment`. The `TokenManager` provided in new Backstage instances
generated by `create-app` is a stub, which returns empty tokens and accepts any
input string as valid. To enable backend-to-backend authentication, you'll need
to instantiate a new one using the secret from your config instead:
```diff
// packages/backend/src/index.ts
function makeCreateEnv(config: Config) {
const root = getRootLogger();
const reader = UrlReaders.default({ logger: root, config });
const discovery = SingleHostDiscovery.fromConfig(config);
root.info(`Created UrlReader ${reader}`);
const cacheManager = CacheManager.fromConfig(config);
const databaseManager = DatabaseManager.fromConfig(config);
- const tokenManager = ServerTokenManager.noop();
+ const tokenManager = ServerTokenManager.fromConfig(config);
```
With this `tokenManager`, you can then generate a server token for requests:
```typescript
const { token } = await this.tokenManager.getToken();
const response = await fetch(pluginBackendApiUrl, {
method: 'GET',
headers: {
...headers,
Authorization: `Bearer ${token}`,
},
});
```
You can use the same `tokenManager` to authenticate tokens supplied on incoming
requests:
```typescript
await tokenManager.authenticate(token); // throws if token is invalid
```
+1 -1
View File
@@ -19,7 +19,7 @@
"@spotify/prettier-config": "^12.0.0",
"docusaurus": "^2.0.0-alpha.70",
"js-yaml": "^4.1.0",
"prettier": "^2.4.1",
"prettier": "^2.5.0",
"yarn-lock-check": "^1.0.5"
},
"prettier": "@spotify/prettier-config"
+4 -4
View File
@@ -5190,10 +5190,10 @@ prepend-http@^2.0.0:
resolved "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897"
integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=
prettier@^2.4.1:
version "2.4.1"
resolved "https://registry.npmjs.org/prettier/-/prettier-2.4.1.tgz#671e11c89c14a4cfc876ce564106c4a6726c9f5c"
integrity sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA==
prettier@^2.5.0:
version "2.5.0"
resolved "https://registry.npmjs.org/prettier/-/prettier-2.5.0.tgz#a6370e2d4594e093270419d9cc47f7670488f893"
integrity sha512-FM/zAKgWTxj40rH03VxzIPdXmj39SwSjwG0heUcNFwI+EMZJnY93yAiKXM3dObIKAM5TA88werc8T/EwhB45eg==
prismjs@^1.22.0:
version "1.25.0"
+2
View File
@@ -30,6 +30,8 @@
"prettier:check": "prettier --check .",
"lerna": "lerna",
"storybook": "yarn workspace storybook start",
"snyk:test": "npx snyk test --yarn-workspaces --strict-out-of-sync=false",
"snyk:test:package": "yarn snyk:test --include",
"build-storybook": "yarn workspace storybook build-storybook",
"techdocs-cli": "node scripts/techdocs-cli.js",
"techdocs-cli:dev": "cross-env TECHDOCS_CLI_DEV_MODE=true node scripts/techdocs-cli.js",
+14 -1
View File
@@ -176,7 +176,20 @@ const routes = (
>
{techDocsPage}
</Route>
<Route path="/create" element={<ScaffolderPage />}>
<Route
path="/create"
element={
<ScaffolderPage
groups={[
{
title: 'Recommended',
filter: entity =>
entity?.metadata?.tags?.includes('recommended') ?? false,
},
]}
/>
}
>
<ScaffolderFieldExtensions>
<LowerCaseValuePickerFieldExtension />
</ScaffolderFieldExtensions>
+21
View File
@@ -1,5 +1,26 @@
# @backstage/backend-common
## 0.9.11
### Patch Changes
- bab752e2b3: Change default port of backend from 7000 to 7007.
This is due to the AirPlay Receiver process occupying port 7000 and preventing local Backstage instances on MacOS to start.
You can change the port back to 7000 or any other value by providing an `app-config.yaml` with the following values:
```
backend:
listen: 0.0.0.0:7123
baseUrl: http://localhost:7123
```
More information can be found here: https://backstage.io/docs/conf/writing
- Updated dependencies
- @backstage/errors@0.1.5
## 0.9.10
### Patch Changes
+24
View File
@@ -526,6 +526,20 @@ export type SearchResponseFile = {
content(): Promise<Buffer>;
};
// @public
export class ServerTokenManager implements TokenManager {
// (undocumented)
authenticate(token: string): Promise<void>;
// (undocumented)
static fromConfig(config: Config): ServerTokenManager;
// (undocumented)
getToken(): Promise<{
token: string;
}>;
// (undocumented)
static noop(): TokenManager;
}
// @public (undocumented)
export type ServiceBuilder = {
loadConfig(config: Config): ServiceBuilder;
@@ -583,6 +597,16 @@ export interface StatusCheckHandlerOptions {
statusCheck?: StatusCheck;
}
// @public
export interface TokenManager {
// (undocumented)
authenticate: (token: string) => Promise<void>;
// (undocumented)
getToken: () => Promise<{
token: string;
}>;
}
// @public
export type UrlReader = {
read(url: string): Promise<Buffer>;
+14
View File
@@ -20,6 +20,20 @@ export interface Config {
};
backend: {
/** Backend configuration for when request authentication is enabled */
auth?: {
/** Keys shared by all backends for signing and validating backend tokens. */
keys: {
/**
* Secret for generating tokens. Should be a base64 string, recommended
* length is 24 bytes.
*
* @visibility secret
*/
secret: string;
}[];
};
baseUrl: string; // defined in core, but repeated here without doc
/** Address that the backend should listen to. */
+5 -4
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/backend-common",
"description": "Common functionality library for Backstage backends",
"version": "0.9.10",
"version": "0.9.11",
"main": "src/index.ts",
"types": "src/index.ts",
"private": false,
@@ -32,7 +32,7 @@
"@backstage/cli-common": "^0.1.6",
"@backstage/config": "^0.1.11",
"@backstage/config-loader": "^0.8.0",
"@backstage/errors": "^0.1.4",
"@backstage/errors": "^0.1.5",
"@backstage/integration": "^0.6.9",
"@backstage/types": "^0.1.1",
"@google-cloud/storage": "^5.8.0",
@@ -54,6 +54,7 @@
"git-url-parse": "^11.6.0",
"helmet": "^4.0.0",
"isomorphic-git": "^1.8.0",
"jose": "^1.27.1",
"keyv": "^4.0.3",
"keyv-memcache": "^1.2.5",
"knex": "^0.95.1",
@@ -80,8 +81,8 @@
}
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
"@backstage/test-utils": "^0.1.22",
"@backstage/cli": "^0.9.1",
"@backstage/test-utils": "^0.1.23",
"@types/archiver": "^5.1.0",
"@types/compression": "^1.7.0",
"@types/concat-stream": "^1.6.0",
+1
View File
@@ -31,4 +31,5 @@ export * from './paths';
export * from './reading';
export * from './scm';
export * from './service';
export * from './tokens';
export * from './util';
@@ -0,0 +1,189 @@
/*
* Copyright 2021 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { ConfigReader } from '@backstage/config';
import { TokenManager } from './types';
import { ServerTokenManager } from './ServerTokenManager';
const emptyConfig = new ConfigReader({});
const configWithSecret = new ConfigReader({
backend: { auth: { keys: [{ secret: 'a-secret-key' }] } },
});
describe('ServerTokenManager', () => {
it('should throw if secret in config does not exist', () => {
expect(() => ServerTokenManager.fromConfig(emptyConfig)).toThrowError();
});
describe('getToken', () => {
it('should return a token if secret in config exists', async () => {
const tokenManager = ServerTokenManager.fromConfig(configWithSecret);
expect((await tokenManager.getToken()).token).toBeDefined();
});
it('should return a token string if using a noop TokenManager', async () => {
const tokenManager = ServerTokenManager.noop();
expect((await tokenManager.getToken()).token).toBeDefined();
});
});
describe('authenticate', () => {
it('should not throw if token is valid', async () => {
const tokenManager = ServerTokenManager.fromConfig(configWithSecret);
const { token } = await tokenManager.getToken();
await expect(tokenManager.authenticate(token)).resolves.not.toThrow();
});
it('should throw if token is invalid', async () => {
const tokenManager = ServerTokenManager.fromConfig(configWithSecret);
await expect(
tokenManager.authenticate('random-string'),
).rejects.toThrowError(/invalid server token/i);
});
it('should validate server tokens created by a different instance using the same secret', async () => {
const tokenManager1 = ServerTokenManager.fromConfig(configWithSecret);
const tokenManager2 = ServerTokenManager.fromConfig(configWithSecret);
const { token } = await tokenManager1.getToken();
await expect(tokenManager2.authenticate(token)).resolves.not.toThrow();
});
it('should validate server tokens created using any of the secrets', async () => {
const tokenManager1 = ServerTokenManager.fromConfig(
new ConfigReader({
backend: { auth: { keys: [{ secret: 'a1b2c3' }] } },
}),
);
const tokenManager2 = ServerTokenManager.fromConfig(
new ConfigReader({
backend: { auth: { keys: [{ secret: 'd4e5f6' }] } },
}),
);
const tokenManager3 = ServerTokenManager.fromConfig(
new ConfigReader({
backend: {
auth: { keys: [{ secret: 'a1b2c3' }, { secret: 'd4e5f6' }] },
},
}),
);
const { token: token1 } = await tokenManager1.getToken();
await expect(tokenManager3.authenticate(token1)).resolves.not.toThrow();
const { token: token2 } = await tokenManager2.getToken();
await expect(tokenManager3.authenticate(token2)).resolves.not.toThrow();
});
it('should throw for server tokens created using a different secret', async () => {
const tokenManager1 = ServerTokenManager.fromConfig(
new ConfigReader({
backend: { auth: { keys: [{ secret: 'a1b2c3' }] } },
}),
);
const tokenManager2 = ServerTokenManager.fromConfig(
new ConfigReader({
backend: { auth: { keys: [{ secret: 'd4e5f6' }] } },
}),
);
const { token } = await tokenManager1.getToken();
await expect(tokenManager2.authenticate(token)).rejects.toThrowError(
/invalid server token/i,
);
});
it('should throw for server tokens created using a noop TokenManager', async () => {
const noopTokenManager = ServerTokenManager.noop();
const tokenManager = ServerTokenManager.fromConfig(
new ConfigReader({
backend: { auth: { keys: [{ secret: 'a1b2c3' }] } },
}),
);
const { token } = await noopTokenManager.getToken();
await expect(tokenManager.authenticate(token)).rejects.toThrowError(
/invalid server token/i,
);
});
});
describe('ServerTokenManager.fromConfig', () => {
it('should throw if backend auth configuration is missing', () => {
expect(() =>
ServerTokenManager.fromConfig(new ConfigReader({})),
).toThrow();
});
it('should throw if no keys are included in the configuration', () => {
expect(() =>
ServerTokenManager.fromConfig(
new ConfigReader({
backend: { auth: { keys: [] } },
}),
),
).toThrow();
});
it('should throw if any key is missing a secret property', () => {
expect(() =>
ServerTokenManager.fromConfig(
new ConfigReader({
backend: {
auth: {
keys: [{ secret: '123' }, {}, { secret: '789' }],
},
},
}),
),
).toThrow();
});
});
describe('ServerTokenManager.noop', () => {
let noopTokenManager: TokenManager;
beforeEach(() => {
noopTokenManager = ServerTokenManager.noop();
});
it('should accept tokens it generates', async () => {
const { token } = await noopTokenManager.getToken();
await expect(noopTokenManager.authenticate(token)).resolves.not.toThrow();
});
it('should accept tokens generated by other noop token managers', async () => {
const noopTokenManager2 = ServerTokenManager.noop();
await expect(
noopTokenManager.authenticate(
(
await noopTokenManager2.getToken()
).token,
),
).resolves.not.toThrow();
});
it('should accept signed tokens', async () => {
const tokenManager = ServerTokenManager.fromConfig(configWithSecret);
await expect(
noopTokenManager.authenticate((await tokenManager.getToken()).token),
).resolves.not.toThrow();
});
});
});
@@ -0,0 +1,80 @@
/*
* Copyright 2021 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { JWKS, JWK, JWT } from 'jose';
import { Config } from '@backstage/config';
import { AuthenticationError } from '@backstage/errors';
import { TokenManager } from './types';
class NoopTokenManager implements TokenManager {
async getToken() {
return { token: '' };
}
async authenticate() {}
}
/**
* Creates and validates tokens for use during backend-to-backend
* authentication.
*
* @public
*/
export class ServerTokenManager implements TokenManager {
private readonly verificationKeys: JWKS.KeyStore;
private readonly signingKey: JWK.Key;
static noop(): TokenManager {
return new NoopTokenManager();
}
static fromConfig(config: Config) {
return new ServerTokenManager(
config
.getConfigArray('backend.auth.keys')
.map(key => key.getString('secret')),
);
}
private constructor(secrets?: string[]) {
if (!secrets?.length) {
throw new Error(
'No secrets provided when constructing ServerTokenManager',
);
}
this.verificationKeys = new JWKS.KeyStore(
secrets.map(k => JWK.asKey({ kty: 'oct', k })),
);
this.signingKey = this.verificationKeys.all()[0];
}
async getToken(): Promise<{ token: string }> {
const jwt = JWT.sign({ sub: 'backstage-server' }, this.signingKey, {
algorithm: 'HS256',
});
return { token: jwt };
}
async authenticate(token: string): Promise<void> {
try {
JWT.verify(token, this.verificationKeys);
} catch (e) {
throw new AuthenticationError('Invalid server token');
}
}
}
@@ -0,0 +1,18 @@
/*
* Copyright 2021 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { ServerTokenManager } from './ServerTokenManager';
export type { TokenManager } from './types';
@@ -0,0 +1,25 @@
/*
* Copyright 2021 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Interface for creating and validating tokens.
*
* @public
*/
export interface TokenManager {
getToken: () => Promise<{ token: string }>;
authenticate: (token: string) => Promise<void>;
}
+22
View File
@@ -1,5 +1,27 @@
# example-backend
## 0.2.54
### Patch Changes
- Updated dependencies
- @backstage/plugin-kubernetes-backend@0.3.19
- @backstage/plugin-tech-insights-backend@0.1.2
- @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.1
- @backstage/plugin-auth-backend@0.4.9
- @backstage/plugin-scaffolder-backend@0.15.14
- @backstage/plugin-catalog-backend@0.18.0
- @backstage/plugin-kafka-backend@0.2.12
- @backstage/backend-common@0.9.11
- @backstage/plugin-azure-devops-backend@0.2.2
- @backstage/plugin-badges-backend@0.1.12
- @backstage/plugin-code-coverage-backend@0.1.15
- @backstage/plugin-jenkins-backend@0.1.8
- @backstage/plugin-proxy-backend@0.2.14
- @backstage/plugin-rollbar-backend@0.1.16
- @backstage/plugin-search-backend@0.2.7
- @backstage/plugin-techdocs-backend@0.10.9
## 0.2.52
### Patch Changes
+18 -18
View File
@@ -1,6 +1,6 @@
{
"name": "example-backend",
"version": "0.2.52",
"version": "0.2.54",
"main": "dist/index.cjs.js",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -24,33 +24,33 @@
"migrate:create": "knex migrate:make -x ts"
},
"dependencies": {
"@backstage/backend-common": "^0.9.10",
"@backstage/backend-common": "^0.9.11",
"@backstage/catalog-client": "^0.5.2",
"@backstage/catalog-model": "^0.9.7",
"@backstage/config": "^0.1.10",
"@backstage/integration": "^0.6.8",
"@backstage/plugin-app-backend": "^0.3.19",
"@backstage/plugin-auth-backend": "^0.4.8",
"@backstage/plugin-azure-devops-backend": "^0.2.1",
"@backstage/plugin-badges-backend": "^0.1.11",
"@backstage/plugin-catalog-backend": "^0.17.4",
"@backstage/plugin-code-coverage-backend": "^0.1.14",
"@backstage/plugin-auth-backend": "^0.4.9",
"@backstage/plugin-azure-devops-backend": "^0.2.2",
"@backstage/plugin-badges-backend": "^0.1.12",
"@backstage/plugin-catalog-backend": "^0.18.0",
"@backstage/plugin-code-coverage-backend": "^0.1.15",
"@backstage/plugin-graphql-backend": "^0.1.9",
"@backstage/plugin-jenkins-backend": "^0.1.7",
"@backstage/plugin-kubernetes-backend": "^0.3.18",
"@backstage/plugin-kafka-backend": "^0.2.11",
"@backstage/plugin-proxy-backend": "^0.2.13",
"@backstage/plugin-rollbar-backend": "^0.1.15",
"@backstage/plugin-scaffolder-backend": "^0.15.13",
"@backstage/plugin-jenkins-backend": "^0.1.8",
"@backstage/plugin-kubernetes-backend": "^0.3.19",
"@backstage/plugin-kafka-backend": "^0.2.12",
"@backstage/plugin-proxy-backend": "^0.2.14",
"@backstage/plugin-rollbar-backend": "^0.1.16",
"@backstage/plugin-scaffolder-backend": "^0.15.14",
"@backstage/plugin-scaffolder-backend-module-rails": "^0.1.7",
"@backstage/plugin-search-backend": "^0.2.6",
"@backstage/plugin-search-backend": "^0.2.7",
"@backstage/plugin-search-backend-node": "^0.4.2",
"@backstage/plugin-search-backend-module-elasticsearch": "^0.0.5",
"@backstage/plugin-search-backend-module-pg": "^0.2.1",
"@backstage/plugin-techdocs-backend": "^0.10.8",
"@backstage/plugin-tech-insights-backend": "^0.1.1",
"@backstage/plugin-techdocs-backend": "^0.10.9",
"@backstage/plugin-tech-insights-backend": "^0.1.2",
"@backstage/plugin-tech-insights-node": "^0.1.0",
"@backstage/plugin-tech-insights-backend-module-jsonfc": "^0.1.0",
"@backstage/plugin-tech-insights-backend-module-jsonfc": "^0.1.1",
"@backstage/plugin-todo-backend": "^0.1.13",
"@gitbeaker/node": "^34.6.0",
"@octokit/rest": "^18.5.3",
@@ -68,7 +68,7 @@
"winston": "^3.2.1"
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
"@backstage/cli": "^0.9.1",
"@types/dockerode": "^3.3.0",
"@types/express": "^4.17.6",
"@types/express-serve-static-core": "^4.17.5"
+3 -1
View File
@@ -33,6 +33,7 @@ import {
SingleHostDiscovery,
UrlReaders,
useHotMemoize,
ServerTokenManager,
} from '@backstage/backend-common';
import { Config } from '@backstage/config';
import healthcheck from './plugins/healthcheck';
@@ -60,6 +61,7 @@ function makeCreateEnv(config: Config) {
const root = getRootLogger();
const reader = UrlReaders.default({ logger: root, config });
const discovery = SingleHostDiscovery.fromConfig(config);
const tokenManager = ServerTokenManager.noop();
root.info(`Created UrlReader ${reader}`);
@@ -70,7 +72,7 @@ function makeCreateEnv(config: Config) {
const logger = root.child({ type: 'plugin', plugin });
const database = databaseManager.forPlugin(plugin);
const cache = cacheManager.forPlugin(plugin);
return { logger, cache, database, config, reader, discovery };
return { logger, cache, database, config, reader, discovery, tokenManager };
};
}
+6 -1
View File
@@ -59,6 +59,7 @@ export default async function createPlugin({
discovery,
config,
database,
tokenManager,
}: PluginEnvironment) {
// Initialize a connection to a search engine.
const searchEngine = await createSearchEngine({ config, logger, database });
@@ -68,7 +69,10 @@ export default async function createPlugin({
// particular collator gathers entities from the software catalog.
indexBuilder.addCollator({
defaultRefreshIntervalSeconds: 600,
collator: DefaultCatalogCollator.fromConfig(config, { discovery }),
collator: DefaultCatalogCollator.fromConfig(config, {
discovery,
tokenManager,
}),
});
indexBuilder.addCollator({
@@ -76,6 +80,7 @@ export default async function createPlugin({
collator: DefaultTechDocsCollator.fromConfig(config, {
discovery,
logger,
tokenManager,
}),
});
+2
View File
@@ -20,6 +20,7 @@ import {
PluginCacheManager,
PluginDatabaseManager,
PluginEndpointDiscovery,
TokenManager,
UrlReader,
} from '@backstage/backend-common';
@@ -30,4 +31,5 @@ export type PluginEnvironment = {
config: Config;
reader: UrlReader;
discovery: PluginEndpointDiscovery;
tokenManager: TokenManager;
};
+24
View File
@@ -1,5 +1,29 @@
# @backstage/cli
## 0.9.1
### Patch Changes
- dde216acf4: Switch the default test coverage provider from the jest default one to `'v8'`, which provides much better coverage information when using the default Backstage test setup. This is considered a bug fix as the current coverage information is often very inaccurate.
- 719cc87d2f: Disable ES transforms in tests transformed by the `jestSucraseTransform.js`. This is not considered a breaking change since all code is already transpiled this way in the development setup.
- bab752e2b3: Change default port of backend from 7000 to 7007.
This is due to the AirPlay Receiver process occupying port 7000 and preventing local Backstage instances on MacOS to start.
You can change the port back to 7000 or any other value by providing an `app-config.yaml` with the following values:
```
backend:
listen: 0.0.0.0:7123
baseUrl: http://localhost:7123
```
More information can be found here: https://backstage.io/docs/conf/writing
- ee055cf6db: Update the default routes to use id instead of title
- Updated dependencies
- @backstage/errors@0.1.5
## 0.9.0
### Minor Changes
+8 -8
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/cli",
"description": "CLI for developing Backstage plugins and apps",
"version": "0.9.0",
"version": "0.9.1",
"private": false,
"publishConfig": {
"access": "public"
@@ -31,7 +31,7 @@
"@backstage/cli-common": "^0.1.6",
"@backstage/config": "^0.1.11",
"@backstage/config-loader": "^0.8.0",
"@backstage/errors": "^0.1.4",
"@backstage/errors": "^0.1.5",
"@backstage/types": "^0.1.1",
"@hot-loader/react-dom": "^16.13.0",
"@lerna/package-graph": "^4.0.0",
@@ -90,7 +90,7 @@
"postcss": "^8.1.0",
"process": "^0.11.10",
"react": "^16.0.0",
"react-dev-utils": "^11.0.4",
"react-dev-utils": "^12.0.0-next.47",
"react-hot-loader": "^4.12.21",
"recursive-readdir": "^2.2.2",
"replace-in-file": "^6.0.0",
@@ -117,13 +117,13 @@
"yn": "^4.0.0"
},
"devDependencies": {
"@backstage/backend-common": "^0.9.10",
"@backstage/backend-common": "^0.9.11",
"@backstage/config": "^0.1.11",
"@backstage/core-components": "^0.7.4",
"@backstage/core-plugin-api": "^0.2.0",
"@backstage/core-app-api": "^0.1.21",
"@backstage/core-components": "^0.7.5",
"@backstage/core-plugin-api": "^0.2.1",
"@backstage/core-app-api": "^0.1.23",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@backstage/test-utils": "^0.1.23",
"@backstage/theme": "^0.2.13",
"@types/diff": "^5.0.0",
"@types/express": "^4.17.6",
+9
View File
@@ -1,5 +1,14 @@
# @backstage/codemods
## 0.1.23
### Patch Changes
- Updated dependencies
- @backstage/core-app-api@0.1.23
- @backstage/core-plugin-api@0.2.1
- @backstage/core-components@0.7.5
## 0.1.22
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/codemods",
"description": "A collection of codemods for Backstage projects",
"version": "0.1.22",
"version": "0.1.23",
"private": false,
"publishConfig": {
"access": "public",
+2 -2
View File
@@ -41,10 +41,10 @@
"json-schema": "^0.4.0",
"json-schema-merge-allof": "^0.8.1",
"json-schema-traverse": "^1.0.0",
"node-fetch": "^2.6.1",
"typescript-json-schema": "^0.51.0",
"yaml": "^1.9.2",
"yup": "^0.32.9",
"node-fetch": "2.6.5"
"yup": "^0.32.9"
},
"devDependencies": {
"@types/jest": "^26.0.7",
+81
View File
@@ -1,5 +1,86 @@
# @backstage/core-app-api
## 0.1.23
### Patch Changes
- bab752e2b3: Change default port of backend from 7000 to 7007.
This is due to the AirPlay Receiver process occupying port 7000 and preventing local Backstage instances on MacOS to start.
You can change the port back to 7000 or any other value by providing an `app-config.yaml` with the following values:
```
backend:
listen: 0.0.0.0:7123
baseUrl: http://localhost:7123
```
More information can be found here: https://backstage.io/docs/conf/writing
- 000190de69: The `ApiRegistry` from `@backstage/core-app-api` class has been deprecated and will be removed in a future release. To replace it, we have introduced two new helpers that are exported from `@backstage/test-utils`, namely `TestApiProvider` and `TestApiRegistry`.
These two new helpers are more tailored for writing tests and development setups, as they allow for partial implementations of each of the APIs.
When migrating existing code it is typically best to prefer usage of `TestApiProvider` when possible, so for example the following code:
```tsx
render(
<ApiProvider
apis={ApiRegistry.from([
[identityApiRef, mockIdentityApi as unknown as IdentityApi]
])}
>
{...}
</ApiProvider>
)
```
Would be migrated to this:
```tsx
render(
<TestApiProvider apis={[[identityApiRef, mockIdentityApi]]}>
{...}
</TestApiProvider>
)
```
In cases where the `ApiProvider` is used in a more standalone way, for example to reuse a set of APIs across multiple tests, the `TestApiRegistry` can be used instead. Note that the `TestApiRegistry` only has a single static factory method, `.from()`, and it is slightly different from the existing `.from()` method on `ApiRegistry` in that it doesn't require the API pairs to be wrapped in an outer array.
Usage that looks like this:
```ts
const apis = ApiRegistry.with(
identityApiRef,
mockIdentityApi as unknown as IdentityApi,
).with(configApiRef, new ConfigReader({}));
```
OR like this:
```ts
const apis = ApiRegistry.from([
[identityApiRef, mockIdentityApi as unknown as IdentityApi],
[configApiRef, new ConfigReader({})],
]);
```
Would be migrated to this:
```ts
const apis = TestApiRegistry.from(
[identityApiRef, mockIdentityApi],
[configApiRef, new ConfigReader({})],
);
```
If your app is still using the `ApiRegistry` to construct the `apis` for `createApp`, we recommend that you move over to use the new method of supplying API factories instead, using `createApiFactory`.
- Updated dependencies
- @backstage/core-plugin-api@0.2.1
- @backstage/core-components@0.7.5
## 0.1.22
### Patch Changes
+5 -5
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/core-app-api",
"description": "Core app API used by Backstage apps",
"version": "0.1.22",
"version": "0.1.23",
"private": false,
"publishConfig": {
"access": "public",
@@ -30,9 +30,9 @@
},
"dependencies": {
"@backstage/app-defaults": "^0.1.1",
"@backstage/core-components": "^0.7.4",
"@backstage/core-components": "^0.7.5",
"@backstage/config": "^0.1.11",
"@backstage/core-plugin-api": "^0.2.0",
"@backstage/core-plugin-api": "^0.2.1",
"@backstage/theme": "^0.2.13",
"@backstage/types": "^0.1.1",
"@backstage/version-bridge": "^0.1.0",
@@ -47,8 +47,8 @@
"zen-observable": "^0.8.15"
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
"@backstage/test-utils": "^0.1.22",
"@backstage/cli": "^0.9.1",
"@backstage/test-utils": "^0.1.23",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^11.2.5",
"@testing-library/react-hooks": "^7.0.2",
+9
View File
@@ -1,5 +1,14 @@
# @backstage/core-components
## 0.7.5
### Patch Changes
- 157530187a: Pin sidebar by default for easier navigation
- Updated dependencies
- @backstage/errors@0.1.5
- @backstage/core-plugin-api@0.2.1
## 0.7.4
### Patch Changes
+6 -6
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/core-components",
"description": "Core components used by Backstage plugins and apps",
"version": "0.7.4",
"version": "0.7.5",
"private": false,
"publishConfig": {
"access": "public",
@@ -30,8 +30,8 @@
},
"dependencies": {
"@backstage/config": "^0.1.11",
"@backstage/core-plugin-api": "^0.2.0",
"@backstage/errors": "^0.1.4",
"@backstage/core-plugin-api": "^0.2.1",
"@backstage/errors": "^0.1.5",
"@backstage/theme": "^0.2.13",
"@material-table/core": "^3.1.0",
"@material-ui/core": "^4.12.2",
@@ -67,9 +67,9 @@
"zen-observable": "^0.8.15"
},
"devDependencies": {
"@backstage/core-app-api": "^0.1.21",
"@backstage/cli": "^0.9.0",
"@backstage/test-utils": "^0.1.22",
"@backstage/core-app-api": "^0.1.23",
"@backstage/cli": "^0.9.1",
"@backstage/test-utils": "^0.1.23",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^11.2.5",
"@testing-library/react-hooks": "^7.0.2",
+8
View File
@@ -1,5 +1,13 @@
# @backstage/core-plugin-api
## 0.2.1
### Patch Changes
- 950b36393c: Deprecated `register` option of `createPlugin` and the `outputs` methods of the plugin instance.
Introduces the `featureFlags` property to define your feature flags instead.
## 0.2.0
### Minor Changes
+4 -4
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/core-plugin-api",
"description": "Core API used by Backstage plugins",
"version": "0.2.0",
"version": "0.2.1",
"private": false,
"publishConfig": {
"access": "public",
@@ -43,9 +43,9 @@
"zen-observable": "^0.8.15"
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
"@backstage/core-app-api": "^0.1.21",
"@backstage/test-utils": "^0.1.22",
"@backstage/cli": "^0.9.1",
"@backstage/core-app-api": "^0.1.23",
"@backstage/test-utils": "^0.1.23",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^11.2.5",
"@testing-library/react-hooks": "^7.0.2",
@@ -59,21 +59,21 @@ export class RouteRefImpl<Params extends AnyParams>
if (config.path) {
// eslint-disable-next-line no-console
console.warn(
`[core-plugin-api] - routeRefs no longer decide their own path, please remove the path for ${this.toString()}. This will be removed in upcoming versions.`,
`DEPRECATION WARNING: Passing a path to createRouteRef is deprecated, please remove the path for ${this}.`,
);
}
if (config.icon) {
// eslint-disable-next-line no-console
console.warn(
`[core-plugin-api] - routeRefs no longer decide their own icon, please remove the icon for ${this.toString()}. This will be removed in upcoming versions.`,
`DEPRECATION WARNING: Passing an icon to createRouteRef is deprecated, please remove the icon for ${this}.`,
);
}
if (config.title) {
// eslint-disable-next-line no-console
console.warn(
`[core-plugin-api] - routeRefs no longer decide their own title, please remove the title for ${this.toString()}. This will be removed in upcoming versions.`,
`DEPRECATION WARNING: Passing a title to createRouteRef is deprecated, please remove the title for ${this}.`,
);
}
}
+22
View File
@@ -1,5 +1,27 @@
# @backstage/create-app
## 0.4.5
### Patch Changes
- dcaeaac174: Cleaned out the `peerDependencies` in the published version of the package, making it much quicker to run `npx @backstage/create-app` as it no longer needs to install a long list of unnecessary.
- a5a5d7e1f1: DefaultTechDocsCollator is now included in the search backend, and the Search Page updated with the SearchType component that includes the techdocs type
- bab752e2b3: Change default port of backend from 7000 to 7007.
This is due to the AirPlay Receiver process occupying port 7000 and preventing local Backstage instances on MacOS to start.
You can change the port back to 7000 or any other value by providing an `app-config.yaml` with the following values:
```
backend:
listen: 0.0.0.0:7123
baseUrl: http://localhost:7123
```
More information can be found here: https://backstage.io/docs/conf/writing
- 42ebbc18c0: Bump gitbeaker to the latest version
## 0.4.4
### Patch Changes
+3 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/create-app",
"description": "A CLI that helps you create your own Backstage app",
"version": "0.4.4",
"version": "0.4.5",
"private": false,
"publishConfig": {
"access": "public"
@@ -25,6 +25,8 @@
"lint": "backstage-cli lint",
"test": "backstage-cli test",
"clean": "backstage-cli clean",
"prepack": "node scripts/prepack.js",
"postpack": "node scripts/postpack.js",
"start": "nodemon --"
},
"dependencies": {
+37
View File
@@ -0,0 +1,37 @@
#!/usr/bin/env node
/*
* Copyright 2021 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* eslint-disable no-restricted-syntax */
const fs = require('fs-extra');
const path = require('path');
async function main() {
const pkgPath = path.resolve(__dirname, '../package.json');
const pkgBackupPath = path.resolve(__dirname, '../package.json-prepack');
try {
await fs.move(pkgBackupPath, pkgPath, { overwrite: true });
} catch (err) {
console.error(`Failed to restore package.json during postpack, ${err}`);
}
}
main().catch(err => {
console.error(err.stack);
process.exit(1);
});
+36
View File
@@ -0,0 +1,36 @@
#!/usr/bin/env node
/*
* Copyright 2021 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* eslint-disable no-restricted-syntax */
const fs = require('fs-extra');
const path = require('path');
async function main() {
const pkgPath = path.resolve(__dirname, '../package.json');
const pkgBackupPath = path.resolve(__dirname, '../package.json-prepack');
const pkg = await fs.readJson(pkgPath);
await fs.writeJson(pkgBackupPath, pkg, { encoding: 'utf8', spaces: 2 });
delete pkg.peerDependencies;
await fs.writeJson(pkgPath, pkg, { encoding: 'utf8', spaces: 2 });
}
main().catch(err => {
console.error(err.stack);
process.exit(1);
});
@@ -6,6 +6,11 @@ organization:
name: My Company
backend:
# Used for enabling authentication, secret is shared by all backend plugins
# See backend-to-backend-auth.md in the docs for information on the format
# auth:
# keys:
# - secret: ${BACKEND_SECRET}
baseUrl: http://localhost:7007
listen:
port: 7007
@@ -17,6 +17,7 @@ import {
DatabaseManager,
SingleHostDiscovery,
UrlReaders,
ServerTokenManager,
} from '@backstage/backend-common';
import { Config } from '@backstage/config';
import app from './plugins/app';
@@ -37,12 +38,13 @@ function makeCreateEnv(config: Config) {
const cacheManager = CacheManager.fromConfig(config);
const databaseManager = DatabaseManager.fromConfig(config);
const tokenManager = ServerTokenManager.noop();
return (plugin: string): PluginEnvironment => {
const logger = root.child({ type: 'plugin', plugin });
const database = databaseManager.forPlugin(plugin);
const cache = cacheManager.forPlugin(plugin);
return { logger, database, cache, config, reader, discovery };
return { logger, database, cache, config, reader, discovery, tokenManager };
};
}
@@ -12,6 +12,7 @@ export default async function createPlugin({
logger,
discovery,
config,
tokenManager,
}: PluginEnvironment) {
// Initialize a connection to a search engine.
const searchEngine = new LunrSearchEngine({ logger });
@@ -21,13 +22,20 @@ export default async function createPlugin({
// collator gathers entities from the software catalog.
indexBuilder.addCollator({
defaultRefreshIntervalSeconds: 600,
collator: DefaultCatalogCollator.fromConfig(config, { discovery }),
collator: DefaultCatalogCollator.fromConfig(config, {
discovery,
tokenManager,
}),
});
// collator gathers entities from techdocs.
indexBuilder.addCollator({
defaultRefreshIntervalSeconds: 600,
collator: DefaultTechDocsCollator.fromConfig(config, { discovery, logger }),
collator: DefaultTechDocsCollator.fromConfig(config, {
discovery,
logger,
tokenManager,
}),
});
// The scheduler controls when documents are gathered from collators and sent
@@ -4,6 +4,7 @@ import {
PluginCacheManager,
PluginDatabaseManager,
PluginEndpointDiscovery,
TokenManager,
UrlReader,
} from '@backstage/backend-common';
@@ -14,4 +15,5 @@ export type PluginEnvironment = {
config: Config;
reader: UrlReader;
discovery: PluginEndpointDiscovery;
tokenManager: TokenManager;
};
+7
View File
@@ -1,5 +1,12 @@
# @backstage/errors
## 0.1.5
### Patch Changes
- 4d09c60256: Deprecate `parseErrorResponse` in favour of `parseErrorResponseBody`. Deprecate `data` field inside `ErrorResponse` in favour of `body`.
Rename the error name for unknown errors from `unknown` to `error`.
## 0.1.4
### Patch Changes
+2 -2
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/errors",
"description": "Common utilities for error handling within Backstage",
"version": "0.1.4",
"version": "0.1.5",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -35,7 +35,7 @@
"serialize-error": "^8.0.1"
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
"@backstage/cli": "^0.9.1",
"@types/jest": "^26.0.7"
},
"files": [
+12 -6
View File
@@ -112,7 +112,9 @@ export function getAzureFileFetchUrl(url: string): string;
export function getAzureRequestOptions(
config: AzureIntegrationConfig,
additionalHeaders?: Record<string, string>,
): RequestInit;
): {
headers: Record<string, string>;
};
// @public
export function getBitbucketDefaultBranch(
@@ -135,7 +137,9 @@ export function getBitbucketFileFetchUrl(
// @public
export function getBitbucketRequestOptions(
config: BitbucketIntegrationConfig,
): RequestInit;
): {
headers: Record<string, string>;
};
// @public
export function getGitHubFileFetchUrl(
@@ -148,7 +152,9 @@ export function getGitHubFileFetchUrl(
export function getGitHubRequestOptions(
config: GitHubIntegrationConfig,
credentials: GithubCredentials,
): RequestInit;
): {
headers: Record<string, string>;
};
// @public
export function getGitLabFileFetchUrl(
@@ -157,9 +163,9 @@ export function getGitLabFileFetchUrl(
): Promise<string>;
// @public
export function getGitLabRequestOptions(
config: GitLabIntegrationConfig,
): RequestInit;
export function getGitLabRequestOptions(config: GitLabIntegrationConfig): {
headers: Record<string, string>;
};
// @public
export type GithubAppConfig = {
+2 -2
View File
@@ -64,8 +64,8 @@ export function getAzureCommitsUrl(url: string): string {
export function getAzureRequestOptions(
config: AzureIntegrationConfig,
additionalHeaders?: Record<string, string>,
): RequestInit {
const headers: HeadersInit = additionalHeaders
): { headers: Record<string, string> } {
const headers: Record<string, string> = additionalHeaders
? { ...additionalHeaders }
: {};
+2 -2
View File
@@ -158,8 +158,8 @@ export function getBitbucketFileFetchUrl(
*/
export function getBitbucketRequestOptions(
config: BitbucketIntegrationConfig,
): RequestInit {
const headers: HeadersInit = {};
): { headers: Record<string, string> } {
const headers: Record<string, string> = {};
if (config.token) {
headers.Authorization = `Bearer ${config.token}`;
+2 -2
View File
@@ -73,8 +73,8 @@ export function getGitHubFileFetchUrl(
export function getGitHubRequestOptions(
config: GitHubIntegrationConfig,
credentials: GithubCredentials,
): RequestInit {
const headers: HeadersInit = {};
): { headers: Record<string, string> } {
const headers: Record<string, string> = {};
if (chooseEndpoint(config, credentials) === 'api') {
headers.Accept = 'application/vnd.github.v3.raw';
+3 -3
View File
@@ -54,9 +54,9 @@ export async function getGitLabFileFetchUrl(
* @param config - The relevant provider config
* @public
*/
export function getGitLabRequestOptions(
config: GitLabIntegrationConfig,
): RequestInit {
export function getGitLabRequestOptions(config: GitLabIntegrationConfig): {
headers: Record<string, string>;
} {
const { token = '' } = config;
return {
headers: {
+1 -1
View File
@@ -65,7 +65,7 @@
"dockerode": "^3.3.1",
"fs-extra": "^9.0.1",
"http-proxy": "^1.18.1",
"react-dev-utils": "^11.0.4",
"react-dev-utils": "^12.0.0-next.47",
"serve-handler": "^6.1.3",
"winston": "^3.2.1"
}
+22
View File
@@ -1,5 +1,27 @@
# @backstage/techdocs-common
## 0.10.8
### Patch Changes
- bab752e2b3: Change default port of backend from 7000 to 7007.
This is due to the AirPlay Receiver process occupying port 7000 and preventing local Backstage instances on MacOS to start.
You can change the port back to 7000 or any other value by providing an `app-config.yaml` with the following values:
```
backend:
listen: 0.0.0.0:7123
baseUrl: http://localhost:7123
```
More information can be found here: https://backstage.io/docs/conf/writing
- Updated dependencies
- @backstage/errors@0.1.5
- @backstage/backend-common@0.9.11
## 0.10.7
### Patch Changes
+4 -4
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/techdocs-common",
"description": "Common functionalities for TechDocs, to be shared between techdocs-backend plugin and techdocs-cli",
"version": "0.10.7",
"version": "0.10.8",
"main": "src/index.ts",
"types": "src/index.ts",
"private": false,
@@ -38,10 +38,10 @@
"dependencies": {
"@azure/identity": "^1.5.0",
"@azure/storage-blob": "^12.5.0",
"@backstage/backend-common": "^0.9.10",
"@backstage/backend-common": "^0.9.11",
"@backstage/catalog-model": "^0.9.7",
"@backstage/config": "^0.1.11",
"@backstage/errors": "^0.1.4",
"@backstage/errors": "^0.1.5",
"@backstage/search-common": "^0.2.1",
"@backstage/integration": "^0.6.9",
"@google-cloud/storage": "^5.6.0",
@@ -60,7 +60,7 @@
"winston": "^3.2.1"
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
"@backstage/cli": "^0.9.1",
"@types/fs-extra": "^9.0.5",
"@types/js-yaml": "^4.0.0",
"@types/mime-types": "^2.1.0",
+67
View File
@@ -1,5 +1,72 @@
# @backstage/test-utils
## 0.1.23
### Patch Changes
- 000190de69: The `ApiRegistry` from `@backstage/core-app-api` class has been deprecated and will be removed in a future release. To replace it, we have introduced two new helpers that are exported from `@backstage/test-utils`, namely `TestApiProvider` and `TestApiRegistry`.
These two new helpers are more tailored for writing tests and development setups, as they allow for partial implementations of each of the APIs.
When migrating existing code it is typically best to prefer usage of `TestApiProvider` when possible, so for example the following code:
```tsx
render(
<ApiProvider
apis={ApiRegistry.from([
[identityApiRef, mockIdentityApi as unknown as IdentityApi]
])}
>
{...}
</ApiProvider>
)
```
Would be migrated to this:
```tsx
render(
<TestApiProvider apis={[[identityApiRef, mockIdentityApi]]}>
{...}
</TestApiProvider>
)
```
In cases where the `ApiProvider` is used in a more standalone way, for example to reuse a set of APIs across multiple tests, the `TestApiRegistry` can be used instead. Note that the `TestApiRegistry` only has a single static factory method, `.from()`, and it is slightly different from the existing `.from()` method on `ApiRegistry` in that it doesn't require the API pairs to be wrapped in an outer array.
Usage that looks like this:
```ts
const apis = ApiRegistry.with(
identityApiRef,
mockIdentityApi as unknown as IdentityApi,
).with(configApiRef, new ConfigReader({}));
```
OR like this:
```ts
const apis = ApiRegistry.from([
[identityApiRef, mockIdentityApi as unknown as IdentityApi],
[configApiRef, new ConfigReader({})],
]);
```
Would be migrated to this:
```ts
const apis = TestApiRegistry.from(
[identityApiRef, mockIdentityApi],
[configApiRef, new ConfigReader({})],
);
```
If your app is still using the `ApiRegistry` to construct the `apis` for `createApp`, we recommend that you move over to use the new method of supplying API factories instead, using `createApiFactory`.
- Updated dependencies
- @backstage/core-app-api@0.1.23
- @backstage/core-plugin-api@0.2.1
## 0.1.22
### Patch Changes
+4 -4
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/test-utils",
"description": "Utilities to test Backstage plugins and apps.",
"version": "0.1.22",
"version": "0.1.23",
"private": false,
"publishConfig": {
"access": "public",
@@ -29,8 +29,8 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/core-app-api": "^0.1.21",
"@backstage/core-plugin-api": "^0.2.0",
"@backstage/core-app-api": "^0.1.23",
"@backstage/core-plugin-api": "^0.2.1",
"@backstage/theme": "^0.2.13",
"@backstage/types": "^0.1.1",
"@material-ui/core": "^4.12.2",
@@ -46,7 +46,7 @@
"zen-observable": "^0.8.15"
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
"@backstage/cli": "^0.9.1",
"@types/jest": "^26.0.7",
"@types/node": "^14.14.32"
},
+5 -5
View File
@@ -23,8 +23,8 @@
},
"dependencies": {
"@backstage/catalog-model": "^0.9.7",
"@backstage/core-components": "^0.7.4",
"@backstage/core-plugin-api": "^0.2.0",
"@backstage/core-components": "^0.7.5",
"@backstage/core-plugin-api": "^0.2.1",
"@backstage/plugin-catalog-react": "^0.6.4",
"@backstage/theme": "^0.2.13",
"@material-ui/core": "^4.12.2",
@@ -36,10 +36,10 @@
"react-use": "^17.2.4"
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
"@backstage/core-app-api": "^0.1.22",
"@backstage/cli": "^0.9.1",
"@backstage/core-app-api": "^0.1.23",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@backstage/test-utils": "^0.1.23",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^11.2.5",
"@testing-library/user-event": "^13.1.8",
+5 -5
View File
@@ -22,8 +22,8 @@
},
"dependencies": {
"@backstage/config": "^0.1.5",
"@backstage/core-components": "^0.7.4",
"@backstage/core-plugin-api": "^0.2.0",
"@backstage/core-components": "^0.7.5",
"@backstage/core-plugin-api": "^0.2.1",
"@backstage/theme": "^0.2.13",
"@material-ui/core": "^4.12.2",
"@material-ui/icons": "^4.9.1",
@@ -34,10 +34,10 @@
"react-use": "^17.2.4"
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
"@backstage/core-app-api": "^0.1.22",
"@backstage/cli": "^0.9.1",
"@backstage/core-app-api": "^0.1.23",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@backstage/test-utils": "^0.1.23",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^11.2.5",
"@testing-library/user-event": "^13.1.8",
+9
View File
@@ -1,5 +1,14 @@
# @backstage/plugin-api-docs
## 0.6.15
### Patch Changes
- c982fc12cb: Adjusted some styles in the OpenAPI definition, for elements which were barely readable in dark mode.
- Updated dependencies
- @backstage/core-plugin-api@0.2.1
- @backstage/core-components@0.7.5
## 0.6.14
### Patch Changes
+6 -6
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/plugin-api-docs",
"description": "A Backstage plugin that helps represent API entities in the frontend",
"version": "0.6.14",
"version": "0.6.15",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -32,8 +32,8 @@
"dependencies": {
"@asyncapi/react-component": "^0.23.0",
"@backstage/catalog-model": "^0.9.7",
"@backstage/core-components": "^0.7.4",
"@backstage/core-plugin-api": "^0.2.0",
"@backstage/core-components": "^0.7.5",
"@backstage/core-plugin-api": "^0.2.1",
"@backstage/plugin-catalog": "^0.7.3",
"@backstage/plugin-catalog-react": "^0.6.4",
"@backstage/theme": "^0.2.13",
@@ -53,10 +53,10 @@
"swagger-ui-react": "^4.0.0-rc.3"
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
"@backstage/core-app-api": "^0.1.22",
"@backstage/cli": "^0.9.1",
"@backstage/core-app-api": "^0.1.23",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@backstage/test-utils": "^0.1.23",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^11.2.5",
"@testing-library/user-event": "^13.1.8",

Some files were not shown because too many files have changed in this diff Show More