feat: add backward compatibility for core anlytics api implementations

Signed-off-by: Camila Belo <camilaibs@gmail.com>
This commit is contained in:
Camila Belo
2024-01-30 11:31:46 +01:00
parent b5b9b8d98a
commit 311dda9e18
9 changed files with 227 additions and 2 deletions
+1 -1
View File
@@ -2,4 +2,4 @@
'@backstage/frontend-plugin-api': minor
---
**BREAKING**: Replace default plugin extension and plugin ids to be `app` instead of `root`.
**BREAKING**: Replace default plugin extension and plugin ids to be `app` instead of `root` and update the `MultipleAnalyticsApi` to support new Analytics API context type .
+1 -1
View File
@@ -4,4 +4,4 @@
'@backstage/plugin-analytics-module-ga': minor
---
**BREAKING**: Add support to the new analytics api and use `app` as default extension and plugin ids. It is breaking only because you will start seeing app as the new default id for extensions and plugins events.
Add support to the new analytics api.
@@ -8,6 +8,8 @@
import { AlertApi } from '@backstage/core-plugin-api';
import { alertApiRef } from '@backstage/core-plugin-api';
import { AlertMessage } from '@backstage/core-plugin-api';
import { AnalyticsApi as AnalyticsApi_2 } from '@backstage/core-plugin-api';
import { AnalyticsEvent as AnalyticsEvent_2 } from '@backstage/core-plugin-api';
import { AnyApiFactory } from '@backstage/core-plugin-api';
import { AnyApiRef } from '@backstage/core-plugin-api';
import { ApiFactory } from '@backstage/core-plugin-api';
@@ -993,6 +995,20 @@ export { identityApiRef };
export { microsoftAuthApiRef };
// @public
export class MultipleAnalyticsApi implements AnalyticsApi_2, AnalyticsApi {
captureEvent(event: AnalyticsEvent_2 | AnalyticsEvent): void;
static fromApis(
actualApis: (AnalyticsApi_2 | AnalyticsApi)[],
): MultipleAnalyticsApi;
}
// @public
export class NoOpAnalyticsApi implements AnalyticsApi_2, AnalyticsApi {
// (undocumented)
captureEvent(_event: AnalyticsEvent_2 | AnalyticsEvent): void;
}
export { OAuthApi };
export { OAuthRequestApi };
@@ -0,0 +1,64 @@
/*
* Copyright 2024 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { MultipleAnalyticsApi } from './MultipleAnalyticsApi';
describe('MultipleAnalyticsApi', () => {
const analyticsApiOne = { captureEvent: jest.fn() };
const analyticsApiTwo = { captureEvent: jest.fn() };
const multipleApis = MultipleAnalyticsApi.fromApis([
analyticsApiOne,
analyticsApiTwo,
]);
const event = {
action: 'navivate',
subject: '/path',
context: {
extension: 'App',
pluginId: 'plugin',
routeRef: 'unknown',
},
};
beforeEach(() => {
jest.clearAllMocks();
});
it('forwards events to all apis', () => {
// When an event is captured
multipleApis.captureEvent(event);
// Then both underlying APIs should have received the event
expect(analyticsApiOne.captureEvent).toHaveBeenCalledTimes(1);
expect(analyticsApiOne.captureEvent).toHaveBeenCalledWith(event);
expect(analyticsApiTwo.captureEvent).toHaveBeenCalledTimes(1);
expect(analyticsApiTwo.captureEvent).toHaveBeenCalledWith(event);
});
it('forwards events to all apis even if one throws an error', () => {
// Given one underlying API that throws on capture
analyticsApiOne.captureEvent.mockImplementation(() => {
throw new Error('!!!');
});
// When an event is captured
multipleApis.captureEvent(event);
// Then the other underlying API should have still received the event
expect(analyticsApiTwo.captureEvent).toHaveBeenCalledTimes(1);
expect(analyticsApiTwo.captureEvent).toHaveBeenCalledWith(event);
});
});
@@ -0,0 +1,76 @@
/*
* Copyright 2024 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { AnalyticsApi, AnalyticsEvent } from '@backstage/core-plugin-api';
import {
AnalyticsApi as NewAnalyicsApi,
AnalyticsEvent as NewAnalyicsEvent,
} from '../../definitions';
/**
* An implementation of the AnalyticsApi that can be used to forward analytics
* events to multiple concrete implementations.
*
* @public
*
* @example
*
* ```jsx
* createApiFactory({
* api: analyticsApiRef,
* deps: { configApi: configApiRef, identityApi: identityApiRef, storageApi: storageApiRef },
* factory: ({ configApi, identityApi, storageApi }) =>
* MultipleAnalyticsApi.fromApis([
* VendorAnalyticsApi.fromConfig(configApi, { identityApi }),
* CustomAnalyticsApi.fromConfig(configApi, { identityApi, storageApi }),
* ]),
* });
* ```
*/
export class MultipleAnalyticsApi implements AnalyticsApi, NewAnalyicsApi {
private constructor(
private readonly actualApis: (AnalyticsApi | NewAnalyicsApi)[],
) {}
/**
* Create an AnalyticsApi implementation from an array of concrete
* implementations.
*
* @example
*
* ```jsx
* MultipleAnalyticsApi.fromApis([
* SomeAnalyticsApi.fromConfig(configApi),
* new CustomAnalyticsApi(),
* ]);
* ```
*/
static fromApis(actualApis: (AnalyticsApi | NewAnalyicsApi)[]) {
return new MultipleAnalyticsApi(actualApis);
}
/**
* Forward the event to all configured analytics API implementations.
*/
captureEvent(event: AnalyticsEvent | NewAnalyicsEvent): void {
this.actualApis.forEach(analyticsApi => {
try {
analyticsApi.captureEvent(event as AnalyticsEvent & NewAnalyicsEvent);
} catch {
/* ignored */
}
});
}
}
@@ -0,0 +1,30 @@
/*
* Copyright 2024 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { AnalyticsApi, AnalyticsEvent } from '@backstage/core-plugin-api';
import {
AnalyticsApi as NewAnalyicsApi,
AnalyticsEvent as NewAnalyicsEvent,
} from '../../definitions';
/**
* Base implementation for the AnalyticsApi that does nothing.
*
* @public
*/
export class NoOpAnalyticsApi implements AnalyticsApi, NewAnalyicsApi {
captureEvent(_event: AnalyticsEvent | NewAnalyicsEvent): void {}
}
@@ -0,0 +1,18 @@
/*
* Copyright 2024 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { MultipleAnalyticsApi } from './MultipleAnalyticsApi';
export { NoOpAnalyticsApi } from './NoOpAnalyticsApi';
@@ -0,0 +1,20 @@
/*
* Copyright 2020 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.
*/
// This folder contains implementations for all core APIs.
// Plugins should rely on these APIs for functionality as much as possible.
export * from './AnalyticsApi';
@@ -15,4 +15,5 @@
*/
export * from './definitions';
export * from './implementations';
export * from './system';