Skip to content

Commit

Permalink
Integrate notifications into the tech-insights backend
Browse files Browse the repository at this point in the history
Make the notifications available as part of the FactRetriever context.
Now that this plugin is available, it would make sense to let users be
able to use this service to trigger notifications when a check is failing.

The usage of this service will be up to the end user, and no logic has to
be implemented into the tech-insights directly.

Signed-off-by: ivangonzalezacuna <[email protected]>
  • Loading branch information
ivangonzalezacuna committed Oct 9, 2024
1 parent 414653d commit ff83d67
Show file tree
Hide file tree
Showing 13 changed files with 120 additions and 1 deletion.
9 changes: 9 additions & 0 deletions workspaces/tech-insights/.changeset/sixty-chicken-wave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@backstage-community/plugin-tech-insights-backend': patch
'@backstage-community/plugin-tech-insights-node': patch
---

Inetgrate notifications plugin into the tech-insights.

If the notifications are enabled, the user will be able to access the
notification service as part of the handler `ctx` when defining the `FactRetriever`.
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
"@backstage/catalog-model": "^1.7.0",
"@backstage/config": "^1.2.0",
"@backstage/errors": "^1.2.4",
"@backstage/plugin-notifications-node": "^0.2.6",
"@backstage/types": "^1.1.1",
"@types/express": "^4.17.6",
"@types/luxon": "^3.0.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import {
techdocsFactRetriever,
} from '../service';
import { createFactRetrieverRegistrationFromConfig } from './config';
import { notificationService } from '@backstage/plugin-notifications-node';

