({
+ id: 'y',
+});
+
+function Verifier() {
+ const holder = useApiHolder();
+ const x = holder.get(xApiRef);
+ const y = holder.get(yApiRef);
+
+ return (
+
+ {x ? (
+
+ x={x.a},{x.b}
+
+ ) : (
+ no x
+ )}
+ {y ? y={y} : no y}
+
+ );
+}
+
+describe('TestApiProvider', () => {
+ it('should provide APIs', () => {
+ render(
+
+
+ ,
+ );
+ expect(screen.getByText('x=a,3')).toBeInTheDocument();
+ expect(screen.getByText('y=y')).toBeInTheDocument();
+ });
+
+ it('should provide partial APIs', () => {
+ render(
+
+
+ ,
+ );
+ expect(screen.getByText('x=a,')).toBeInTheDocument();
+ expect(screen.getByText('no y')).toBeInTheDocument();
+ });
+
+ it('should require partial implementations to still match types', () => {
+ render(
+ // @ts-expect-error
+
+
+ ,
+ );
+ expect(screen.getByText('x=3,')).toBeInTheDocument();
+ expect(screen.getByText('no y')).toBeInTheDocument();
+ });
+
+ it('should allow empty APIs', () => {
+ render(
+
+
+ ,
+ );
+ expect(screen.getByText('no x')).toBeInTheDocument();
+ expect(screen.getByText('no y')).toBeInTheDocument();
+ });
+});
+
+describe('TestApiRegistry', () => {
+ it('should be created with APIs', () => {
+ const x = { a: 'a', b: 3 };
+ const y = 'y';
+ const registry = TestApiRegistry.from([xApiRef, x], [yApiRef, y]);
+
+ expect(registry.get(xApiRef)).toBe(x);
+ expect(registry.get(yApiRef)).toBe(y);
+ });
+
+ it('should allow partial implementations', () => {
+ const x = { a: 'a' };
+ const registry = TestApiRegistry.from([xApiRef, x]);
+
+ expect(registry.get(xApiRef)).toBe(x);
+ expect(registry.get(yApiRef)).toBeUndefined();
+ });
+
+ it('should require partial implementations to match types', () => {
+ const x = { a: 2 };
+ // @ts-expect-error
+ const registry = TestApiRegistry.from([xApiRef, x]);
+
+ expect(registry.get(xApiRef)).toBe(x);
+ expect(registry.get(yApiRef)).toBeUndefined();
+ });
+
+ it('should prefer last duplicate API that was provided', () => {
+ const x1 = { a: 'a' };
+ const x2 = { a: 's' };
+ const x3 = { a: 'd' };
+ const registry = TestApiRegistry.from(
+ [xApiRef, x1],
+ [xApiRef, x2],
+ [xApiRef, x3],
+ );
+
+ expect(registry.get(xApiRef)).toBe(x3);
+ });
+});
diff --git a/packages/test-utils/src/testUtils/TestApiProvider.tsx b/packages/test-utils/src/testUtils/TestApiProvider.tsx
new file mode 100644
index 0000000000..b1499b0cde
--- /dev/null
+++ b/packages/test-utils/src/testUtils/TestApiProvider.tsx
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * 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 React, { ReactNode } from 'react';
+import { ApiProvider } from '@backstage/core-app-api';
+import { ApiRef, ApiHolder } from '@backstage/core-plugin-api';
+
+/** @ignore */
+type TestApiProviderPropsApiPair = TApi extends infer TImpl
+ ? readonly [ApiRef, Partial]
+ : never;
+
+/** @ignore */
+type TestApiProviderPropsApiPairs = {
+ [TIndex in keyof TApiPairs]: TestApiProviderPropsApiPair;
+};
+
+/**
+ * Properties for the {@link TestApiProvider} component.
+ *
+ * @public
+ */
+export type TestApiProviderProps = {
+ apis: readonly [...TestApiProviderPropsApiPairs];
+ children: ReactNode;
+};
+
+/**
+ * The `TestApiRegistry` is an {@link @backstage/core-plugin-api#ApiHolder} implementation
+ * that is particularly well suited for development and test environments such as
+ * unit tests, storybooks, and isolated plugin development setups.
+ *
+ * @public
+ */
+export class TestApiRegistry implements ApiHolder {
+ /**
+ * Creates a new {@link TestApiRegistry} with a list of API implementation pairs.
+ *
+ * Similar to the {@link TestApiProvider}, there is no need to provide a full
+ * implementation of each API, it's enough to implement the methods that are tested.
+ *
+ * @example
+ * ```ts
+ * const apis = TestApiRegistry.from(
+ * [configApiRef, new ConfigReader({})],
+ * [identityApiRef, { getUserId: () => 'tester' }],
+ * );
+ * ```
+ *
+ * @public
+ * @param apis - A list of pairs mapping an ApiRef to its respective implementation.
+ */
+ static from(
+ ...apis: readonly [...TestApiProviderPropsApiPairs]
+ ) {
+ return new TestApiRegistry(
+ new Map(apis.map(([api, impl]) => [api.id, impl])),
+ );
+ }
+
+ private constructor(private readonly apis: Map) {}
+
+ /**
+ * Returns an implementation of the API.
+ *
+ * @public
+ */
+ get(api: ApiRef): T | undefined {
+ return this.apis.get(api.id) as T | undefined;
+ }
+}
+
+/**
+ * The `TestApiProvider` is a Utility API context provider that is particularly
+ * well suited for development and test environments such as unit tests, storybooks,
+ * and isolated plugin development setups.
+ *
+ * It lets you provide any number of API implementations, without necessarily
+ * having to fully implement each of the APIs.
+ *
+ * A migration from `ApiRegistry` and `ApiProvider` might look like this, from:
+ *
+ * ```tsx
+ * renderInTestApp(
+ *
+ * {...}
+ *
+ * )
+ * ```
+ *
+ * To the following:
+ *
+ * ```tsx
+ * renderInTestApp(
+ *
+ * {...}
+ *
+ * )
+ * ```
+ *
+ * Note that the cast to `IdentityApi` is no longer needed as long as the mock API
+ * implements a subset of the `IdentityApi`.
+ *
+ * @public
+ **/
+export const TestApiProvider = ({
+ apis,
+ children,
+}: TestApiProviderProps) => {
+ return (
+
+ );
+};
diff --git a/packages/test-utils/src/testUtils/index.tsx b/packages/test-utils/src/testUtils/index.tsx
index 7d93d606cc..c778c5c837 100644
--- a/packages/test-utils/src/testUtils/index.tsx
+++ b/packages/test-utils/src/testUtils/index.tsx
@@ -22,3 +22,5 @@ export * from './msw';
export * from './Keyboard';
export * from './logCollector';
export * from './testingLibrary';
+export { TestApiProvider, TestApiRegistry } from './TestApiProvider';
+export type { TestApiProviderProps } from './TestApiProvider';
diff --git a/plugins/allure/package.json b/plugins/allure/package.json
index 6a9a55bceb..9efe6132e8 100644
--- a/plugins/allure/package.json
+++ b/plugins/allure/package.json
@@ -37,7 +37,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/plugins/analytics-module-ga/package.json b/plugins/analytics-module-ga/package.json
index b83aed37c0..e0a32960c5 100644
--- a/plugins/analytics-module-ga/package.json
+++ b/plugins/analytics-module-ga/package.json
@@ -35,7 +35,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/plugins/api-docs/package.json b/plugins/api-docs/package.json
index 16f2d0d188..a4aa15c419 100644
--- a/plugins/api-docs/package.json
+++ b/plugins/api-docs/package.json
@@ -54,7 +54,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/plugins/auth-backend/README.md b/plugins/auth-backend/README.md
index 1fea3346a7..fe2cd05c22 100644
--- a/plugins/auth-backend/README.md
+++ b/plugins/auth-backend/README.md
@@ -34,7 +34,7 @@ Follow this link, [Create new OAuth App](https://github.com/settings/application
1. Set Application Name to `backstage-dev` or something along those lines.
1. You can set the Homepage URL to whatever you want to.
1. The Authorization Callback URL should match the redirect URI set in Backstage.
- 1. Set this to `http://localhost:7000/api/auth/github` for local development.
+ 1. Set this to `http://localhost:7007/api/auth/github` for local development.
1. Set this to `http://{APP_FQDN}:{APP_BACKEND_PORT}/api/auth/github` for non-local deployments.
```bash
@@ -58,7 +58,7 @@ Follow this link, [Add new application](https://gitlab.com/-/profile/application
1. Set Application Name to `backstage-dev` or something along those lines.
1. The Authorization Callback URL should match the redirect URI set in Backstage.
- 1. Set this to `http://localhost:7000/api/auth/gitlab/handler/frame` for local development.
+ 1. Set this to `http://localhost:7007/api/auth/gitlab/handler/frame` for local development.
1. Set this to `http://{APP_FQDN}:{APP_BACKEND_PORT}/api/auth/gitlab/handler/frame` for non-local deployments.
1. Select the following scopes from the list:
- [x] `read_user` Grants read-only access to the authenticated user's profile through the /user API endpoint, which includes username, public email, and full name. Also grants access to read-only API endpoints under /users.
@@ -91,9 +91,9 @@ export AUTH_GITLAB_CLIENT_SECRET=x
Add a new Okta application using the following URI conventions:
-Login redirect URI's: `http://localhost:7000/api/auth/okta/handler/frame`
-Logout redirect URI's: `http://localhost:7000/api/auth/okta/logout`
-Initiate login URI's: `http://localhost:7000/api/auth/okta/start`
+Login redirect URI's: `http://localhost:7007/api/auth/okta/handler/frame`
+Logout redirect URI's: `http://localhost:7007/api/auth/okta/logout`
+Initiate login URI's: `http://localhost:7007/api/auth/okta/start`
Then configure the following environment variables to be used in the `app-config.yaml` file:
@@ -122,7 +122,7 @@ Click [here](https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMe
- Give the app a name. e.g. `backstage-dev`
- Select `Accounts in this organizational directory only` under supported account types.
- Enter the callback URL for your backstage backend instance:
- - For local development, this is likely `http://localhost:7000/api/auth/microsoft/handler/frame`
+ - For local development, this is likely `http://localhost:7007/api/auth/microsoft/handler/frame`
- For non-local deployments, this will be `https://{APP_FQDN}:{APP_BACKEND_PORT}/auth/microsoft/handler/frame`
- Click `Register`.
diff --git a/plugins/auth-backend/scripts/start-saml-idp.sh b/plugins/auth-backend/scripts/start-saml-idp.sh
index b312a4b85e..e12b725191 100755
--- a/plugins/auth-backend/scripts/start-saml-idp.sh
+++ b/plugins/auth-backend/scripts/start-saml-idp.sh
@@ -18,4 +18,4 @@ fi
echo "Downloading and starting SAML-IdP"
export NPM_CONFIG_REGISTRY=https://registry.npmjs.org
-exec npx saml-idp --acsUrl "http://localhost:7000/api/auth/saml/handler/frame" --audience "http://localhost:7000" --port 7001
+exec npx saml-idp --acsUrl "http://localhost:7007/api/auth/saml/handler/frame" --audience "http://localhost:7007" --port 7001
diff --git a/plugins/auth-backend/src/lib/oauth/OAuthAdapter.test.ts b/plugins/auth-backend/src/lib/oauth/OAuthAdapter.test.ts
index dfb3a0a79a..fa61d69d80 100644
--- a/plugins/auth-backend/src/lib/oauth/OAuthAdapter.test.ts
+++ b/plugins/auth-backend/src/lib/oauth/OAuthAdapter.test.ts
@@ -176,7 +176,7 @@ describe('OAuthAdapter', () => {
const mockResponse = {
cookie: jest.fn().mockReturnThis(),
- send: jest.fn().mockReturnThis(),
+ end: jest.fn().mockReturnThis(),
status: jest.fn().mockReturnThis(),
} as unknown as express.Response;
@@ -187,6 +187,7 @@ describe('OAuthAdapter', () => {
'',
expect.objectContaining({ path: '/auth/test-provider' }),
);
+ expect(mockResponse.end).toHaveBeenCalledTimes(1);
});
it('gets new access-token when refreshing', async () => {
@@ -230,21 +231,14 @@ describe('OAuthAdapter', () => {
const mockRequest = {
header: () => 'XMLHttpRequest',
- cookies: {
- 'test-provider-refresh-token': 'token',
- },
- query: {},
} as unknown as express.Request;
- const mockResponse = {
- send: jest.fn().mockReturnThis(),
- status: jest.fn().mockReturnThis(),
- } as unknown as express.Response;
+ const mockResponse = {} as unknown as express.Response;
- await oauthProvider.refresh(mockRequest, mockResponse);
- expect(mockResponse.send).toHaveBeenCalledTimes(1);
- expect(mockResponse.send).toHaveBeenCalledWith(
- 'Refresh token not supported for provider: test-provider',
+ await expect(
+ oauthProvider.refresh(mockRequest, mockResponse),
+ ).rejects.toThrow(
+ 'Refresh token is not supported for provider test-provider',
);
});
});
diff --git a/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts b/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts
index 24b9a0f210..e1a6fdf2f9 100644
--- a/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts
+++ b/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts
@@ -22,7 +22,12 @@ import {
BackstageIdentity,
AuthProviderConfig,
} from '../../providers/types';
-import { InputError, isError, NotAllowedError } from '@backstage/errors';
+import {
+ AuthenticationError,
+ InputError,
+ isError,
+ NotAllowedError,
+} from '@backstage/errors';
import { TokenIssuer } from '../../identity/types';
import { readState, verifyNonce } from './helpers';
import { postMessageResponse, ensuresXRequestedWith } from '../flow';
@@ -166,29 +171,24 @@ export class OAuthAdapter implements AuthProviderRouteHandlers {
async logout(req: express.Request, res: express.Response): Promise {
if (!ensuresXRequestedWith(req)) {
- res.status(401).send('Invalid X-Requested-With header');
- return;
+ throw new AuthenticationError('Invalid X-Requested-With header');
}
// remove refresh token cookie if it is set
this.removeRefreshTokenCookie(res);
- res.status(200).send('logout!');
+ res.status(200).end();
}
async refresh(req: express.Request, res: express.Response): Promise {
if (!ensuresXRequestedWith(req)) {
- res.status(401).send('Invalid X-Requested-With header');
- return;
+ throw new AuthenticationError('Invalid X-Requested-With header');
}
if (!this.handlers.refresh || this.options.disableRefresh) {
- res
- .status(400)
- .send(
- `Refresh token not supported for provider: ${this.options.providerId}`,
- );
- return;
+ throw new InputError(
+ `Refresh token is not supported for provider ${this.options.providerId}`,
+ );
}
try {
@@ -197,7 +197,7 @@ export class OAuthAdapter implements AuthProviderRouteHandlers {
// throw error if refresh token is missing in the request
if (!refreshToken) {
- throw new Error('Missing session cookie');
+ throw new InputError('Missing session cookie');
}
const scope = req.query.scope?.toString() ?? '';
@@ -220,7 +220,7 @@ export class OAuthAdapter implements AuthProviderRouteHandlers {
res.status(200).json(response);
} catch (error) {
- res.status(401).send(String(error));
+ throw new AuthenticationError('Refresh failed', error);
}
}
diff --git a/plugins/auth-backend/src/lib/oauth/OAuthEnvironmentHandler.ts b/plugins/auth-backend/src/lib/oauth/OAuthEnvironmentHandler.ts
index a2f427e741..95a0547a5e 100644
--- a/plugins/auth-backend/src/lib/oauth/OAuthEnvironmentHandler.ts
+++ b/plugins/auth-backend/src/lib/oauth/OAuthEnvironmentHandler.ts
@@ -16,7 +16,7 @@
import express from 'express';
import { Config } from '@backstage/config';
-import { InputError } from '@backstage/errors';
+import { InputError, NotFoundError } from '@backstage/errors';
import { readState } from './helpers';
import { AuthProviderRouteHandlers } from '../../providers/types';
@@ -42,26 +42,26 @@ export class OAuthEnvironmentHandler implements AuthProviderRouteHandlers {
) {}
async start(req: express.Request, res: express.Response): Promise {
- const provider = this.getProviderForEnv(req, res);
- await provider?.start(req, res);
+ const provider = this.getProviderForEnv(req);
+ await provider.start(req, res);
}
async frameHandler(
req: express.Request,
res: express.Response,
): Promise {
- const provider = this.getProviderForEnv(req, res);
- await provider?.frameHandler(req, res);
+ const provider = this.getProviderForEnv(req);
+ await provider.frameHandler(req, res);
}
async refresh(req: express.Request, res: express.Response): Promise {
- const provider = this.getProviderForEnv(req, res);
- await provider?.refresh?.(req, res);
+ const provider = this.getProviderForEnv(req);
+ await provider.refresh?.(req, res);
}
async logout(req: express.Request, res: express.Response): Promise {
- const provider = this.getProviderForEnv(req, res);
- await provider?.logout?.(req, res);
+ const provider = this.getProviderForEnv(req);
+ await provider.logout?.(req, res);
}
private getRequestFromEnv(req: express.Request): string | undefined {
@@ -77,26 +77,20 @@ export class OAuthEnvironmentHandler implements AuthProviderRouteHandlers {
return env;
}
- private getProviderForEnv(
- req: express.Request,
- res: express.Response,
- ): AuthProviderRouteHandlers | undefined {
+ private getProviderForEnv(req: express.Request): AuthProviderRouteHandlers {
const env: string | undefined = this.getRequestFromEnv(req);
if (!env) {
throw new InputError(`Must specify 'env' query to select environment`);
}
- if (!this.handlers.has(env)) {
- res.status(404).send(
- `Missing configuration.
-
-
- For this flow to work you need to supply a valid configuration for the "${env}" environment of provider.`,
+ const handler = this.handlers.get(env);
+ if (!handler) {
+ throw new NotFoundError(
+ `No configuration available for the '${env}' environment of this provider.`,
);
- return undefined;
}
- return this.handlers.get(env);
+ return handler;
}
}
diff --git a/plugins/azure-devops-backend/README.md b/plugins/azure-devops-backend/README.md
index 6101794cd1..79db9f5ff1 100644
--- a/plugins/azure-devops-backend/README.md
+++ b/plugins/azure-devops-backend/README.md
@@ -63,7 +63,7 @@ Here's how to get the backend up and running:
```
4. Now run `yarn start-backend` from the repo root
-5. Finally open `http://localhost:7000/api/azure-devops/health` in a browser and it should return `{"status":"ok"}`
+5. Finally open `http://localhost:7007/api/azure-devops/health` in a browser and it should return `{"status":"ok"}`
## Links
diff --git a/plugins/azure-devops-backend/src/run.ts b/plugins/azure-devops-backend/src/run.ts
index addfdfd6d7..53d4e4334a 100644
--- a/plugins/azure-devops-backend/src/run.ts
+++ b/plugins/azure-devops-backend/src/run.ts
@@ -18,7 +18,7 @@ import { getRootLogger } from '@backstage/backend-common';
import yn from 'yn';
import { startStandaloneServer } from './service/standaloneServer';
-const port = process.env.PLUGIN_PORT ? Number(process.env.PLUGIN_PORT) : 7000;
+const port = process.env.PLUGIN_PORT ? Number(process.env.PLUGIN_PORT) : 7007;
const enableCors = yn(process.env.PLUGIN_CORS, { default: false });
const logger = getRootLogger();
diff --git a/plugins/azure-devops/README.md b/plugins/azure-devops/README.md
index f33bd3bdb6..7b39dae443 100644
--- a/plugins/azure-devops/README.md
+++ b/plugins/azure-devops/README.md
@@ -84,7 +84,7 @@ To get the Azure Pipelines component working you'll need to do the following two
**Notes:**
- The `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 annotation
-- The `defaultLimit` proper on the `EntityAzurePipelinesContent` will set the max number of Builds you would like to see, if not set this will default to 10
+- The `defaultLimit` property on the `EntityAzurePipelinesContent` will set the max number of Builds you would like to see, if not set this will default to 10
### Azure Repos Component
@@ -98,12 +98,12 @@ To get the Azure Repos component working you'll need to do the following two ste
yarn add @backstage/plugin-azure-devops
```
-2. Second we need to add the `EntityAzureReposContent` extension to the entity page in your app:
+2. Second we need to add the `EntityAzurePullRequestsContent` extension to the entity page in your app:
```tsx
// In packages/app/src/components/catalog/EntityPage.tsx
import {
- EntityAzureReposContent,
+ EntityAzurePullRequestsContent,
isAzureDevOpsAvailable,
} from '@backstage/plugin-azure-devops';
@@ -112,7 +112,7 @@ To get the Azure Repos component working you'll need to do the following two ste
// ...
-
+
// ...
@@ -122,7 +122,7 @@ To get the Azure Repos component working you'll need to do the following two ste
- You'll need to add the `EntityLayout.Route` above from step 2 to all the entity sections you want to see Pull Requests in. For example if you wanted to see Pull Requests when looking at Website entities then you would need to add this to the `websiteEntityPage` section.
- The `if` prop is optional on the `EntityLayout.Route`, you can remove it if you always want to see the tab even if the entity being viewed does not have the needed annotation
-- The `defaultLimit` proper on the `EntityAzureReposContent` will set the max number of Pull Requests you would like to see, if not set this will default to 10
+- The `defaultLimit` property on the `EntityAzurePullRequestsContent` will set the max number of Pull Requests you would like to see, if not set this will default to 10
## Limitations
diff --git a/plugins/azure-devops/package.json b/plugins/azure-devops/package.json
index 0642a24cac..9d235b0641 100644
--- a/plugins/azure-devops/package.json
+++ b/plugins/azure-devops/package.json
@@ -46,7 +46,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/plugins/badges-backend/src/run.ts b/plugins/badges-backend/src/run.ts
index addfdfd6d7..53d4e4334a 100644
--- a/plugins/badges-backend/src/run.ts
+++ b/plugins/badges-backend/src/run.ts
@@ -18,7 +18,7 @@ import { getRootLogger } from '@backstage/backend-common';
import yn from 'yn';
import { startStandaloneServer } from './service/standaloneServer';
-const port = process.env.PLUGIN_PORT ? Number(process.env.PLUGIN_PORT) : 7000;
+const port = process.env.PLUGIN_PORT ? Number(process.env.PLUGIN_PORT) : 7007;
const enableCors = yn(process.env.PLUGIN_CORS, { default: false });
const logger = getRootLogger();
diff --git a/plugins/badges-backend/src/service/router.test.ts b/plugins/badges-backend/src/service/router.test.ts
index 51ad1e7e11..286a2335f1 100644
--- a/plugins/badges-backend/src/service/router.test.ts
+++ b/plugins/badges-backend/src/service/router.test.ts
@@ -73,7 +73,7 @@ describe('createRouter', () => {
config = new ConfigReader({
backend: {
baseUrl: 'http://127.0.0.1',
- listen: { port: 7000 },
+ listen: { port: 7007 },
},
});
discovery = SingleHostDiscovery.fromConfig(config);
diff --git a/plugins/badges/package.json b/plugins/badges/package.json
index dcc422ec19..4d02d64237 100644
--- a/plugins/badges/package.json
+++ b/plugins/badges/package.json
@@ -43,7 +43,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/plugins/bazaar-backend/src/run.ts b/plugins/bazaar-backend/src/run.ts
index 54d2716290..0a3ed2b7f0 100644
--- a/plugins/bazaar-backend/src/run.ts
+++ b/plugins/bazaar-backend/src/run.ts
@@ -18,7 +18,7 @@ import { getRootLogger } from '@backstage/backend-common';
import yn from 'yn';
import { startStandaloneServer } from './service/standaloneServer';
-const port = process.env.PLUGIN_PORT ? Number(process.env.PLUGIN_PORT) : 7000;
+const port = process.env.PLUGIN_PORT ? Number(process.env.PLUGIN_PORT) : 7007;
const enableCors = yn(process.env.PLUGIN_CORS, { default: false });
const logger = getRootLogger();
diff --git a/plugins/bitrise/package.json b/plugins/bitrise/package.json
index 28a3c88ad1..92cd9693e1 100644
--- a/plugins/bitrise/package.json
+++ b/plugins/bitrise/package.json
@@ -40,7 +40,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/plugins/catalog-backend/api-report.md b/plugins/catalog-backend/api-report.md
index abea100aae..f37132109d 100644
--- a/plugins/catalog-backend/api-report.md
+++ b/plugins/catalog-backend/api-report.md
@@ -852,8 +852,7 @@ export type EntitiesResponse = {
// @public
export type EntitiesSearchFilter = {
key: string;
- matchValueIn?: string[];
- matchValueExists?: boolean;
+ values?: string[];
};
// Warning: (ae-missing-release-tag) "entity" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
@@ -883,6 +882,9 @@ export type EntityFilter =
| {
anyOf: EntityFilter[];
}
+ | {
+ not: EntityFilter;
+ }
| EntitiesSearchFilter;
// Warning: (ae-missing-release-tag) "EntityPagination" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
@@ -1552,9 +1554,9 @@ export class UrlReaderProcessor implements CatalogProcessor {
// Warnings were encountered during analysis:
//
-// src/catalog/types.d.ts:97:8 - (tsdoc-param-tag-with-invalid-name) The @param block should be followed by a valid parameter name: The identifier cannot non-word characters
-// src/catalog/types.d.ts:98:8 - (tsdoc-param-tag-with-invalid-name) The @param block should be followed by a valid parameter name: The identifier cannot non-word characters
-// src/catalog/types.d.ts:99:8 - (tsdoc-param-tag-with-invalid-name) The @param block should be followed by a valid parameter name: The identifier cannot non-word characters
+// src/catalog/types.d.ts:94:8 - (tsdoc-param-tag-with-invalid-name) The @param block should be followed by a valid parameter name: The identifier cannot non-word characters
+// src/catalog/types.d.ts:95:8 - (tsdoc-param-tag-with-invalid-name) The @param block should be followed by a valid parameter name: The identifier cannot non-word characters
+// src/catalog/types.d.ts:96:8 - (tsdoc-param-tag-with-invalid-name) The @param block should be followed by a valid parameter name: The identifier cannot non-word characters
// src/ingestion/processors/GithubMultiOrgReaderProcessor.d.ts:23:9 - (ae-forgotten-export) The symbol "GithubMultiOrgConfig" needs to be exported by the entry point index.d.ts
// src/ingestion/types.d.ts:8:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
// src/legacy/database/types.d.ts:98:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
diff --git a/plugins/catalog-backend/src/catalog/types.ts b/plugins/catalog-backend/src/catalog/types.ts
index df693bfd42..2a18783679 100644
--- a/plugins/catalog-backend/src/catalog/types.ts
+++ b/plugins/catalog-backend/src/catalog/types.ts
@@ -25,6 +25,7 @@ import { Entity, EntityRelationSpec } from '@backstage/catalog-model';
export type EntityFilter =
| { allOf: EntityFilter[] }
| { anyOf: EntityFilter[] }
+ | { not: EntityFilter }
| EntitiesSearchFilter;
/**
@@ -50,16 +51,10 @@ export type EntitiesSearchFilter = {
/**
* Match on plain equality of values.
*
- * If undefined, this factor is not taken into account. Otherwise, match on
- * values that are equal to any of the given array items. Matches are always
- * case insensitive.
+ * Match on values that are equal to any of the given array items. Matches are
+ * always case insensitive.
*/
- matchValueIn?: string[];
-
- /**
- * Match on existence of key.
- */
- matchValueExists?: boolean;
+ values?: string[];
};
export type PageInfo =
diff --git a/plugins/catalog-backend/src/legacy/database/CommonDatabase.test.ts b/plugins/catalog-backend/src/legacy/database/CommonDatabase.test.ts
index ca2e6c2934..8b72b470a6 100644
--- a/plugins/catalog-backend/src/legacy/database/CommonDatabase.test.ts
+++ b/plugins/catalog-backend/src/legacy/database/CommonDatabase.test.ts
@@ -536,9 +536,7 @@ describe('CommonDatabase', () => {
filter: {
anyOf: [
{
- allOf: [
- { key: 'metadata.annotations.foo', matchValueExists: true },
- ],
+ allOf: [{ key: 'metadata.annotations.foo' }],
},
],
},
@@ -558,30 +556,6 @@ describe('CommonDatabase', () => {
},
]),
);
-
- const nonExistRows = await db.transaction(async tx =>
- db.entities(tx, {
- filter: {
- anyOf: [
- {
- allOf: [
- { key: 'metadata.annotations.foo', matchValueExists: false },
- ],
- },
- ],
- },
- }),
- );
-
- expect(nonExistRows.entities.length).toEqual(1);
- expect(nonExistRows.entities).toEqual(
- expect.arrayContaining([
- {
- locationId: undefined,
- entity: expect.objectContaining({ kind: 'k3' }),
- },
- ]),
- );
});
});
diff --git a/plugins/catalog-backend/src/legacy/database/CommonDatabase.ts b/plugins/catalog-backend/src/legacy/database/CommonDatabase.ts
index 6a150f7583..3ea8696437 100644
--- a/plugins/catalog-backend/src/legacy/database/CommonDatabase.ts
+++ b/plugins/catalog-backend/src/legacy/database/CommonDatabase.ts
@@ -224,7 +224,8 @@ export class CommonDatabase implements Database {
if (
request?.filter &&
(request.filter.hasOwnProperty('key') ||
- request.filter.hasOwnProperty('allOf'))
+ request.filter.hasOwnProperty('allOf') ||
+ request.filter.hasOwnProperty('not'))
) {
throw new Error(
'Filters for the legacy CommonDatabase must obey the { anyOf: [{ allOf: [] }] } format.',
@@ -236,13 +237,14 @@ export class CommonDatabase implements Database {
for (const filter of singleFilter.allOf) {
if (
filter.hasOwnProperty('anyOf') ||
- filter.hasOwnProperty('allOf')
+ filter.hasOwnProperty('allOf') ||
+ filter.hasOwnProperty('not')
) {
throw new Error(
'Nested filters are not supported in the legacy CommonDatabase',
);
}
- const { key, matchValueIn, matchValueExists } = filter;
+ const { key, values } = filter;
// NOTE(freben): This used to be a set of OUTER JOIN, which may seem to
// make a lot of sense. However, it had abysmal performance on sqlite
// when datasets grew large, so we're using IN instead.
@@ -250,24 +252,19 @@ export class CommonDatabase implements Database {
.select('entity_id')
.where(function keyFilter() {
this.andWhere({ key: key.toLowerCase() });
- if (matchValueExists !== false && matchValueIn) {
- if (matchValueIn.length === 1) {
- this.andWhere({ value: matchValueIn[0].toLowerCase() });
- } else if (matchValueIn.length > 1) {
+ if (values) {
+ if (values.length === 1) {
+ this.andWhere({ value: values[0].toLowerCase() });
+ } else if (values.length > 1) {
this.andWhere(
'value',
'in',
- matchValueIn.map(v => v.toLowerCase()),
+ values.map(v => v.toLowerCase()),
);
}
}
});
- // Explicitly evaluate matchValueExists as a boolean since it may be undefined
- this.andWhere(
- 'id',
- matchValueExists === false ? 'not in' : 'in',
- matchQuery,
- );
+ this.andWhere('id', 'in', matchQuery);
}
});
}
diff --git a/plugins/catalog-backend/src/legacy/service/router.test.ts b/plugins/catalog-backend/src/legacy/service/router.test.ts
index edc7d852ac..0ff5a44ed0 100644
--- a/plugins/catalog-backend/src/legacy/service/router.test.ts
+++ b/plugins/catalog-backend/src/legacy/service/router.test.ts
@@ -115,11 +115,11 @@ describe('createRouter readonly disabled', () => {
anyOf: [
{
allOf: [
- { key: 'a', matchValueIn: ['1', '2'] },
- { key: 'b', matchValueIn: ['3'] },
+ { key: 'a', values: ['1', '2'] },
+ { key: 'b', values: ['3'] },
],
},
- { allOf: [{ key: 'c', matchValueIn: ['4'] }] },
+ { allOf: [{ key: 'c', values: ['4'] }] },
],
},
});
diff --git a/plugins/catalog-backend/src/run.ts b/plugins/catalog-backend/src/run.ts
index 54d2716290..0a3ed2b7f0 100644
--- a/plugins/catalog-backend/src/run.ts
+++ b/plugins/catalog-backend/src/run.ts
@@ -18,7 +18,7 @@ import { getRootLogger } from '@backstage/backend-common';
import yn from 'yn';
import { startStandaloneServer } from './service/standaloneServer';
-const port = process.env.PLUGIN_PORT ? Number(process.env.PLUGIN_PORT) : 7000;
+const port = process.env.PLUGIN_PORT ? Number(process.env.PLUGIN_PORT) : 7007;
const enableCors = yn(process.env.PLUGIN_CORS, { default: false });
const logger = getRootLogger();
diff --git a/plugins/catalog-backend/src/search/DefaultCatalogCollator.test.ts b/plugins/catalog-backend/src/search/DefaultCatalogCollator.test.ts
index 49235584e1..9f42c7de83 100644
--- a/plugins/catalog-backend/src/search/DefaultCatalogCollator.test.ts
+++ b/plugins/catalog-backend/src/search/DefaultCatalogCollator.test.ts
@@ -63,7 +63,7 @@ describe('DefaultCatalogCollator', () => {
beforeAll(() => {
mockDiscoveryApi = {
- getBaseUrl: jest.fn().mockResolvedValue('http://localhost:7000'),
+ getBaseUrl: jest.fn().mockResolvedValue('http://localhost:7007'),
getExternalBaseUrl: jest.fn(),
};
mockTokenManager = {
@@ -78,7 +78,7 @@ describe('DefaultCatalogCollator', () => {
});
beforeEach(() => {
server.use(
- rest.get('http://localhost:7000/entities', (req, res, ctx) => {
+ rest.get('http://localhost:7007/entities', (req, res, ctx) => {
if (req.url.searchParams.has('filter')) {
const filter = req.url.searchParams.get('filter');
if (filter === 'kind=Foo,kind=Bar') {
diff --git a/plugins/catalog-backend/src/search/DefaultCatalogCollator.ts b/plugins/catalog-backend/src/search/DefaultCatalogCollator.ts
index 36ba59ad2e..6bef785ac8 100644
--- a/plugins/catalog-backend/src/search/DefaultCatalogCollator.ts
+++ b/plugins/catalog-backend/src/search/DefaultCatalogCollator.ts
@@ -18,7 +18,7 @@ import {
PluginEndpointDiscovery,
TokenManager,
} from '@backstage/backend-common';
-import { Entity } from '@backstage/catalog-model';
+import { Entity, UserEntity } from '@backstage/catalog-model';
import { IndexableDocument, DocumentCollator } from '@backstage/search-common';
import { Config } from '@backstage/config';
import {
@@ -89,6 +89,24 @@ export class DefaultCatalogCollator implements DocumentCollator {
return formatted.toLowerCase();
}
+ private isUserEntity(entity: Entity): entity is UserEntity {
+ return entity.kind.toLocaleUpperCase('en-US') === 'USER';
+ }
+
+ private getDocumentText(entity: Entity): string {
+ let documentText = entity.metadata.description || '';
+ if (this.isUserEntity(entity)) {
+ if (entity.spec?.profile?.displayName && documentText) {
+ // combine displayName and description
+ const displayName = entity.spec?.profile?.displayName;
+ documentText = displayName.concat(' : ', documentText);
+ } else {
+ documentText = entity.spec?.profile?.displayName || documentText;
+ }
+ }
+ return documentText;
+ }
+
async execute() {
const { token } = await this.tokenManager.getServerToken();
const response = await this.catalogClient.getEntities(
@@ -105,7 +123,7 @@ export class DefaultCatalogCollator implements DocumentCollator {
kind: entity.kind,
name: entity.metadata.name,
}),
- text: entity.metadata.description || '',
+ text: this.getDocumentText(entity),
componentType: entity.spec?.type?.toString() || 'other',
namespace: entity.metadata.namespace || 'default',
kind: entity.kind,
diff --git a/plugins/catalog-backend/src/service/NextEntitiesCatalog.test.ts b/plugins/catalog-backend/src/service/NextEntitiesCatalog.test.ts
index 32d5fa843e..ee86e78c6b 100644
--- a/plugins/catalog-backend/src/service/NextEntitiesCatalog.test.ts
+++ b/plugins/catalog-backend/src/service/NextEntitiesCatalog.test.ts
@@ -282,7 +282,6 @@ describe('NextEntitiesCatalog', () => {
const testFilter = {
key: 'spec.test',
- matchValueExists: true,
};
const request = { filter: testFilter };
const { entities } = await catalog.entities(request);
@@ -293,7 +292,42 @@ describe('NextEntitiesCatalog', () => {
);
it.each(databases.eachSupportedId())(
- 'should return correct entity for nested filter',
+ 'should return correct entity for negation filter',
+ async databaseId => {
+ const { knex } = await createDatabase(databaseId);
+ const entity1: Entity = {
+ apiVersion: 'a',
+ kind: 'k',
+ metadata: { name: 'one' },
+ spec: {},
+ };
+ const entity2: Entity = {
+ apiVersion: 'a',
+ kind: 'k',
+ metadata: { name: 'two' },
+ spec: {
+ test: 'test value',
+ },
+ };
+ await addEntityToSearch(knex, entity1);
+ await addEntityToSearch(knex, entity2);
+ const catalog = new NextEntitiesCatalog(knex);
+
+ const testFilter = {
+ not: {
+ key: 'spec.test',
+ },
+ };
+ const request = { filter: testFilter };
+ const { entities } = await catalog.entities(request);
+
+ expect(entities.length).toBe(1);
+ expect(entities[0]).toEqual(entity1);
+ },
+ );
+
+ it.each(databases.eachSupportedId())(
+ 'should return correct entities for nested filter',
async databaseId => {
const { knex } = await createDatabase(databaseId);
const entity1: Entity = {
@@ -328,24 +362,27 @@ describe('NextEntitiesCatalog', () => {
const testFilter1 = {
key: 'metadata.org',
- matchValueExists: true,
- matchValueIn: ['b'],
+ values: ['b'],
};
const testFilter2 = {
key: 'metadata.desc',
- matchValueExists: true,
};
const testFilter3 = {
key: 'metadata.color',
- matchValueExists: true,
- matchValueIn: ['blue'],
+ values: ['blue'],
+ };
+ const testFilter4 = {
+ not: {
+ key: 'metadata.color',
+ values: ['red'],
+ },
};
const request = {
filter: {
allOf: [
testFilter1,
{
- anyOf: [testFilter2, testFilter3],
+ anyOf: [testFilter2, testFilter3, testFilter4],
},
],
},
@@ -357,5 +394,46 @@ describe('NextEntitiesCatalog', () => {
expect(entities).toContainEqual(entity4);
},
);
+
+ it.each(databases.eachSupportedId())(
+ 'should return correct entities for complex negation filter',
+ async databaseId => {
+ const { knex } = await createDatabase(databaseId);
+ const entity1: Entity = {
+ apiVersion: 'a',
+ kind: 'k',
+ metadata: { name: 'one', org: 'a', desc: 'description' },
+ spec: {},
+ };
+ const entity2: Entity = {
+ apiVersion: 'a',
+ kind: 'k',
+ metadata: { name: 'two', org: 'b', desc: 'description' },
+ spec: {},
+ };
+ await addEntityToSearch(knex, entity1);
+ await addEntityToSearch(knex, entity2);
+ const catalog = new NextEntitiesCatalog(knex);
+
+ const testFilter1 = {
+ key: 'metadata.org',
+ values: ['b'],
+ };
+ const testFilter2 = {
+ key: 'metadata.desc',
+ };
+ const request = {
+ filter: {
+ not: {
+ allOf: [testFilter1, testFilter2],
+ },
+ },
+ };
+ const { entities } = await catalog.entities(request);
+
+ expect(entities.length).toBe(1);
+ expect(entities).toContainEqual(entity1);
+ },
+ );
});
});
diff --git a/plugins/catalog-backend/src/service/NextEntitiesCatalog.ts b/plugins/catalog-backend/src/service/NextEntitiesCatalog.ts
index 1c615f862a..8c2de9d7c1 100644
--- a/plugins/catalog-backend/src/service/NextEntitiesCatalog.ts
+++ b/plugins/catalog-backend/src/service/NextEntitiesCatalog.ts
@@ -78,33 +78,29 @@ function stringifyPagination(input: { limit: number; offset: number }) {
function addCondition(
queryBuilder: Knex.QueryBuilder,
db: Knex,
- { key, matchValueIn, matchValueExists }: EntitiesSearchFilter,
+ filter: EntitiesSearchFilter,
+ negate: boolean = false,
) {
// NOTE(freben): This used to be a set of OUTER JOIN, which may seem to
// make a lot of sense. However, it had abysmal performance on sqlite
// when datasets grew large, so we're using IN instead.
const matchQuery = db('search')
.select('entity_id')
- .where(function keyFilter() {
- this.andWhere({ key: key.toLowerCase() });
- if (matchValueExists !== false && matchValueIn) {
- if (matchValueIn.length === 1) {
- this.andWhere({ value: matchValueIn[0].toLowerCase() });
- } else if (matchValueIn.length > 1) {
+ .where({ key: filter.key.toLowerCase() })
+ .andWhere(function keyFilter() {
+ if (filter.values) {
+ if (filter.values.length === 1) {
+ this.where({ value: filter.values[0].toLowerCase() });
+ } else if (filter.values.length > 1) {
this.andWhere(
'value',
'in',
- matchValueIn.map(v => v.toLowerCase()),
+ filter.values.map(v => v.toLowerCase()),
);
}
}
});
- // Explicitly evaluate matchValueExists as a boolean since it may be undefined
- queryBuilder.andWhere(
- 'entity_id',
- matchValueExists === false ? 'not in' : 'in',
- matchQuery,
- );
+ queryBuilder.andWhere('entity_id', negate ? 'not in' : 'in', matchQuery);
}
function isEntitiesSearchFilter(
@@ -113,46 +109,45 @@ function isEntitiesSearchFilter(
return filter.hasOwnProperty('key');
}
-function isAndEntityFilter(
- filter: { allOf: EntityFilter[] } | EntityFilter,
-): filter is { allOf: EntityFilter[] } {
- return filter.hasOwnProperty('allOf');
-}
-
function isOrEntityFilter(
filter: { anyOf: EntityFilter[] } | EntityFilter,
): filter is { anyOf: EntityFilter[] } {
return filter.hasOwnProperty('anyOf');
}
+function isNegationEntityFilter(
+ filter: { not: EntityFilter } | EntityFilter,
+): filter is { not: EntityFilter } {
+ return filter.hasOwnProperty('not');
+}
+
function parseFilter(
filter: EntityFilter,
query: Knex.QueryBuilder,
db: Knex,
+ negate: boolean = false,
): Knex.QueryBuilder {
if (isEntitiesSearchFilter(filter)) {
return query.andWhere(function filterFunction() {
- addCondition(this, db, filter);
+ addCondition(this, db, filter, negate);
});
}
- if (isOrEntityFilter(filter)) {
- return query.andWhere(function filterFunction() {
+ if (isNegationEntityFilter(filter)) {
+ return parseFilter(filter.not, query, db, !negate);
+ }
+
+ return query[negate ? 'andWhereNot' : 'andWhere'](function filterFunction() {
+ if (isOrEntityFilter(filter)) {
for (const subFilter of filter.anyOf ?? []) {
this.orWhere(subQuery => parseFilter(subFilter, subQuery, db));
}
- });
- }
-
- if (isAndEntityFilter(filter)) {
- return query.andWhere(function filterFunction() {
+ } else {
for (const subFilter of filter.allOf ?? []) {
this.andWhere(subQuery => parseFilter(subFilter, subQuery, db));
}
- });
- }
-
- return query;
+ }
+ });
}
export class NextEntitiesCatalog implements EntitiesCatalog {
diff --git a/plugins/catalog-backend/src/service/NextRouter.test.ts b/plugins/catalog-backend/src/service/NextRouter.test.ts
index 57911c74fb..6bc4481425 100644
--- a/plugins/catalog-backend/src/service/NextRouter.test.ts
+++ b/plugins/catalog-backend/src/service/NextRouter.test.ts
@@ -104,11 +104,11 @@ describe('createNextRouter readonly disabled', () => {
anyOf: [
{
allOf: [
- { key: 'a', matchValueIn: ['1', '2'] },
- { key: 'b', matchValueIn: ['3'] },
+ { key: 'a', values: ['1', '2'] },
+ { key: 'b', values: ['3'] },
],
},
- { allOf: [{ key: 'c', matchValueIn: ['4'] }] },
+ { allOf: [{ key: 'c', values: ['4'] }] },
],
},
});
diff --git a/plugins/catalog-backend/src/service/request/basicEntityFilter.ts b/plugins/catalog-backend/src/service/request/basicEntityFilter.ts
index 1cf9ca95f0..36448e0304 100644
--- a/plugins/catalog-backend/src/service/request/basicEntityFilter.ts
+++ b/plugins/catalog-backend/src/service/request/basicEntityFilter.ts
@@ -30,9 +30,9 @@ export function basicEntityFilter(
const f =
key in filtersByKey
? filtersByKey[key]
- : (filtersByKey[key] = { key, matchValueIn: [] });
+ : (filtersByKey[key] = { key, values: [] });
- f.matchValueIn!.push(...values);
+ f.values!.push(...values);
}
return { anyOf: [{ allOf: Object.values(filtersByKey) }] };
diff --git a/plugins/catalog-backend/src/service/request/parseEntityFilterParams.test.ts b/plugins/catalog-backend/src/service/request/parseEntityFilterParams.test.ts
index fc22a638de..f9fc596cb9 100644
--- a/plugins/catalog-backend/src/service/request/parseEntityFilterParams.test.ts
+++ b/plugins/catalog-backend/src/service/request/parseEntityFilterParams.test.ts
@@ -28,7 +28,7 @@ describe('parseEntityFilterParams', () => {
it('supports single-string format', () => {
const result = parseEntityFilterParams({ filter: 'a=1' })!;
expect(result).toEqual({
- anyOf: [{ allOf: [{ key: 'a', matchValueIn: ['1'] }] }],
+ anyOf: [{ allOf: [{ key: 'a', values: ['1'] }] }],
});
});
@@ -38,8 +38,8 @@ describe('parseEntityFilterParams', () => {
});
expect(result).toEqual({
anyOf: [
- { allOf: [{ key: 'a', matchValueIn: ['1'] }] },
- { allOf: [{ key: 'b', matchValueIn: ['2'] }] },
+ { allOf: [{ key: 'a', values: ['1'] }] },
+ { allOf: [{ key: 'b', values: ['2'] }] },
],
});
});
@@ -50,11 +50,11 @@ describe('parseEntityFilterParams', () => {
});
expect(result).toEqual({
anyOf: [
- { allOf: [{ key: 'a', matchValueIn: ['1'] }] },
+ { allOf: [{ key: 'a', values: ['1'] }] },
{
allOf: [
- { key: 'b', matchValueIn: ['2', '3'] },
- { key: 'c', matchValueIn: ['4'] },
+ { key: 'b', values: ['2', '3'] },
+ { key: 'c', values: ['4'] },
],
},
],
@@ -70,17 +70,17 @@ describe('parseEntityFilterString', () => {
it('works for the happy path', () => {
expect(parseEntityFilterString('')).toBeUndefined();
expect(parseEntityFilterString('a=1,b=2,a=3,c,d=')).toEqual([
- { key: 'a', matchValueIn: ['1', '3'] },
- { key: 'b', matchValueIn: ['2'] },
- { key: 'c', matchValueExists: true },
- { key: 'd', matchValueIn: [''] },
+ { key: 'a', values: ['1', '3'] },
+ { key: 'b', values: ['2'] },
+ { key: 'c' },
+ { key: 'd', values: [''] },
]);
});
it('trims values', () => {
expect(parseEntityFilterString(' a = 1 , b = 2 , a = 3 ')).toEqual([
- { key: 'a', matchValueIn: ['1', '3'] },
- { key: 'b', matchValueIn: ['2'] },
+ { key: 'a', values: ['1', '3'] },
+ { key: 'b', values: ['2'] },
]);
});
diff --git a/plugins/catalog-backend/src/service/request/parseEntityFilterParams.ts b/plugins/catalog-backend/src/service/request/parseEntityFilterParams.ts
index 452958b7ae..1ea5d44b2c 100644
--- a/plugins/catalog-backend/src/service/request/parseEntityFilterParams.ts
+++ b/plugins/catalog-backend/src/service/request/parseEntityFilterParams.ts
@@ -75,11 +75,9 @@ export function parseEntityFilterString(
const f =
key in filtersByKey ? filtersByKey[key] : (filtersByKey[key] = { key });
- if (value === undefined) {
- f.matchValueExists = true;
- } else {
- f.matchValueIn = f.matchValueIn || [];
- f.matchValueIn.push(value);
+ if (value !== undefined) {
+ f.values = f.values || [];
+ f.values.push(value);
}
}
diff --git a/plugins/catalog-graph/package.json b/plugins/catalog-graph/package.json
index 53fde11c7b..13869cfd38 100644
--- a/plugins/catalog-graph/package.json
+++ b/plugins/catalog-graph/package.json
@@ -42,7 +42,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/plugins/catalog-import/package.json b/plugins/catalog-import/package.json
index bd7f99c884..933a84f13e 100644
--- a/plugins/catalog-import/package.json
+++ b/plugins/catalog-import/package.json
@@ -56,7 +56,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json
index 254718bd3c..ddee20c488 100644
--- a/plugins/catalog/package.json
+++ b/plugins/catalog/package.json
@@ -52,7 +52,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/plugins/circleci/package.json b/plugins/circleci/package.json
index d7cd3b0fd2..7228044f4f 100644
--- a/plugins/circleci/package.json
+++ b/plugins/circleci/package.json
@@ -53,7 +53,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/plugins/cloudbuild/package.json b/plugins/cloudbuild/package.json
index 32b860ec23..4125a8c82e 100644
--- a/plugins/cloudbuild/package.json
+++ b/plugins/cloudbuild/package.json
@@ -50,7 +50,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/plugins/code-coverage-backend/README.md b/plugins/code-coverage-backend/README.md
index 101bee3e3f..4cfc187a3d 100644
--- a/plugins/code-coverage-backend/README.md
+++ b/plugins/code-coverage-backend/README.md
@@ -31,11 +31,11 @@ POST a Cobertura XML file to `/report`
Example:
```json
-// curl -X POST -H "Content-Type:text/xml" -d @cobertura.xml "localhost:7000/api/code-coverage/report?entity=component:default/entity-name&coverageType=cobertura"
+// curl -X POST -H "Content-Type:text/xml" -d @cobertura.xml "localhost:7007/api/code-coverage/report?entity=component:default/entity-name&coverageType=cobertura"
{
"links": [
{
- "href": "http://localhost:7000/api/code-coverage/report?entity=component:default/entity-name",
+ "href": "http://localhost:7007/api/code-coverage/report?entity=component:default/entity-name",
"rel": "coverage"
}
]
@@ -49,11 +49,11 @@ POST a JaCoCo XML file to `/report`
Example:
```json
-// curl -X POST -H "Content-Type:text/xml" -d @jacoco.xml "localhost:7000/api/code-coverage/report?entity=component:default/entity-name&coverageType=jacoco"
+// curl -X POST -H "Content-Type:text/xml" -d @jacoco.xml "localhost:7007/api/code-coverage/report?entity=component:default/entity-name&coverageType=jacoco"
{
"links": [
{
- "href": "http://localhost:7000/api/code-coverage/report?entity=component:default/entity-name",
+ "href": "http://localhost:7007/api/code-coverage/report?entity=component:default/entity-name",
"rel": "coverage"
}
]
@@ -67,7 +67,7 @@ GET `/report`
Example:
```json
-// curl localhost:7000/api/code-coverage/report?entity=component:default/entity-name
+// curl localhost:7007/api/code-coverage/report?entity=component:default/entity-name
{
"aggregate": {
"branch": {
@@ -111,7 +111,7 @@ GET `/history`
Example
```json
-// curl localhost:7000/api/code-coverage/history?entity=component:default/entity-name
+// curl localhost:7007/api/code-coverage/history?entity=component:default/entity-name
{
"entity": {
"kind": "Component",
diff --git a/plugins/code-coverage-backend/src/run.ts b/plugins/code-coverage-backend/src/run.ts
index 54d2716290..0a3ed2b7f0 100644
--- a/plugins/code-coverage-backend/src/run.ts
+++ b/plugins/code-coverage-backend/src/run.ts
@@ -18,7 +18,7 @@ import { getRootLogger } from '@backstage/backend-common';
import yn from 'yn';
import { startStandaloneServer } from './service/standaloneServer';
-const port = process.env.PLUGIN_PORT ? Number(process.env.PLUGIN_PORT) : 7000;
+const port = process.env.PLUGIN_PORT ? Number(process.env.PLUGIN_PORT) : 7007;
const enableCors = yn(process.env.PLUGIN_CORS, { default: false });
const logger = getRootLogger();
diff --git a/plugins/code-coverage-backend/src/service/router.test.ts b/plugins/code-coverage-backend/src/service/router.test.ts
index 462606bbab..4e6a66fdd8 100644
--- a/plugins/code-coverage-backend/src/service/router.test.ts
+++ b/plugins/code-coverage-backend/src/service/router.test.ts
@@ -42,7 +42,7 @@ function createDatabase(): PluginDatabaseManager {
const testDiscovery: jest.Mocked = {
getBaseUrl: jest
.fn()
- .mockResolvedValue('http://localhost:7000/api/code-coverage'),
+ .mockResolvedValue('http://localhost:7007/api/code-coverage'),
getExternalBaseUrl: jest.fn(),
};
const mockUrlReader = UrlReaders.default({
diff --git a/plugins/code-coverage/package.json b/plugins/code-coverage/package.json
index 0c32718e97..e5b51e90b4 100644
--- a/plugins/code-coverage/package.json
+++ b/plugins/code-coverage/package.json
@@ -43,7 +43,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/plugins/config-schema/package.json b/plugins/config-schema/package.json
index 0385a64ec8..c9abbc7e4e 100644
--- a/plugins/config-schema/package.json
+++ b/plugins/config-schema/package.json
@@ -38,7 +38,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/plugins/cost-insights/package.json b/plugins/cost-insights/package.json
index 04e4f41701..da9ba8b1f6 100644
--- a/plugins/cost-insights/package.json
+++ b/plugins/cost-insights/package.json
@@ -56,7 +56,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/plugins/explore/package.json b/plugins/explore/package.json
index 5732e3fca6..d9945edc51 100644
--- a/plugins/explore/package.json
+++ b/plugins/explore/package.json
@@ -50,7 +50,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/plugins/firehydrant/package.json b/plugins/firehydrant/package.json
index dce261617d..f332efc150 100644
--- a/plugins/firehydrant/package.json
+++ b/plugins/firehydrant/package.json
@@ -36,7 +36,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/plugins/fossa/package.json b/plugins/fossa/package.json
index 8090fdc1c7..cc0b486d60 100644
--- a/plugins/fossa/package.json
+++ b/plugins/fossa/package.json
@@ -50,7 +50,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/plugins/gcp-projects/package.json b/plugins/gcp-projects/package.json
index 0e33130274..cd1c3ac4a1 100644
--- a/plugins/gcp-projects/package.json
+++ b/plugins/gcp-projects/package.json
@@ -44,7 +44,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/plugins/git-release-manager/package.json b/plugins/git-release-manager/package.json
index 0c52381514..7f7ff6184d 100644
--- a/plugins/git-release-manager/package.json
+++ b/plugins/git-release-manager/package.json
@@ -40,7 +40,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/plugins/github-actions/README.md b/plugins/github-actions/README.md
index d027368c8b..082267d424 100644
--- a/plugins/github-actions/README.md
+++ b/plugins/github-actions/README.md
@@ -11,7 +11,7 @@ TBD
### Generic Requirements
1. Provide OAuth credentials:
- 1. [Create an OAuth App](https://developer.github.com/apps/building-oauth-apps/creating-an-oauth-app/) with the callback URL set to `http://localhost:7000/api/auth/github`.
+ 1. [Create an OAuth App](https://developer.github.com/apps/building-oauth-apps/creating-an-oauth-app/) with the callback URL set to `http://localhost:7007/api/auth/github`.
2. Take the Client ID and Client Secret from the newly created app's settings page and put them into `AUTH_GITHUB_CLIENT_ID` and `AUTH_GITHUB_CLIENT_SECRET` environment variables.
2. Annotate your component with a correct GitHub Actions repository and owner:
diff --git a/plugins/github-actions/package.json b/plugins/github-actions/package.json
index 789385308e..ae7f32be1f 100644
--- a/plugins/github-actions/package.json
+++ b/plugins/github-actions/package.json
@@ -53,7 +53,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/plugins/github-deployments/package.json b/plugins/github-deployments/package.json
index a52bbfa95a..062113a8ef 100644
--- a/plugins/github-deployments/package.json
+++ b/plugins/github-deployments/package.json
@@ -40,7 +40,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/plugins/gitops-profiles/package.json b/plugins/gitops-profiles/package.json
index 226a45332c..dfbd6297cf 100644
--- a/plugins/gitops-profiles/package.json
+++ b/plugins/gitops-profiles/package.json
@@ -45,7 +45,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/plugins/graphiql/package.json b/plugins/graphiql/package.json
index aeefce3340..5c72a4c728 100644
--- a/plugins/graphiql/package.json
+++ b/plugins/graphiql/package.json
@@ -45,7 +45,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/plugins/home/package.json b/plugins/home/package.json
index 74336d80be..ef13ce3a00 100644
--- a/plugins/home/package.json
+++ b/plugins/home/package.json
@@ -36,7 +36,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/plugins/ilert/package.json b/plugins/ilert/package.json
index e0ccd3cd2d..6011dd4f46 100644
--- a/plugins/ilert/package.json
+++ b/plugins/ilert/package.json
@@ -40,7 +40,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/plugins/jenkins-backend/src/run.ts b/plugins/jenkins-backend/src/run.ts
index b96989e4b8..068a2b9d5f 100644
--- a/plugins/jenkins-backend/src/run.ts
+++ b/plugins/jenkins-backend/src/run.ts
@@ -18,7 +18,7 @@ import { getRootLogger } from '@backstage/backend-common';
import yn from 'yn';
import { startStandaloneServer } from './service/standaloneServer';
-const port = process.env.PLUGIN_PORT ? Number(process.env.PLUGIN_PORT) : 7000;
+const port = process.env.PLUGIN_PORT ? Number(process.env.PLUGIN_PORT) : 7007;
const enableCors = yn(process.env.PLUGIN_CORS, { default: false });
const logger = getRootLogger();
diff --git a/plugins/jenkins/package.json b/plugins/jenkins/package.json
index e8115c3800..4456b15284 100644
--- a/plugins/jenkins/package.json
+++ b/plugins/jenkins/package.json
@@ -49,7 +49,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/plugins/kafka/package.json b/plugins/kafka/package.json
index bea4aadcba..a6fbe36e99 100644
--- a/plugins/kafka/package.json
+++ b/plugins/kafka/package.json
@@ -36,7 +36,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/plugins/kubernetes/package.json b/plugins/kubernetes/package.json
index 8f4e3356c5..618f814c21 100644
--- a/plugins/kubernetes/package.json
+++ b/plugins/kubernetes/package.json
@@ -52,7 +52,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/plugins/lighthouse/package.json b/plugins/lighthouse/package.json
index b1e0290b4c..e53f6ee261 100644
--- a/plugins/lighthouse/package.json
+++ b/plugins/lighthouse/package.json
@@ -48,7 +48,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/plugins/newrelic/package.json b/plugins/newrelic/package.json
index c19bc9ed37..16029f1783 100644
--- a/plugins/newrelic/package.json
+++ b/plugins/newrelic/package.json
@@ -44,7 +44,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/plugins/org/package.json b/plugins/org/package.json
index 035ae50c3b..db6cfe4d0b 100644
--- a/plugins/org/package.json
+++ b/plugins/org/package.json
@@ -38,7 +38,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/plugins/pagerduty/package.json b/plugins/pagerduty/package.json
index 735b541451..7981b2c104 100644
--- a/plugins/pagerduty/package.json
+++ b/plugins/pagerduty/package.json
@@ -49,7 +49,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/plugins/permission-common/api-report.md b/plugins/permission-common/api-report.md
index cbf1877c75..043b27554c 100644
--- a/plugins/permission-common/api-report.md
+++ b/plugins/permission-common/api-report.md
@@ -3,6 +3,8 @@
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
+import { Config } from '@backstage/config';
+
// @public
export type AuthorizeRequest = {
permission: Permission;
@@ -67,7 +69,7 @@ export type PermissionAttributes = {
// @public
export class PermissionClient {
- constructor(options: { discoveryApi: DiscoveryApi; enabled?: boolean });
+ constructor(options: { discoveryApi: DiscoveryApi; configApi: Config });
authorize(
requests: AuthorizeRequest[],
options?: AuthorizeRequestOptions,
diff --git a/plugins/permission-common/package.json b/plugins/permission-common/package.json
index 95a0d9d3c3..9e1d60f782 100644
--- a/plugins/permission-common/package.json
+++ b/plugins/permission-common/package.json
@@ -38,6 +38,7 @@
"url": "https://github.com/backstage/backstage/issues"
},
"dependencies": {
+ "@backstage/config": "^0.1.11",
"@backstage/errors": "^0.1.2",
"cross-fetch": "^3.0.6",
"uuid": "^8.0.0",
diff --git a/plugins/permission-common/src/PermissionClient.test.ts b/plugins/permission-common/src/PermissionClient.test.ts
index 06e2ae0561..b2e66986a1 100644
--- a/plugins/permission-common/src/PermissionClient.test.ts
+++ b/plugins/permission-common/src/PermissionClient.test.ts
@@ -16,6 +16,7 @@
import { RestContext, rest } from 'msw';
import { setupServer } from 'msw/node';
+import { ConfigReader } from '@backstage/config';
import { PermissionClient } from './PermissionClient';
import { AuthorizeRequest, AuthorizeResult, Identified } from './types/api';
import { DiscoveryApi } from './types/discovery';
@@ -32,7 +33,7 @@ const discoveryApi: DiscoveryApi = {
};
const client: PermissionClient = new PermissionClient({
discoveryApi,
- enabled: true,
+ configApi: new ConfigReader({ permission: { enabled: true } }),
});
const mockPermission: Permission = {
@@ -145,7 +146,7 @@ describe('PermissionClient', () => {
).rejects.toThrowError(/invalid input/i);
});
- it('should allow all when authorization is not enabled', async () => {
+ it('should allow all when permission.enabled is false', async () => {
mockAuthorizeHandler.mockImplementationOnce(
(req, res, { json }: RestContext) => {
const responses = req.body.map((a: Identified) => ({
@@ -156,7 +157,32 @@ describe('PermissionClient', () => {
return res(json(responses));
},
);
- const disabled = new PermissionClient({ discoveryApi, enabled: false });
+ const disabled = new PermissionClient({
+ discoveryApi,
+ configApi: new ConfigReader({ permission: { enabled: false } }),
+ });
+ const response = await disabled.authorize([mockAuthorizeRequest]);
+ expect(response[0]).toEqual(
+ expect.objectContaining({ result: AuthorizeResult.ALLOW }),
+ );
+ expect(mockAuthorizeHandler).not.toBeCalled();
+ });
+
+ it('should allow all when permission.enabled is not configured', async () => {
+ mockAuthorizeHandler.mockImplementationOnce(
+ (req, res, { json }: RestContext) => {
+ const responses = req.body.map((a: Identified) => ({
+ id: a.id,
+ outcome: AuthorizeResult.DENY,
+ }));
+
+ return res(json(responses));
+ },
+ );
+ const disabled = new PermissionClient({
+ discoveryApi,
+ configApi: new ConfigReader({}),
+ });
const response = await disabled.authorize([mockAuthorizeRequest]);
expect(response[0]).toEqual(
expect.objectContaining({ result: AuthorizeResult.ALLOW }),
diff --git a/plugins/permission-common/src/PermissionClient.ts b/plugins/permission-common/src/PermissionClient.ts
index 5b17ccd333..f98d40a3c4 100644
--- a/plugins/permission-common/src/PermissionClient.ts
+++ b/plugins/permission-common/src/PermissionClient.ts
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+import { Config } from '@backstage/config';
import { ResponseError } from '@backstage/errors';
import fetch from 'cross-fetch';
import * as uuid from 'uuid';
@@ -74,9 +75,10 @@ export class PermissionClient {
private readonly enabled: boolean;
private readonly discoveryApi: DiscoveryApi;
- constructor(options: { discoveryApi: DiscoveryApi; enabled?: boolean }) {
+ constructor(options: { discoveryApi: DiscoveryApi; configApi: Config }) {
this.discoveryApi = options.discoveryApi;
- this.enabled = options.enabled ?? false;
+ this.enabled =
+ options.configApi.getOptionalBoolean('permission.enabled') ?? false;
}
/**
diff --git a/plugins/proxy-backend/src/run.ts b/plugins/proxy-backend/src/run.ts
index 54d2716290..0a3ed2b7f0 100644
--- a/plugins/proxy-backend/src/run.ts
+++ b/plugins/proxy-backend/src/run.ts
@@ -18,7 +18,7 @@ import { getRootLogger } from '@backstage/backend-common';
import yn from 'yn';
import { startStandaloneServer } from './service/standaloneServer';
-const port = process.env.PLUGIN_PORT ? Number(process.env.PLUGIN_PORT) : 7000;
+const port = process.env.PLUGIN_PORT ? Number(process.env.PLUGIN_PORT) : 7007;
const enableCors = yn(process.env.PLUGIN_CORS, { default: false });
const logger = getRootLogger();
diff --git a/plugins/proxy-backend/src/service/router.test.ts b/plugins/proxy-backend/src/service/router.test.ts
index df999dbe2a..ddb524d3aa 100644
--- a/plugins/proxy-backend/src/service/router.test.ts
+++ b/plugins/proxy-backend/src/service/router.test.ts
@@ -34,9 +34,9 @@ describe('createRouter', () => {
const logger = getVoidLogger();
const config = new ConfigReader({
backend: {
- baseUrl: 'https://example.com:7000',
+ baseUrl: 'https://example.com:7007',
listen: {
- port: 7000,
+ port: 7007,
},
},
});
diff --git a/plugins/rollbar-backend/src/run.ts b/plugins/rollbar-backend/src/run.ts
index 54d2716290..0a3ed2b7f0 100644
--- a/plugins/rollbar-backend/src/run.ts
+++ b/plugins/rollbar-backend/src/run.ts
@@ -18,7 +18,7 @@ import { getRootLogger } from '@backstage/backend-common';
import yn from 'yn';
import { startStandaloneServer } from './service/standaloneServer';
-const port = process.env.PLUGIN_PORT ? Number(process.env.PLUGIN_PORT) : 7000;
+const port = process.env.PLUGIN_PORT ? Number(process.env.PLUGIN_PORT) : 7007;
const enableCors = yn(process.env.PLUGIN_CORS, { default: false });
const logger = getRootLogger();
diff --git a/plugins/rollbar/package.json b/plugins/rollbar/package.json
index f3d32eed11..ee3fc9f5a6 100644
--- a/plugins/rollbar/package.json
+++ b/plugins/rollbar/package.json
@@ -50,7 +50,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json
index 3d7bde77c9..a47cee2d75 100644
--- a/plugins/scaffolder/package.json
+++ b/plugins/scaffolder/package.json
@@ -67,7 +67,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/plugins/search-backend/src/run.ts b/plugins/search-backend/src/run.ts
index addfdfd6d7..53d4e4334a 100644
--- a/plugins/search-backend/src/run.ts
+++ b/plugins/search-backend/src/run.ts
@@ -18,7 +18,7 @@ import { getRootLogger } from '@backstage/backend-common';
import yn from 'yn';
import { startStandaloneServer } from './service/standaloneServer';
-const port = process.env.PLUGIN_PORT ? Number(process.env.PLUGIN_PORT) : 7000;
+const port = process.env.PLUGIN_PORT ? Number(process.env.PLUGIN_PORT) : 7007;
const enableCors = yn(process.env.PLUGIN_CORS, { default: false });
const logger = getRootLogger();
diff --git a/plugins/search/package.json b/plugins/search/package.json
index 24984d10e7..aaddf130bf 100644
--- a/plugins/search/package.json
+++ b/plugins/search/package.json
@@ -52,7 +52,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/plugins/sentry/package.json b/plugins/sentry/package.json
index fd7cc34b1f..a04043c789 100644
--- a/plugins/sentry/package.json
+++ b/plugins/sentry/package.json
@@ -49,7 +49,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/plugins/shortcuts/package.json b/plugins/shortcuts/package.json
index 8fad41f0a8..f0139d5728 100644
--- a/plugins/shortcuts/package.json
+++ b/plugins/shortcuts/package.json
@@ -39,7 +39,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/plugins/sonarqube/package.json b/plugins/sonarqube/package.json
index 07467ac1cf..f92c21ad7e 100644
--- a/plugins/sonarqube/package.json
+++ b/plugins/sonarqube/package.json
@@ -50,7 +50,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/plugins/splunk-on-call/package.json b/plugins/splunk-on-call/package.json
index dfb1c58aca..10eb807ba1 100644
--- a/plugins/splunk-on-call/package.json
+++ b/plugins/splunk-on-call/package.json
@@ -48,7 +48,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/plugins/tech-insights-backend-module-jsonfc/README.md b/plugins/tech-insights-backend-module-jsonfc/README.md
index 48c1e69919..c0f992ffc7 100644
--- a/plugins/tech-insights-backend-module-jsonfc/README.md
+++ b/plugins/tech-insights-backend-module-jsonfc/README.md
@@ -24,7 +24,7 @@ and modify the `techInsights.ts` file to contain a reference to the FactCheckers
+ logger,
+}),
- const builder = new DefaultTechInsightsBuilder({
+ const builder = buildTechInsightsContext({
logger,
config,
database,
@@ -59,7 +59,7 @@ export const exampleCheck: TechInsightJsonRuleCheck = {
name: 'demodatacheck', // A human readable name of this check to be displayed in the UI
type: JSON_RULE_ENGINE_CHECK_TYPE, // Type identifier of the check. Used to run logic against, determine persistence option to use and render correct components on the UI
description: 'A fact check for demoing purposes', // A description to be displayed in the UI
- factRefs: ['demo-poc.factretriever'], // References to fact containers that this check uses. See documentation on FactRetrievers for more information on these
+ factIds: ['documentation-number-factretriever'], // References to fact ids that this check uses. See documentation on FactRetrievers for more information on these
rule: {
// The actual rule
conditions: {
diff --git a/plugins/tech-insights-backend/README.md b/plugins/tech-insights-backend/README.md
index e2cc1c0252..764ad860b8 100644
--- a/plugins/tech-insights-backend/README.md
+++ b/plugins/tech-insights-backend/README.md
@@ -22,7 +22,7 @@ do this by creating a file called `packages/backend/src/plugins/techInsights.ts`
```ts
import {
createRouter,
- DefaultTechInsightsBuilder,
+ buildTechInsightsContext,
} from '@backstage/plugin-tech-insights-backend';
import { Router } from 'express';
import { PluginEnvironment } from '../types';
@@ -33,7 +33,7 @@ export default async function createPlugin({
discovery,
database,
}: PluginEnvironment): Promise {
- const builder = new DefaultTechInsightsBuilder({
+ const builder = buildTechInsightsContext({
logger,
config,
database,
diff --git a/plugins/tech-radar/package.json b/plugins/tech-radar/package.json
index d07b75c401..99fce10345 100644
--- a/plugins/tech-radar/package.json
+++ b/plugins/tech-radar/package.json
@@ -46,7 +46,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/plugins/techdocs-backend/config.d.ts b/plugins/techdocs-backend/config.d.ts
index da3cd34830..9e563137bd 100644
--- a/plugins/techdocs-backend/config.d.ts
+++ b/plugins/techdocs-backend/config.d.ts
@@ -227,14 +227,14 @@ export interface Config {
};
/**
- * @example http://localhost:7000/api/techdocs
+ * @example http://localhost:7007/api/techdocs
* @visibility frontend
* @deprecated
*/
requestUrl?: string;
/**
- * @example http://localhost:7000/api/techdocs/static/docs
+ * @example http://localhost:7007/api/techdocs/static/docs
* @deprecated
*/
storageUrl?: string;
diff --git a/plugins/techdocs/config.d.ts b/plugins/techdocs/config.d.ts
index d6bf21b10b..45fd524eff 100644
--- a/plugins/techdocs/config.d.ts
+++ b/plugins/techdocs/config.d.ts
@@ -34,7 +34,7 @@ export interface Config {
legacyUseCaseSensitiveTripletPaths?: boolean;
/**
- * @example http://localhost:7000/api/techdocs
+ * @example http://localhost:7007/api/techdocs
* @visibility frontend
* @deprecated
*/
diff --git a/plugins/techdocs/package.json b/plugins/techdocs/package.json
index d1c337754a..663c83118e 100644
--- a/plugins/techdocs/package.json
+++ b/plugins/techdocs/package.json
@@ -62,7 +62,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/plugins/todo/package.json b/plugins/todo/package.json
index b11721695a..22a8e6b1e2 100644
--- a/plugins/todo/package.json
+++ b/plugins/todo/package.json
@@ -42,7 +42,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/plugins/user-settings/package.json b/plugins/user-settings/package.json
index 6b7ef01538..def12ac1d2 100644
--- a/plugins/user-settings/package.json
+++ b/plugins/user-settings/package.json
@@ -44,7 +44,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/plugins/xcmetrics/package.json b/plugins/xcmetrics/package.json
index c23a5487db..f29f763666 100644
--- a/plugins/xcmetrics/package.json
+++ b/plugins/xcmetrics/package.json
@@ -37,7 +37,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.9.0",
- "@backstage/core-app-api": "^0.1.21",
+ "@backstage/core-app-api": "^0.1.22",
"@backstage/dev-utils": "^0.2.13",
"@backstage/test-utils": "^0.1.22",
"@testing-library/jest-dom": "^5.10.1",
diff --git a/scripts/check-if-release.js b/scripts/check-if-release.js
index 4475ed6207..b61b0e2eb7 100755
--- a/scripts/check-if-release.js
+++ b/scripts/check-if-release.js
@@ -96,7 +96,9 @@ async function main() {
const newVersions = packageVersions.filter(
({ oldVersion, newVersion }) =>
- oldVersion !== newVersion && newVersion !== '',
+ oldVersion !== newVersion &&
+ oldVersion !== '' &&
+ newVersion !== '',
);
if (newVersions.length === 0) {
diff --git a/scripts/list-deprecations.js b/scripts/list-deprecations.js
new file mode 100755
index 0000000000..920b01c7b5
--- /dev/null
+++ b/scripts/list-deprecations.js
@@ -0,0 +1,229 @@
+#!/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 import/no-extraneous-dependencies */
+
+const _ = require('lodash');
+const fs = require('fs-extra');
+const globby = require('globby');
+const { resolve: resolvePath, relative: relativePath } = require('path');
+const { execFile: execFileCb } = require('child_process');
+const { promisify } = require('util');
+
+const execFile = promisify(execFileCb);
+
+const WORKER_COUNT = 16;
+
+const deprecatedPattern = /@deprecated|DEPRECATION/;
+
+class ReleaseProvider {
+ cache = new Map();
+
+ constructor(rootPath) {
+ this.rootPath = rootPath;
+ }
+
+ async lookup(commitSha, packageDir) {
+ const key = commitSha + packageDir;
+
+ if (this.cache.has(key)) {
+ return this.cache.get(key);
+ }
+
+ const pkgJsonPath = relativePath(
+ this.rootPath,
+ resolvePath(this.rootPath, packageDir, 'package.json'),
+ );
+ const releasePromise = Promise.resolve().then(async () => {
+ // Find all tags that contain the commit
+ const { stdout: tagOutput } = await execFile(
+ 'git',
+ ['tag', '--contains', commitSha],
+ { shell: true },
+ );
+
+ // Filter out just the releases
+ const releases = tagOutput
+ .split('\n')
+ .filter(l => l.startsWith('release-'));
+
+ // Then find the earliest release that affected our package
+ for (const release of releases) {
+ let oldVersion;
+ let newVersion;
+
+ try {
+ const { stdout: content } = await execFile(
+ 'git',
+ ['show', `${release}^:${pkgJsonPath}`],
+ { shell: true },
+ );
+ oldVersion = JSON.parse(content).version;
+ } catch {
+ /* */
+ }
+ try {
+ const { stdout: content } = await execFile(
+ 'git',
+ ['show', `${release}:${pkgJsonPath}`],
+ { shell: true },
+ );
+ newVersion = JSON.parse(content).version;
+ } catch {
+ /* */
+ }
+
+ if (oldVersion !== newVersion) {
+ return release;
+ }
+ }
+ return undefined;
+ });
+
+ this.cache.set(key, releasePromise);
+ return releasePromise;
+ }
+}
+
+async function main() {
+ let packageDirQueue = process.argv.slice(2);
+
+ const rootPath = resolvePath(__dirname, '..');
+
+ if (packageDirQueue.length === 0) {
+ packageDirQueue = await Promise.all([
+ fs.readdir(resolvePath(rootPath, 'packages')),
+ fs.readdir(resolvePath(rootPath, 'plugins')),
+ ]).then(([packages, plugins]) => [
+ ...packages.map(dir => `packages/${dir}`),
+ ...plugins.map(dir => `plugins/${dir}`),
+ ]);
+ }
+
+ const fileQueue = [];
+ const deprecationQueue = [];
+ const releaseProvider = new ReleaseProvider(rootPath);
+ const deprecations = [];
+
+ await Promise.all(
+ Array(WORKER_COUNT)
+ .fill()
+ .map(async () => {
+ // Find all files we want to scan
+ while (packageDirQueue.length) {
+ const packageDir = packageDirQueue.pop();
+ const srcDir = resolvePath(rootPath, packageDir, 'src');
+
+ if (await fs.pathExists(srcDir)) {
+ const files = await globby(['**/*.{js,jsx,ts,tsx}'], {
+ cwd: srcDir,
+ });
+ fileQueue.push(
+ ...files.map(file => ({
+ packageDir,
+ file: resolvePath(srcDir, file),
+ })),
+ );
+ }
+ }
+
+ // Parse files and search for deprecations
+ while (fileQueue.length) {
+ const { packageDir, file } = fileQueue.pop();
+ const content = await fs.readFile(file, 'utf8');
+ if (!deprecatedPattern.test(content)) {
+ continue;
+ }
+
+ const lines = content.split('\n');
+ for (const [index, line] of lines.entries()) {
+ if (deprecatedPattern.test(line)) {
+ deprecationQueue.push({
+ packageDir,
+ file,
+ lineNumber: index + 1,
+ lineContent: line,
+ });
+ }
+ }
+ }
+
+ // Lookup git information for each deprecation
+ while (deprecationQueue.length) {
+ const deprecation = deprecationQueue.pop();
+
+ const { file, packageDir, lineNumber: n, lineContent } = deprecation;
+ const { stdout: blameOutput } = await execFile(
+ 'git',
+ ['blame', '--porcelain', `-L ${n},${n}`, file],
+ { shell: true },
+ );
+
+ const blameInfo = Object.fromEntries(
+ blameOutput
+ .split('\n')
+ .slice(1, -2)
+ .map(line => {
+ const [key] = line.split(' ', 1);
+ return [key, line.slice(key.length + 1)];
+ }),
+ );
+ const [commit] = blameOutput.split(' ', 1);
+ const { author, ['author-time']: authorTime } = blameInfo;
+
+ const release = await releaseProvider.lookup(commit, packageDir);
+
+ deprecations.push({
+ file: relativePath(rootPath, file),
+ release,
+ commit,
+ author,
+ authorTime: new Date(authorTime * 1000),
+ lineContent,
+ lineNumber: n,
+ });
+ }
+ }),
+ );
+
+ const maxAuthor = Math.max(...deprecations.map(d => d.author.length)) + 1;
+
+ // Group and sort by release
+ const sortedByRelease = _.sortBy(
+ Object.entries(_.groupBy(deprecations, 'release')),
+ ([release]) => release,
+ );
+
+ for (const [release, ds] of sortedByRelease) {
+ console.log(`\n### ${release === 'undefined' ? 'Not released' : release}`);
+ for (const d of _.sortBy(ds, 'authorTime', 'file', 'lineNumber')) {
+ console.log(
+ [
+ d.commit.slice(0, 8),
+ d.authorTime.toLocaleDateString().padEnd('00/00/0000'.length + 1),
+ d.author.padEnd(maxAuthor + 1),
+ `${d.file}:${d.lineNumber}`,
+ ].join(' '),
+ );
+ }
+ }
+}
+
+main().catch(err => {
+ console.error(err.stack);
+ process.exit(1);
+});
diff --git a/scripts/migrate-location-types.js b/scripts/migrate-location-types.js
index d6ac5c6a2a..168a5e825c 100755
--- a/scripts/migrate-location-types.js
+++ b/scripts/migrate-location-types.js
@@ -20,7 +20,7 @@
// catalog API endpoint and execute the script. It will delete and add
// back the locations with the correct type one by one.
-const BASE_URL = 'http://localhost:7000/api/catalog'; // Change me
+const BASE_URL = 'http://localhost:7007/api/catalog'; // Change me
const deprecatedTypes = [
'github',
@@ -81,9 +81,9 @@ async function request(method, url, body) {
return;
}
try {
- const body = Buffer.concat(chunks).toString('utf8').trim();
- if (body) {
- resolve(JSON.parse(body));
+ const responseBody = Buffer.concat(chunks).toString('utf8').trim();
+ if (responseBody) {
+ resolve(JSON.parse(responseBody));
} else {
resolve();
}
diff --git a/yarn.lock b/yarn.lock
index 9b934191d8..1bc51389d1 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5072,19 +5072,19 @@
resolved "https://registry.npmjs.org/@octokit/webhooks-methods/-/webhooks-methods-2.0.0.tgz#1108b9ea661ca6c81e4a8bfa63a09eb27d5bc2db"
integrity sha512-35cfQ4YWlnZnmZKmIxlGPUPLtbkF8lr/A/1Sk1eC0ddLMwQN06dOuLc+dI3YLQS+T+MoNt3DIQ0NynwgKPilig==
-"@octokit/webhooks-types@4.12.0":
- version "4.12.0"
- resolved "https://registry.npmjs.org/@octokit/webhooks-types/-/webhooks-types-4.12.0.tgz#add8b98d60ab42e965c4ba31040097f810e222de"
- integrity sha512-G0k7CoS9bK+OI7kPHgqi1KqK4WhrjDQSjy0wJI+0OTx/xvbHUIZDeqatY60ceeRINP/1ExEk6kTARboP0xavEw==
+"@octokit/webhooks-types@4.15.0":
+ version "4.15.0"
+ resolved "https://registry.npmjs.org/@octokit/webhooks-types/-/webhooks-types-4.15.0.tgz#1158cba6578237d60957a37963a4a05654f5668b"
+ integrity sha512-s9LgKsUzq/JH3PWDjaD/m1DIlC/QWgBWbmXVqjdxJXJQBA67KZrLWjStVlYPf0mWlVZ1MOKphDyHiOGCbs0+Kg==
"@octokit/webhooks@^9.14.1":
- version "9.17.0"
- resolved "https://registry.npmjs.org/@octokit/webhooks/-/webhooks-9.17.0.tgz#81140b2e127157aa9817d085cd8758545e4a72e4"
- integrity sha512-/+9WSLuDuoqNWnMY4w6ePioILBqsUOiUt0ygQzugYzd112WB+yPIjmUQjAbNXImDsAa1myLpBICAMQDZlULyAA==
+ version "9.18.0"
+ resolved "https://registry.npmjs.org/@octokit/webhooks/-/webhooks-9.18.0.tgz#19cc70e1ef281e33d830ea23e8011d25d8051f7f"
+ integrity sha512-N2hP7vCouKk9UWZxvqgWTPbp34i6g9Om/jk+TZeZ5Z+VsKjXvGtONlEd9H8DM1yOeEC+ARDpfhraX6UsK5tesQ==
dependencies:
"@octokit/request-error" "^2.0.2"
"@octokit/webhooks-methods" "^2.0.0"
- "@octokit/webhooks-types" "4.12.0"
+ "@octokit/webhooks-types" "4.15.0"
aggregate-error "^3.1.0"
"@open-draft/until@^1.0.3":
@@ -7080,9 +7080,9 @@
"@types/ms" "*"
"@types/diff@^5.0.0":
- version "5.0.0"
- resolved "https://registry.npmjs.org/@types/diff/-/diff-5.0.0.tgz#eb71e94feae62548282c4889308a3dfb57e36020"
- integrity sha512-jrm2K65CokCCX4NmowtA+MfXyuprZC13jbRuwprs6/04z/EcFg/MCwYdsHn+zgV4CQBiATiI7AEq7y1sZCtWKA==
+ version "5.0.1"
+ resolved "https://registry.npmjs.org/@types/diff/-/diff-5.0.1.tgz#9c9b9a331d4e41ccccff553f5d7ef964c6cf4042"
+ integrity sha512-XIpxU6Qdvp1ZE6Kr3yrkv1qgUab0fyf4mHYvW8N3Bx3PCsbN6or1q9/q72cv5jIFWolaGH08U9XyYoLLIykyKQ==
"@types/docker-modem@*":
version "3.0.2"
@@ -16266,11 +16266,6 @@ hsla-regex@^1.0.0:
resolved "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz#c1ce7a3168c8c6614033a4b5f7877f3b225f9c38"
integrity sha1-wc56MWjIxmFAM6S194d/OyJfnDg=
-html-comment-regex@^1.1.0:
- version "1.1.2"
- resolved "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.2.tgz#97d4688aeb5c81886a364faa0cad1dda14d433a7"
- integrity sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==
-
html-encoding-sniffer@^2.0.1:
version "2.0.1"
resolved "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3"
@@ -17484,13 +17479,6 @@ is-subdir@^1.1.1:
dependencies:
better-path-resolve "1.0.0"
-is-svg@^3.0.0:
- version "3.0.0"
- resolved "https://registry.npmjs.org/is-svg/-/is-svg-3.0.0.tgz#9321dbd29c212e5ca99c4fa9794c714bcafa2f75"
- integrity sha512-gi4iHK53LR2ujhLVVj+37Ykh9GLqYHX6JOVXbLAucaG/Cqw9xwdFOjDM2qeifLs1sF1npXXFvDu0r5HNgCMrzQ==
- dependencies:
- html-comment-regex "^1.1.0"
-
is-symbol@^1.0.2, is-symbol@^1.0.3:
version "1.0.3"
resolved "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937"
@@ -20755,10 +20743,10 @@ mixin-object@^2.0.1:
for-in "^0.1.3"
is-extendable "^0.1.1"
-mixme@^0.3.1:
- version "0.3.5"
- resolved "https://registry.npmjs.org/mixme/-/mixme-0.3.5.tgz#304652cdaf24a3df0487205e61ac6162c6906ddd"
- integrity sha512-SyV9uPETRig5ZmYev0ANfiGeB+g6N2EnqqEfBbCGmmJ6MgZ3E4qv5aPbnHVdZ60KAHHXV+T3sXopdrnIXQdmjQ==
+mixme@^0.5.1:
+ version "0.5.4"
+ resolved "https://registry.npmjs.org/mixme/-/mixme-0.5.4.tgz#8cb3bd0cd32a513c161bf1ca99d143f0bcf2eff3"
+ integrity sha512-3KYa4m4Vlqx98GPdOHghxSdNtTvcP8E0kkaJ5Dlh+h2DRzF7zpuVVcA8B0QpKd11YJeP9QQ7ASkKzOeu195Wzw==
mkdirp-classic@^0.5.2:
version "0.5.2"
@@ -23181,11 +23169,10 @@ postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.2, postcss-selector
util-deprecate "^1.0.2"
postcss-svgo@^4.0.2:
- version "4.0.2"
- resolved "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-4.0.2.tgz#17b997bc711b333bab143aaed3b8d3d6e3d38258"
- integrity sha512-C6wyjo3VwFm0QgBy+Fu7gCYOkCmgmClghO+pjcxvrcBKtiKt0uCF+hvbMO1fyv5BMImRK90SMb+dwUnfbGd+jw==
+ version "4.0.3"
+ resolved "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-4.0.3.tgz#343a2cdbac9505d416243d496f724f38894c941e"
+ integrity sha512-NoRbrcMWTtUghzuKSoIm6XV+sJdvZ7GZSc3wdBN0W19FTtp2ko8NqLsgoh/m9CzNhU3KLPvQmjIwtaNFkaFTvw==
dependencies:
- is-svg "^3.0.0"
postcss "^7.0.0"
postcss-value-parser "^3.0.0"
svgo "^1.0.0"
@@ -25628,10 +25615,12 @@ serialize-error@^8.0.1, serialize-error@^8.1.0:
dependencies:
type-fest "^0.20.2"
-serialize-javascript@^2.1.2:
- version "2.1.2"
- resolved "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz#ecec53b0e0317bdc95ef76ab7074b7384785fa61"
- integrity sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==
+serialize-javascript@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa"
+ integrity sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==
+ dependencies:
+ randombytes "^2.1.0"
serialize-javascript@^5.0.1:
version "5.0.1"
@@ -26469,11 +26458,11 @@ stream-shift@^1.0.0:
integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==
stream-transform@^2.0.1:
- version "2.0.2"
- resolved "https://registry.npmjs.org/stream-transform/-/stream-transform-2.0.2.tgz#3cb7a14c802eb39bc40caaab0535e584f3a65caf"
- integrity sha512-J+D5jWPF/1oX+r9ZaZvEXFbu7znjxSkbNAHJ9L44bt/tCVuOEWZlDqU9qJk7N2xBU1S+K2DPpSKeR/MucmCA1Q==
+ version "2.1.3"
+ resolved "https://registry.npmjs.org/stream-transform/-/stream-transform-2.1.3.tgz#a1c3ecd72ddbf500aa8d342b0b9df38f5aa598e3"
+ integrity sha512-9GHUiM5hMiCi6Y03jD2ARC1ettBXkQBoQAe7nJsPknnI0ow10aXjTnew8QtYQmLjzn974BnmWEAJgCY6ZP1DeQ==
dependencies:
- mixme "^0.3.1"
+ mixme "^0.5.1"
streamsearch@0.1.2:
version "0.1.2"
@@ -27209,15 +27198,15 @@ terser-webpack-plugin@*, terser-webpack-plugin@^5.1.3:
terser "^5.7.2"
terser-webpack-plugin@^1.4.3:
- version "1.4.3"
- resolved "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz#5ecaf2dbdc5fb99745fd06791f46fc9ddb1c9a7c"
- integrity sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA==
+ version "1.4.5"
+ resolved "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz#a217aefaea330e734ffacb6120ec1fa312d6040b"
+ integrity sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==
dependencies:
cacache "^12.0.2"
find-cache-dir "^2.1.0"
is-wsl "^1.1.0"
schema-utils "^1.0.0"
- serialize-javascript "^2.1.2"
+ serialize-javascript "^4.0.0"
source-map "^0.6.1"
terser "^4.1.2"
webpack-sources "^1.4.0"