removed deprecations from the 2021-11-25 release

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2022-01-04 01:57:59 +01:00
parent cd529c4094
commit e2eb92c109
22 changed files with 95 additions and 262 deletions
+7
View File
@@ -0,0 +1,7 @@
---
'@backstage/core-plugin-api': minor
---
Removed previously deprecated exports: `PluginHooks`, `PluginOutput`, and `FeatureFlagOutput`.
The deprecated `register` method of `PluginConfig` has been removed, as well as the deprecated `output` method of `BackstagePlugin`.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/core-components': patch
---
Updated `ResponseErrorPanel` to not use the deprecated `data` property of `ResponseError`.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/core-app-api': minor
---
Removed previously deprecated `ApiRegistry` export.
+7
View File
@@ -0,0 +1,7 @@
---
'@backstage/errors': minor
---
Removed the deprecated exports `ErrorResponse` and `parseErrorResponse`.
Removed the deprecated `constructor` and the deprecated `data` property of `ResponseError`.
@@ -17,7 +17,7 @@
import {
AuthenticationError,
ConflictError,
ErrorResponse,
ErrorResponseBody,
InputError,
NotAllowedError,
NotFoundError,
@@ -89,7 +89,7 @@ export function errorHandler(
return;
}
const body: ErrorResponse = {
const body: ErrorResponseBody = {
error: serializeError(error, { includeStack: showStackTraces }),
request: { method: req.method, url: req.url },
response: { statusCode },
+13 -24
View File
@@ -50,7 +50,6 @@ import { oktaAuthApiRef } from '@backstage/core-plugin-api';
import { oneloginAuthApiRef } from '@backstage/core-plugin-api';
import { OpenIdConnectApi } from '@backstage/core-plugin-api';
import { PendingOAuthRequest } from '@backstage/core-plugin-api';
import { PluginOutput } from '@backstage/core-plugin-api';
import { ProfileInfo } from '@backstage/core-plugin-api';
import { ProfileInfoApi } from '@backstage/core-plugin-api';
import { PropsWithChildren } from 'react';
@@ -129,21 +128,6 @@ export type ApiProviderProps = {
children: ReactNode;
};
// @public @deprecated
export class ApiRegistry implements ApiHolder {
constructor(apis: Map<string, unknown>);
// Warning: (ae-forgotten-export) The symbol "ApiRegistryBuilder" needs to be exported by the entry point index.d.ts
//
// (undocumented)
static builder(): ApiRegistryBuilder;
// Warning: (ae-forgotten-export) The symbol "ApiImpl" needs to be exported by the entry point index.d.ts
static from(apis: ApiImpl[]): ApiRegistry;
// (undocumented)
get<T>(api: ApiRef<T>): T | undefined;
static with<T>(api: ApiRef<T>, impl: T): ApiRegistry;
with<T>(api: ApiRef<T>, impl: T): ApiRegistry;
}
// @public
export class ApiResolver implements ApiHolder {
constructor(factories: ApiFactoryHolder);
@@ -208,14 +192,19 @@ export type AppOptions = {
icons: AppIcons & {
[key in string]: IconComponent;
};
plugins?: (Omit<BackstagePlugin<any, any>, 'output'> & {
output(): (
| PluginOutput
| {
type: string;
}
)[];
})[];
plugins?: Array<
BackstagePlugin<any, any> & {
output?(): Array<
| {
type: 'feature-flag';
name: string;
}
| {
type: string;
}
>;
}
>;
components: AppComponents;
themes: (Partial<AppTheme> & Omit<AppTheme, 'theme'>)[];
configLoader?: AppConfigLoader;
@@ -18,6 +18,7 @@ import { ApiRef, ApiHolder } from '@backstage/core-plugin-api';
type ApiImpl<T = unknown> = readonly [ApiRef<T>, T];
/** @internal */
class ApiRegistryBuilder {
private apis: [string, unknown][] = [];
@@ -35,8 +36,7 @@ class ApiRegistryBuilder {
/**
* A registry for utility APIs.
*
* @public
* @deprecated Will be removed, use {@link @backstage/test-utils#TestApiProvider} or {@link @backstage/test-utils#TestApiRegistry} instead.
* @internal
*/
export class ApiRegistry implements ApiHolder {
static builder() {
@@ -16,7 +16,6 @@
export { ApiProvider } from './ApiProvider';
export type { ApiProviderProps } from './ApiProvider';
export { ApiRegistry } from './ApiRegistry';
export { ApiResolver } from './ApiResolver';
export { ApiFactoryRegistry } from './ApiFactoryRegistry';
export type { ApiFactoryScope } from './ApiFactoryRegistry';
@@ -316,7 +316,7 @@ describe('Integration Test', () => {
plugins: [
createPlugin({
id: 'test',
register: p => p.featureFlags.register('name'),
featureFlags: [{ name: 'name' }],
}),
],
components,
@@ -384,8 +384,24 @@ describe('Integration Test', () => {
name: 'foo',
},
],
register: p => p.featureFlags.register('name'),
}),
// We still support consuming the old feature flag API for a little while longer
{
getId() {
return 'old-test';
},
getApis() {
return [];
},
output() {
return [
{
type: 'feature-flag',
name: 'old-feature-flag',
},
];
},
} as any,
],
components,
configLoader: async () => [],
@@ -412,12 +428,12 @@ describe('Integration Test', () => {
);
expect(storageFlags.registerFlag).toHaveBeenCalledWith({
name: 'name',
name: 'foo',
pluginId: 'test',
});
expect(storageFlags.registerFlag).toHaveBeenCalledWith({
name: 'foo',
pluginId: 'test',
name: 'old-feature-flag',
pluginId: 'old-test',
});
});
+17 -18
View File
@@ -27,7 +27,6 @@ import { Route, Routes } from 'react-router-dom';
import useAsync from 'react-use/lib/useAsync';
import {
ApiProvider,
ApiRegistry,
AppThemeSelector,
ConfigReader,
LocalStorageFeatureFlags,
@@ -80,6 +79,13 @@ import {
} from './types';
import { AppThemeProvider } from './AppThemeProvider';
import { defaultConfigLoader } from './defaultConfigLoader';
import { ApiRegistry } from '../apis/system/ApiRegistry';
type CompatiblePlugin =
| BackstagePlugin<any, any>
| (Omit<BackstagePlugin<any, any>, 'getFeatureFlags'> & {
output(): Array<{ type: 'feature-flag'; name: string }>;
});
export function generateBoundRoutes(bindRoutes: AppOptions['bindRoutes']) {
const result = new Map<ExternalRouteRef, RouteRef | SubRouteRef>();
@@ -149,7 +155,7 @@ function useConfigLoader(
if (noConfigNode) {
return {
node: (
<ApiProvider apis={ApiRegistry.from([[appThemeApiRef, appThemeApi]])}>
<ApiProvider apis={ApiRegistry.with(appThemeApiRef, appThemeApi)}>
<ThemeProvider>{noConfigNode}</ThemeProvider>
</ApiProvider>
),
@@ -183,7 +189,7 @@ export class AppManager implements BackstageApp {
private readonly apis: Iterable<AnyApiFactory>;
private readonly icons: NonNullable<AppOptions['icons']>;
private readonly plugins: Set<BackstagePlugin<any, any>>;
private readonly plugins: Set<CompatiblePlugin>;
private readonly components: AppComponents;
private readonly themes: AppTheme[];
private readonly configLoader?: AppConfigLoader;
@@ -196,9 +202,7 @@ export class AppManager implements BackstageApp {
constructor(options: AppOptions) {
this.apis = options.apis ?? [];
this.icons = options.icons;
this.plugins = new Set(
(options.plugins as BackstagePlugin<any, any>[]) ?? [],
);
this.plugins = new Set((options.plugins as CompatiblePlugin[]) ?? []);
this.components = options.components;
this.themes = options.themes as AppTheme[];
this.configLoader = options.configLoader ?? defaultConfigLoader;
@@ -208,7 +212,7 @@ export class AppManager implements BackstageApp {
}
getPlugins(): BackstagePlugin<any, any>[] {
return Array.from(this.plugins);
return Array.from(this.plugins) as BackstagePlugin<any, any>[];
}
getSystemIcon(key: string): IconComponent | undefined {
@@ -282,16 +286,11 @@ export class AppManager implements BackstageApp {
}
} else {
for (const output of plugin.output()) {
switch (output.type) {
case 'feature-flag': {
featureFlagsApi.registerFlag({
name: output.name,
pluginId: plugin.getId(),
});
break;
}
default:
break;
if (output.type === 'feature-flag') {
featureFlagsApi.registerFlag({
name: output.name,
pluginId: plugin.getId(),
});
}
}
}
@@ -468,7 +467,7 @@ export class AppManager implements BackstageApp {
return this.apiHolder;
}
private verifyPlugins(plugins: Iterable<BackstagePlugin>) {
private verifyPlugins(plugins: Iterable<CompatiblePlugin>) {
const pluginIds = new Set<string>();
for (const plugin of plugins) {
+7 -4
View File
@@ -24,7 +24,6 @@ import {
RouteRef,
SubRouteRef,
ExternalRouteRef,
PluginOutput,
IdentityApi,
} from '@backstage/core-plugin-api';
import { AppConfig } from '@backstage/config';
@@ -232,9 +231,13 @@ export type AppOptions = {
/**
* A list of all plugins to include in the app.
*/
plugins?: (Omit<BackstagePlugin<any, any>, 'output'> & {
output(): (PluginOutput | { type: string })[];
})[];
plugins?: Array<
BackstagePlugin<any, any> & {
output?(): Array<
{ type: 'feature-flag'; name: string } | { type: string }
>; // support for old plugins
}
>;
/**
* Supply components to the app to override the default ones.
@@ -61,14 +61,14 @@ export function ResponseErrorPanel(props: ErrorPanelProps) {
);
}
const { data, cause } = error as ResponseError;
const { request, response } = data;
const { body, cause } = error as ResponseError;
const { request, response } = body;
const errorString = `${response.statusCode}: ${cause.name}`;
const requestString = request && `${request.method} ${request.url}`;
const messageString = cause.message.replace(/\\n/g, '\n');
const stackString = cause.stack?.replace(/\\n/g, '\n');
const jsonString = JSON.stringify(data, undefined, 2);
const jsonString = JSON.stringify(body, undefined, 2);
return (
<ErrorPanel
-16
View File
@@ -241,7 +241,6 @@ export type BackstagePlugin<
ExternalRoutes extends AnyExternalRoutes = {},
> = {
getId(): string;
output(): PluginOutput[];
getApis(): Iterable<AnyApiFactory>;
getFeatureFlags(): Iterable<PluginFeatureFlagConfig>;
provide<T>(extension: Extension<T>): T;
@@ -446,12 +445,6 @@ export type FeatureFlag = {
pluginId: string;
};
// @public @deprecated
export type FeatureFlagOutput = {
type: 'feature-flag';
name: string;
};
// @public
export interface FeatureFlagsApi {
getRegisteredFlags(): FeatureFlag[];
@@ -687,7 +680,6 @@ export type PluginConfig<
> = {
id: string;
apis?: Iterable<AnyApiFactory>;
register?(hooks: PluginHooks): void;
routes?: Routes;
externalRoutes?: ExternalRoutes;
featureFlags?: PluginFeatureFlagConfig[];
@@ -698,14 +690,6 @@ export type PluginFeatureFlagConfig = {
name: string;
};
// @public @deprecated
export type PluginHooks = {
featureFlags: FeatureFlagsHooks;
};
// @public @deprecated
export type PluginOutput = FeatureFlagOutput;
// @public
export type ProfileInfo = {
email?: string;
@@ -28,62 +28,7 @@ describe('Plugin Feature Flag', () => {
expect(
createPlugin({
id: 'test',
register({ featureFlags }) {
featureFlags.register('blob');
},
}).getFeatureFlags(),
).toEqual([{ name: 'blob' }]);
expect(
createPlugin({
id: 'test',
register({ featureFlags }) {
featureFlags.register('blob');
},
featureFlags: [{ name: 'test' }],
}).getFeatureFlags(),
).toEqual([{ name: 'test' }, { name: 'blob' }]);
expect(
createPlugin({
id: 'test',
}).getFeatureFlags(),
).toEqual([]);
/* deprecated tests */
expect(
createPlugin({
id: 'test',
featureFlags: [{ name: 'test' }],
}).output(),
).toEqual([{ name: 'test', type: 'feature-flag' }]);
expect(
createPlugin({
id: 'test',
register({ featureFlags }) {
featureFlags.register('blob');
},
}).output(),
).toEqual([{ name: 'blob', type: 'feature-flag' }]);
expect(
createPlugin({
id: 'test',
register({ featureFlags }) {
featureFlags.register('blob');
},
featureFlags: [{ name: 'test' }],
}).output(),
).toEqual([
{ name: 'test', type: 'feature-flag' },
{ name: 'blob', type: 'feature-flag' },
]);
expect(
createPlugin({
id: 'test',
}).output(),
).toEqual([]);
});
});
+1 -36
View File
@@ -16,7 +16,6 @@
import {
PluginConfig,
PluginOutput,
BackstagePlugin,
Extension,
AnyRoutes,
@@ -33,8 +32,6 @@ export class PluginImpl<
ExternalRoutes extends AnyExternalRoutes,
> implements BackstagePlugin<Routes, ExternalRoutes>
{
private storedOutput?: PluginOutput[];
constructor(private readonly config: PluginConfig<Routes, ExternalRoutes>) {}
getId(): string {
@@ -46,11 +43,7 @@ export class PluginImpl<
}
getFeatureFlags(): Iterable<PluginFeatureFlagConfig> {
const registeredFlags = this.output()
.filter(({ type }) => type === 'feature-flag')
.map(({ name }) => ({ name }));
return registeredFlags;
return this.config.featureFlags?.slice() ?? [];
}
get routes(): Routes {
@@ -61,34 +54,6 @@ export class PluginImpl<
return this.config.externalRoutes ?? ({} as ExternalRoutes);
}
output(): PluginOutput[] {
if (this.storedOutput) {
return this.storedOutput;
}
const outputs = new Array<PluginOutput>();
this.storedOutput = outputs;
if (this.config.featureFlags) {
for (const flag of this.config.featureFlags) {
outputs.push({ type: 'feature-flag', name: flag.name });
}
}
if (!this.config.register) {
return outputs;
}
this.config.register({
featureFlags: {
register(name) {
outputs.push({ type: 'feature-flag', name });
},
},
});
return this.storedOutput;
}
provide<T>(extension: Extension<T>): T {
return extension.expose(this);
}
@@ -20,10 +20,7 @@ export type {
AnyRoutes,
BackstagePlugin,
Extension,
FeatureFlagOutput,
FeatureFlagsHooks,
PluginConfig,
PluginHooks,
PluginOutput,
PluginFeatureFlagConfig,
} from './types';
@@ -17,24 +17,6 @@
import { RouteRef, SubRouteRef, ExternalRouteRef } from '../routing';
import { AnyApiFactory } from '../apis/system';
/**
* Replace with using {@link RouteRef}s.
* @deprecated will be removed
* @public
*/
export type FeatureFlagOutput = {
type: 'feature-flag';
name: string;
};
/**
* {@link FeatureFlagOutput} type.
*
* @public
* @deprecated Use {@link BackstagePlugin.getFeatureFlags} instead.
*/
export type PluginOutput = FeatureFlagOutput;
/**
* Plugin extension type.
*
@@ -72,10 +54,6 @@ export type BackstagePlugin<
ExternalRoutes extends AnyExternalRoutes = {},
> = {
getId(): string;
/**
* @deprecated use getFeatureFlags instead.
* */
output(): PluginOutput[];
getApis(): Iterable<AnyApiFactory>;
/**
* Returns all registered feature flags for this plugin.
@@ -107,23 +85,11 @@ export type PluginConfig<
> = {
id: string;
apis?: Iterable<AnyApiFactory>;
/** @deprecated use featureFlags property instead for defining feature flags */
register?(hooks: PluginHooks): void;
routes?: Routes;
externalRoutes?: ExternalRoutes;
featureFlags?: PluginFeatureFlagConfig[];
};
/**
* Holds hooks registered by the plugin.
*
* @deprecated - feature flags are now registered in plugin config under featureFlags
* @public
*/
export type PluginHooks = {
featureFlags: FeatureFlagsHooks;
};
/**
* Interface for registering feature flags hooks.
*
-15
View File
@@ -33,9 +33,6 @@ export type ErrorLike = {
[unknownKeys: string]: unknown;
};
// @public @deprecated
export type ErrorResponse = ErrorResponseBody;
// @public
export type ErrorResponseBody = {
error: SerializedError;
@@ -68,9 +65,6 @@ export class NotFoundError extends CustomErrorBase {}
// @public
export class NotModifiedError extends CustomErrorBase {}
// @public @deprecated
export function parseErrorResponse(response: Response): Promise<ErrorResponse>;
// @public
export function parseErrorResponseBody(
response: Response,
@@ -78,17 +72,8 @@ export function parseErrorResponseBody(
// @public
export class ResponseError extends Error {
// @deprecated
constructor(props: {
message: string;
response: Response;
data: ErrorResponseBody;
cause: Error;
});
readonly body: ErrorResponseBody;
readonly cause: Error;
// @deprecated
get data(): ErrorResponseBody;
static fromResponse(response: Response): Promise<ResponseError>;
readonly response: Response;
}
@@ -14,12 +14,12 @@
* limitations under the License.
*/
import { ErrorResponse } from '../serialization';
import { ErrorResponseBody } from '../serialization';
import { ResponseError } from './ResponseError';
describe('ResponseError', () => {
it('constructs itself from a response', async () => {
const body: ErrorResponse = {
const body: ErrorResponseBody = {
error: { name: 'Fours', message: 'Expected fives', stack: 'lines' },
request: { method: 'GET', url: '/' },
response: { statusCode: 444 },
+1 -13
View File
@@ -75,10 +75,7 @@ export class ResponseError extends Error {
});
}
/**
* @deprecated will be removed.
**/
constructor(props: {
private constructor(props: {
message: string;
response: Response;
data: ErrorResponseBody;
@@ -90,13 +87,4 @@ export class ResponseError extends Error {
this.body = props.data;
this.cause = props.cause;
}
/**
* The parsed JSON error body, as sent by the server.
* @deprecated use body instead.
*/
get data(): ErrorResponseBody {
// eslint-disable-next-line no-console
console.warn('ErrorResponse.data is deprecated, use .body instead.');
return this.body;
}
}
+2 -2
View File
@@ -16,5 +16,5 @@
export { deserializeError, serializeError, stringifyError } from './error';
export type { SerializedError } from './error';
export { parseErrorResponse, parseErrorResponseBody } from './response';
export type { ErrorResponse, ErrorResponseBody } from './response';
export { parseErrorResponseBody } from './response';
export type { ErrorResponseBody } from './response';
@@ -16,14 +16,6 @@
import { SerializedError } from './error';
/**
* A standard shape of JSON data returned as the body of backend errors.
*
* @public
* @deprecated - Use {@link ErrorResponseBody} instead.
*/
export type ErrorResponse = ErrorResponseBody;
/**
* A standard shape of JSON data returned as the body of backend errors.
*
@@ -48,25 +40,6 @@ export type ErrorResponseBody = {
};
};
/**
* Attempts to construct an ErrorResponse out of a failed server request.
* Assumes that the response has already been checked to be not ok. This
* function consumes the body of the response, and assumes that it hasn't
* been consumed before.
*
* The code is forgiving, and constructs a useful synthetic body as best it can
* if the response body wasn't on the expected form.
*
* @public
* @param response - The response of a failed request
* @deprecated - Use {@link parseErrorResponseBody} instead.
*/
export async function parseErrorResponse(
response: Response,
): Promise<ErrorResponse> {
return parseErrorResponseBody(response);
}
/**
* Attempts to construct an ErrorResponseBody out of a failed server request.
* Assumes that the response has already been checked to be not ok. This