/**
* The tech-insights backend plugin.
Expand Down Expand Up @@ -101,6 +102,7 @@ export const techInsightsPlugin = createBackendPlugin({
logger: coreServices.logger,
scheduler: coreServices.scheduler,
auth: coreServices.auth,
notification: notificationService,
},
async init({
config,
Expand All @@ -110,6 +112,7 @@ export const techInsightsPlugin = createBackendPlugin({
logger,
scheduler,
auth,
notification,
}) {
const factRetrievers: FactRetrieverRegistration[] = Object.entries(
addedFactRetrievers,
Expand All @@ -134,6 +137,7 @@ export const techInsightsPlugin = createBackendPlugin({
persistenceContext,
scheduler,
auth,
notification,
});

httpRouter.use(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {
mockServices,
} from '@backstage/backend-test-utils';
import { DefaultSchedulerService } from '@backstage/backend-defaults/scheduler';
import { NotificationService } from '@backstage/plugin-notifications-node';

jest.setTimeout(60_000);

Expand Down Expand Up @@ -65,6 +66,10 @@ const testFactRetriever: FactRetriever = {
}),
};

const notificationService: jest.Mocked<NotificationService> = {
send: jest.fn(),
};

const defaultCadence = '1 * * * *';

describe('FactRetrieverEngine', () => {
Expand Down Expand Up @@ -147,6 +152,7 @@ describe('FactRetrieverEngine', () => {
getBaseUrl: (_: string) => Promise.resolve('http://mock.url'),
getExternalBaseUrl: (_: string) => Promise.resolve('http://mock.url'),
},
notification: notificationService,
},
factRetrieverRegistry: createMockFactRetrieverRegistry(
cadence,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { GetEntitiesResponse } from '@backstage/catalog-client';
import { entityMetadataFactRetriever } from './entityMetadataFactRetriever';
import { mockServices } from '@backstage/backend-test-utils';
import { DiscoveryService } from '@backstage/backend-plugin-api';
import { NotificationService } from '@backstage/plugin-notifications-node';

const getEntitiesMock = jest.fn();
jest.mock('@backstage/catalog-client', () => {
Expand All @@ -34,6 +35,10 @@ const discovery: jest.Mocked<DiscoveryService> = {
getExternalBaseUrl: jest.fn(),
};

const notificationService: jest.Mocked<NotificationService> = {
send: jest.fn(),
};

const defaultEntityListResponse: GetEntitiesResponse = {
items: [
{
Expand Down Expand Up @@ -103,6 +108,7 @@ const handlerContext = {
logger: mockServices.logger.mock(),
auth: mockServices.auth(),
config: ConfigReader.fromConfigs([]),
notification: notificationService,
};

const entityFactRetriever = entityMetadataFactRetriever;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { ConfigReader } from '@backstage/config';
import { GetEntitiesResponse } from '@backstage/catalog-client';
import { mockServices } from '@backstage/backend-test-utils';
import { DiscoveryService } from '@backstage/backend-plugin-api';
import { NotificationService } from '@backstage/plugin-notifications-node';

const getEntitiesMock = jest.fn();
jest.mock('@backstage/catalog-client', () => {
Expand All @@ -34,6 +35,10 @@ const discovery: jest.Mocked<DiscoveryService> = {
getExternalBaseUrl: jest.fn(),
};

const notificationService: jest.Mocked<NotificationService> = {
send: jest.fn(),
};

const defaultEntityListResponse: GetEntitiesResponse = {
items: [
{
Expand Down Expand Up @@ -103,6 +108,7 @@ const handlerContext = {
logger: mockServices.logger.mock(),
auth: mockServices.auth(),
config: ConfigReader.fromConfigs([]),
notification: notificationService,
};

const entityFactRetriever = entityOwnershipFactRetriever;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { ConfigReader } from '@backstage/config';
import { GetEntitiesResponse } from '@backstage/catalog-client';
import { mockServices } from '@backstage/backend-test-utils';
import { DiscoveryService } from '@backstage/backend-plugin-api';
import { NotificationService } from '@backstage/plugin-notifications-node';

const getEntitiesMock = jest.fn();
jest.mock('@backstage/catalog-client', () => {
Expand All @@ -34,6 +35,10 @@ const discovery: jest.Mocked<DiscoveryService> = {
getExternalBaseUrl: jest.fn(),
};

const notificationService: jest.Mocked<NotificationService> = {
send: jest.fn(),
};

const defaultEntityListResponse: GetEntitiesResponse = {
items: [
{
Expand Down Expand Up @@ -104,6 +109,7 @@ const handlerContext = {
logger: mockServices.logger.mock(),
auth: mockServices.auth(),
config: ConfigReader.fromConfigs([]),
notification: notificationService,
};

const entityFactRetriever = techdocsFactRetriever;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
import { DateTime } from 'luxon';
import { mockServices } from '@backstage/backend-test-utils';
import { DefaultSchedulerService } from '@backstage/backend-defaults/scheduler';
import { NotificationService } from '@backstage/plugin-notifications-node';

describe('Tech Insights router tests', () => {
let app: express.Express;
Expand All @@ -42,6 +43,10 @@ describe('Tech Insights router tests', () => {
} as unknown as TechInsightsStore,
};

const notificationService: jest.Mocked<NotificationService> = {
send: jest.fn(),
};

afterEach(() => {
jest.resetAllMocks();
});
Expand All @@ -62,6 +67,7 @@ describe('Tech Insights router tests', () => {
getExternalBaseUrl: (_: string) => Promise.resolve('http://mock.url'),
},
auth: mockServices.auth(),
notification: notificationService,
});

const router = await createRouter({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { DefaultFactRetrieverRegistry } from './fact/FactRetrieverRegistry';
import { Knex } from 'knex';
import { mockServices } from '@backstage/backend-test-utils';
import { DatabaseService } from '@backstage/backend-plugin-api';
import { NotificationService } from '@backstage/plugin-notifications-node';

jest.mock('./fact/FactRetrieverRegistry');
jest.mock('./fact/FactRetrieverEngine', () => ({
Expand All @@ -31,6 +32,10 @@ jest.mock('./fact/FactRetrieverEngine', () => ({
},
}));

const notificationService: jest.Mocked<NotificationService> = {
send: jest.fn(),
};

describe('buildTechInsightsContext', () => {
const logger = mockServices.logger.mock();
const database: DatabaseService = {
Expand Down Expand Up @@ -61,6 +66,7 @@ describe('buildTechInsightsContext', () => {
config: ConfigReader.fromConfigs([]),
discovery: discoveryMock,
auth: mockServices.auth(),
notification: notificationService,
});
expect(DefaultFactRetrieverRegistry).toHaveBeenCalledTimes(1);
});
Expand All @@ -77,6 +83,7 @@ describe('buildTechInsightsContext', () => {
config: ConfigReader.fromConfigs([]),
discovery: discoveryMock,
auth: mockServices.auth(),
notification: notificationService,
});
expect(DefaultFactRetrieverRegistry).not.toHaveBeenCalled();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
LoggerService,
SchedulerService,
} from '@backstage/backend-plugin-api';
import { NotificationService } from '@backstage/plugin-notifications-node';

/**
* @public
Expand Down Expand Up @@ -82,6 +83,7 @@ export interface TechInsightsOptions<
database: DatabaseService;
scheduler: SchedulerService;
auth: AuthService;
notification: NotificationService;
}

/**
Expand Down Expand Up @@ -125,6 +127,7 @@ export const buildTechInsightsContext = async <
logger,
scheduler,
auth,
notification,
} = options;

const buildFactRetrieverRegistry = (): FactRetrieverRegistry => {
Expand Down Expand Up @@ -156,6 +159,7 @@ export const buildTechInsightsContext = async <
discovery,
logger,
auth,
notification,
},
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"@backstage/backend-plugin-api": "^1.0.0",
"@backstage/catalog-model": "^1.7.0",
"@backstage/config": "^1.2.0",
"@backstage/plugin-notifications-node": "^0.2.6",
"@backstage/types": "^1.1.1",
"@types/luxon": "^3.0.0",
"luxon": "^3.0.0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
DiscoveryService,
LoggerService,
} from '@backstage/backend-plugin-api';
import { NotificationService } from '@backstage/plugin-notifications-node';

/**
* A container for facts. The shape of the fact records needs to correspond to the FactSchema with same `ref` value.
Expand Down Expand Up @@ -93,6 +94,7 @@ export type FactRetrieverContext = {
discovery: DiscoveryService;
logger: LoggerService;
auth: AuthService;
notification: NotificationService;
entityFilter?:
| Record<string, string | symbol | (string | symbol)[]>[]
| Record<string, string | symbol | (string | symbol)[]>;
Expand Down
63 changes: 62 additions & 1 deletion workspaces/tech-insights/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2813,6 +2813,7 @@ __metadata:
"@backstage/cli": ^0.27.1
"@backstage/config": ^1.2.0
"@backstage/errors": ^1.2.4
"@backstage/plugin-notifications-node": ^0.2.6
"@backstage/types": ^1.1.1
"@types/express": ^4.17.6
"@types/lodash": ^4.14.151
Expand Down Expand Up @@ -2859,6 +2860,7 @@ __metadata:
"@backstage/catalog-model": ^1.7.0
"@backstage/cli": ^0.27.1
"@backstage/config": ^1.2.0
"@backstage/plugin-notifications-node": ^0.2.6
"@backstage/types": ^1.1.1
"@types/luxon": ^3.0.0
luxon: ^3.0.0
Expand Down Expand Up @@ -4558,6 +4560,33 @@ __metadata:
languageName: node
linkType: hard

"@backstage/plugin-notifications-common@npm:^0.0.5":
version: 0.0.5
resolution: "@backstage/plugin-notifications-common@npm:0.0.5"
dependencies:
"@backstage/config": ^1.2.0
"@material-ui/icons": ^4.9.1
checksum: 3cdfd9565d9bfcb2d7187381e697978833d54ce6633baa4d18494a55761006f7893b73ddfdfc6e0d068fe470559aa2febbd7dac401fbcad2bff9a959f61a71d1
languageName: node
linkType: hard

"@backstage/plugin-notifications-node@npm:^0.2.6":
version: 0.2.6
resolution: "@backstage/plugin-notifications-node@npm:0.2.6"
dependencies:
"@backstage/backend-common": ^0.25.0
"@backstage/backend-plugin-api": ^1.0.0
"@backstage/catalog-client": ^1.7.0
"@backstage/catalog-model": ^1.7.0
"@backstage/plugin-notifications-common": ^0.0.5
"@backstage/plugin-signals-node": ^0.1.11
knex: ^3.0.0
node-fetch: ^2.7.0
uuid: ^9.0.0
checksum: 8dabc31a84bb6aea2e52eea9103e79f545794d01d75bda273117b362a3548cb6813eaca5883389d7943c8f6d01bca0d646af079a3b2903ec89adc631ad51a21b
languageName: node
linkType: hard

"@backstage/plugin-org@npm:^0.6.29":
version: 0.6.29
resolution: "@backstage/plugin-org@npm:0.6.29"
Expand Down Expand Up @@ -5179,6 +5208,23 @@ __metadata:
languageName: node
linkType: hard

"@backstage/plugin-signals-node@npm:^0.1.11":
version: 0.1.11
resolution: "@backstage/plugin-signals-node@npm:0.1.11"
dependencies:
"@backstage/backend-common": ^0.25.0
"@backstage/backend-plugin-api": ^1.0.0
"@backstage/config": ^1.2.0
"@backstage/plugin-auth-node": ^0.5.2
"@backstage/plugin-events-node": ^0.4.0
"@backstage/types": ^1.1.1
express: ^4.17.1
uuid: ^9.0.0
ws: ^8.18.0
checksum: 1c4e012666d40a5fddcc7a88d7b5d776e6aea958b5adafc2ae9619354aa693c63f30e6b52d02d6b418de6bac8462422dff0d8c98ace4996ff84c51093065409c
languageName: node
linkType: hard

"@backstage/plugin-signals-react@npm:^0.0.5":
version: 0.0.5
resolution: "@backstage/plugin-signals-react@npm:0.0.5"
Expand Down Expand Up @@ -33835,7 +33881,7 @@ __metadata:
languageName: node
linkType: hard

"ws@npm:8.17.1, ws@npm:^8.11.0, ws@npm:^8.12.0, ws@npm:^8.13.0, ws@npm:^8.15.0, ws@npm:^8.16.0":
"ws@npm:8.17.1":
version: 8.17.1
resolution: "ws@npm:8.17.1"
peerDependencies:
Expand Down Expand Up @@ -33865,6 +33911,21 @@ __metadata:
languageName: node
linkType: hard

"ws@npm:^8.11.0, ws@npm:^8.12.0, ws@npm:^8.13.0, ws@npm:^8.15.0, ws@npm:^8.16.0, ws@npm:^8.18.0":
version: 8.18.0
resolution: "ws@npm:8.18.0"
peerDependencies:
bufferutil: ^4.0.1
utf-8-validate: ">=5.0.2"
peerDependenciesMeta:
bufferutil:
optional: true
utf-8-validate:
optional: true
checksum: 91d4d35bc99ff6df483bdf029b9ea4bfd7af1f16fc91231a96777a63d263e1eabf486e13a2353970efc534f9faa43bdbf9ee76525af22f4752cbc5ebda333975
languageName: node
linkType: hard

"xcase@npm:^2.0.1":
version: 2.0.1
resolution: "xcase@npm:2.0.1"
Expand Down

0 comments on commit ff83d67

Please sign in to comment.