From 29c38981657224aa1f5b5c240b40de645e0afaaa Mon Sep 17 00:00:00 2001 From: Patrick Jungermann Date: Sun, 14 Apr 2024 00:45:06 +0200 Subject: [PATCH] feat(events,github)!: remove use of `EventBroker` and `EventSubscriber` Remove use legacy event implementation including use of `EventBroker` and `EventSubscriber`. Tests migrated from the `EventBroker` to the `EventsService`. BREAKING CHANGE: - `GithubOrgEntityProvider.onEvent` made private - `GithubOrgEntityProvider.supportsEventTopics` removed - `eventBroker` option was removed from `GithubMultiOrgEntityProvider.fromConfig` - `GithubMultiOrgEntityProvider.supportsEventTopics` removed Signed-off-by: Patrick Jungermann --- .changeset/sweet-singers-argue.md | 19 ++++++++ .../api-report.md | 11 +---- .../GithubMultiOrgEntityProvider.test.ts | 43 ++++++++--------- .../providers/GithubMultiOrgEntityProvider.ts | 24 +--------- .../providers/GithubOrgEntityProvider.test.ts | 47 ++++++++++++------- .../src/providers/GithubOrgEntityProvider.ts | 18 ++----- 6 files changed, 75 insertions(+), 87 deletions(-) create mode 100644 .changeset/sweet-singers-argue.md diff --git a/.changeset/sweet-singers-argue.md b/.changeset/sweet-singers-argue.md new file mode 100644 index 0000000000..a410c1def9 --- /dev/null +++ b/.changeset/sweet-singers-argue.md @@ -0,0 +1,19 @@ +--- +'@backstage/plugin-catalog-backend-module-github': minor +--- + +Remove use of `EventBroker` and `EventSubscriber` for the GitHub org data providers. + +BREAKING CHANGE: + +- `GithubOrgEntityProvider.onEvent` made private +- `GithubOrgEntityProvider.supportsEventTopics` removed +- `eventBroker` option was removed from `GithubMultiOrgEntityProvider.fromConfig` +- `GithubMultiOrgEntityProvider.supportsEventTopics` removed + +This change only impacts users who still use the legacy backend system +**and** who still use `eventBroker` as option when creating these +entity providers. + +Please pass the `EventsService` instance as option `events` instead. +You can find more information at the [installation documentation](https://backstage.io/docs/integrations/github/org/#legacy-backend-system). diff --git a/plugins/catalog-backend-module-github/api-report.md b/plugins/catalog-backend-module-github/api-report.md index 5214841ac4..b53d1b7b17 100644 --- a/plugins/catalog-backend-module-github/api-report.md +++ b/plugins/catalog-backend-module-github/api-report.md @@ -11,7 +11,6 @@ import { Config } from '@backstage/config'; import { Entity } from '@backstage/catalog-model'; import { EntityProvider } from '@backstage/plugin-catalog-node'; import { EntityProviderConnection } from '@backstage/plugin-catalog-node'; -import { EventBroker } from '@backstage/plugin-events-node'; import { EventParams } from '@backstage/plugin-events-node'; import { EventsService } from '@backstage/plugin-events-node'; import { EventSubscriber } from '@backstage/plugin-events-node'; @@ -166,8 +165,6 @@ export class GithubMultiOrgEntityProvider implements EntityProvider { // @public export interface GithubMultiOrgEntityProviderOptions { - // @deprecated - eventBroker?: EventBroker; events?: EventsService; githubCredentialsProvider?: GithubCredentialsProvider; githubUrl: string; @@ -219,9 +216,7 @@ export class GitHubOrgEntityProvider extends GithubOrgEntityProvider { } // @public -export class GithubOrgEntityProvider - implements EntityProvider, EventSubscriber -{ +export class GithubOrgEntityProvider implements EntityProvider { constructor(options: { events?: EventsService; id: string; @@ -241,11 +236,7 @@ export class GithubOrgEntityProvider ): GithubOrgEntityProvider; // (undocumented) getProviderName(): string; - // (undocumented) - onEvent(params: EventParams): Promise; read(options?: { logger?: LoggerService }): Promise; - // (undocumented) - supportsEventTopics(): string[]; } // @public @deprecated (undocumented) diff --git a/plugins/catalog-backend-module-github/src/providers/GithubMultiOrgEntityProvider.test.ts b/plugins/catalog-backend-module-github/src/providers/GithubMultiOrgEntityProvider.test.ts index d5c073a89d..0542e64d64 100644 --- a/plugins/catalog-backend-module-github/src/providers/GithubMultiOrgEntityProvider.test.ts +++ b/plugins/catalog-backend-module-github/src/providers/GithubMultiOrgEntityProvider.test.ts @@ -19,7 +19,10 @@ import { GroupEntity, UserEntity } from '@backstage/catalog-model'; import { ConfigReader } from '@backstage/config'; import { GithubCredentialsProvider } from '@backstage/integration'; import { EntityProviderConnection } from '@backstage/plugin-catalog-node'; -import { EventSubscriber } from '@backstage/plugin-events-node'; +import { + DefaultEventsService, + EventsService, +} from '@backstage/plugin-events-node'; import { graphql } from '@octokit/graphql'; import { GithubMultiOrgEntityProvider, @@ -717,15 +720,16 @@ describe('GithubMultiOrgEntityProvider', () => { }); describe('events', () => { - let onEvent: Function; + let events: EventsService; const entityProviderConnection: EntityProviderConnection = { applyMutation: jest.fn(), refresh: jest.fn(), }; - beforeEach(() => { + beforeEach(async () => { const logger = getVoidLogger(); + events = DefaultEventsService.create({ logger }); const config = new ConfigReader({ integrations: { github: [ @@ -745,29 +749,22 @@ describe('GithubMultiOrgEntityProvider', () => { getCredentials: mockGetCredentials, }; - const mockEventBroker = { - publish: async () => {}, - subscribe: (subscriber: EventSubscriber) => { - onEvent = subscriber.onEvent; - }, - }; - const entityProvider = GithubMultiOrgEntityProvider.fromConfig(config, { + events, id: 'my-id', githubCredentialsProvider, githubUrl: 'https://github.com', logger, orgs: ['orgA', 'orgB'], - eventBroker: mockEventBroker, }); - entityProvider.connect(entityProviderConnection); + await entityProvider.connect(entityProviderConnection); }); afterEach(() => jest.resetAllMocks()); it('should ignore events from non-applicable orgs', async () => { - await onEvent({ + await events.publish({ topic: 'github.organization', eventPayload: { action: 'member_added', @@ -787,7 +784,7 @@ describe('GithubMultiOrgEntityProvider', () => { expect(entityProviderConnection.applyMutation).not.toHaveBeenCalled(); - await onEvent({ + await events.publish({ topic: 'github.installation', eventPayload: { action: 'created', @@ -901,7 +898,7 @@ describe('GithubMultiOrgEntityProvider', () => { (graphql.defaults as jest.Mock).mockReturnValue(mockClient); - await onEvent({ + await events.publish({ topic: 'github.installation', eventPayload: { action: 'created', @@ -1033,7 +1030,7 @@ describe('GithubMultiOrgEntityProvider', () => { (graphql.defaults as jest.Mock).mockReturnValue(mockClient); - await onEvent({ + await events.publish({ topic: 'github.organization', eventPayload: { action: 'member_added', @@ -1103,7 +1100,7 @@ describe('GithubMultiOrgEntityProvider', () => { (graphql.defaults as jest.Mock).mockReturnValue(mockClient); - await onEvent({ + await events.publish({ topic: 'github.organization', eventPayload: { action: 'member_removed', @@ -1198,7 +1195,7 @@ describe('GithubMultiOrgEntityProvider', () => { (graphql.defaults as jest.Mock).mockReturnValue(mockClient); - await onEvent({ + await events.publish({ topic: 'github.organization', eventPayload: { action: 'member_removed', @@ -1253,7 +1250,7 @@ describe('GithubMultiOrgEntityProvider', () => { describe('team', () => { it('should create a new group from a new team', async () => { - await onEvent({ + await events.publish({ topic: 'github.team', eventPayload: { action: 'created', @@ -1312,7 +1309,7 @@ describe('GithubMultiOrgEntityProvider', () => { }); it('should remove a group from a deleted team', async () => { - await onEvent({ + await events.publish({ topic: 'github.team', eventPayload: { action: 'deleted', @@ -1467,7 +1464,7 @@ describe('GithubMultiOrgEntityProvider', () => { (graphql.defaults as jest.Mock).mockReturnValue(mockClient); - await onEvent({ + await events.publish({ topic: 'github.team', eventPayload: { action: 'edited', @@ -1676,7 +1673,7 @@ describe('GithubMultiOrgEntityProvider', () => { (graphql.defaults as jest.Mock).mockReturnValue(mockClient); - await onEvent({ + await events.publish({ topic: 'github.membership', eventPayload: { action: 'added', @@ -1848,7 +1845,7 @@ describe('GithubMultiOrgEntityProvider', () => { (graphql.defaults as jest.Mock).mockReturnValue(mockClient); - await onEvent({ + await events.publish({ topic: 'github.membership', eventPayload: { action: 'removed', diff --git a/plugins/catalog-backend-module-github/src/providers/GithubMultiOrgEntityProvider.ts b/plugins/catalog-backend-module-github/src/providers/GithubMultiOrgEntityProvider.ts index 0f3b7a5b79..f07d033ecd 100644 --- a/plugins/catalog-backend-module-github/src/providers/GithubMultiOrgEntityProvider.ts +++ b/plugins/catalog-backend-module-github/src/providers/GithubMultiOrgEntityProvider.ts @@ -38,11 +38,7 @@ import { EntityProvider, EntityProviderConnection, } from '@backstage/plugin-catalog-node'; -import { - EventBroker, - EventParams, - EventsService, -} from '@backstage/plugin-events-node'; +import { EventParams, EventsService } from '@backstage/plugin-events-node'; import { graphql } from '@octokit/graphql'; import { InstallationCreatedEvent, @@ -157,13 +153,6 @@ export interface GithubMultiOrgEntityProviderOptions { * By default, groups will be namespaced according to their GitHub org. */ teamTransformer?: TeamTransformer; - - /** - * An EventBroker to subscribe this provider to GitHub events to trigger delta mutations - * - * @deprecated Use `events` instead. - */ - eventBroker?: EventBroker; } type CreateDeltaOperation = (entities: Entity[]) => { @@ -213,13 +202,6 @@ export class GithubMultiOrgEntityProvider implements EntityProvider { provider.schedule(options.schedule); - if (options.eventBroker) { - options.eventBroker.subscribe({ - supportsEventTopics: provider.supportsEventTopics.bind(provider), - onEvent: provider.onEvent.bind(provider), - }); - } - return provider; } @@ -336,10 +318,6 @@ export class GithubMultiOrgEntityProvider implements EntityProvider { markCommitComplete(); } - private supportsEventTopics(): string[] { - return EVENT_TOPICS; - } - private async onEvent(params: EventParams): Promise { const { logger } = this.options; logger.debug(`Received event from ${params.topic}`); diff --git a/plugins/catalog-backend-module-github/src/providers/GithubOrgEntityProvider.test.ts b/plugins/catalog-backend-module-github/src/providers/GithubOrgEntityProvider.test.ts index 486ff47f1c..dade7d7983 100644 --- a/plugins/catalog-backend-module-github/src/providers/GithubOrgEntityProvider.test.ts +++ b/plugins/catalog-backend-module-github/src/providers/GithubOrgEntityProvider.test.ts @@ -22,7 +22,10 @@ import { } from '@backstage/integration'; import { EntityProviderConnection } from '@backstage/plugin-catalog-node'; import { graphql } from '@octokit/graphql'; -import { EventParams } from '@backstage/plugin-events-node'; +import { + DefaultEventsService, + EventParams, +} from '@backstage/plugin-events-node'; import { GithubOrgEntityProvider } from './GithubOrgEntityProvider'; import { withLocations } from '../lib/withLocations'; @@ -267,6 +270,7 @@ describe('GithubOrgEntityProvider', () => { }; const logger = getVoidLogger(); + const events = DefaultEventsService.create({ logger }); const gitHubConfig: GithubIntegrationConfig = { host: 'github.com', }; @@ -281,6 +285,7 @@ describe('GithubOrgEntityProvider', () => { }; const entityProvider = new GithubOrgEntityProvider({ + events, id: 'my-id', githubCredentialsProvider, orgUrl: 'https://github.com/backstage', @@ -288,7 +293,7 @@ describe('GithubOrgEntityProvider', () => { logger, }); - entityProvider.connect(entityProviderConnection); + await entityProvider.connect(entityProviderConnection); const expectedEntity = { apiVersion: 'backstage.io/v1alpha1', @@ -330,8 +335,7 @@ describe('GithubOrgEntityProvider', () => { }, }, }; - - await entityProvider.onEvent(event); + await events.publish(event); expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(1); expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ @@ -353,6 +357,7 @@ describe('GithubOrgEntityProvider', () => { }; const logger = getVoidLogger(); + const events = DefaultEventsService.create({ logger }); const gitHubConfig: GithubIntegrationConfig = { host: 'github.com', }; @@ -367,6 +372,7 @@ describe('GithubOrgEntityProvider', () => { }; const entityProvider = new GithubOrgEntityProvider({ + events, id: 'my-id', githubCredentialsProvider, orgUrl: 'https://github.com/backstage', @@ -374,7 +380,7 @@ describe('GithubOrgEntityProvider', () => { logger, }); - entityProvider.connect(entityProviderConnection); + await entityProvider.connect(entityProviderConnection); const expectedEntity = { apiVersion: 'backstage.io/v1alpha1', @@ -416,8 +422,7 @@ describe('GithubOrgEntityProvider', () => { }, }, }; - - await entityProvider.onEvent(event); + await events.publish(event); expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(1); expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ @@ -439,6 +444,7 @@ describe('GithubOrgEntityProvider', () => { }; const logger = getVoidLogger(); + const events = DefaultEventsService.create({ logger }); const gitHubConfig: GithubIntegrationConfig = { host: 'github.com', }; @@ -453,6 +459,7 @@ describe('GithubOrgEntityProvider', () => { }; const entityProvider = new GithubOrgEntityProvider({ + events, id: 'my-id', githubCredentialsProvider, orgUrl: 'https://github.com/backstage', @@ -508,7 +515,7 @@ describe('GithubOrgEntityProvider', () => { }, }; - await entityProvider.onEvent(event); + await events.publish(event); expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(1); expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ @@ -530,6 +537,7 @@ describe('GithubOrgEntityProvider', () => { }; const logger = getVoidLogger(); + const events = DefaultEventsService.create({ logger }); const gitHubConfig: GithubIntegrationConfig = { host: 'github.com', }; @@ -544,6 +552,7 @@ describe('GithubOrgEntityProvider', () => { }; const entityProvider = new GithubOrgEntityProvider({ + events, id: 'my-id', githubCredentialsProvider, orgUrl: 'https://github.com/backstage', @@ -551,7 +560,7 @@ describe('GithubOrgEntityProvider', () => { logger, }); - entityProvider.connect(entityProviderConnection); + await entityProvider.connect(entityProviderConnection); const expectedEntity = { apiVersion: 'backstage.io/v1alpha1', @@ -600,7 +609,7 @@ describe('GithubOrgEntityProvider', () => { }, }; - await entityProvider.onEvent(event); + await events.publish(event); expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(1); expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ @@ -622,6 +631,7 @@ describe('GithubOrgEntityProvider', () => { }; const logger = getVoidLogger(); + const events = DefaultEventsService.create({ logger }); const gitHubConfig: GithubIntegrationConfig = { host: 'github.com', }; @@ -636,6 +646,7 @@ describe('GithubOrgEntityProvider', () => { }; const entityProvider = new GithubOrgEntityProvider({ + events, id: 'my-id', githubCredentialsProvider, orgUrl: 'https://github.com/backstage', @@ -717,7 +728,7 @@ describe('GithubOrgEntityProvider', () => { (graphql.defaults as jest.Mock).mockReturnValue(mockClient); - entityProvider.connect(entityProviderConnection); + await entityProvider.connect(entityProviderConnection); const event: EventParams = { topic: 'github.team', @@ -744,7 +755,7 @@ describe('GithubOrgEntityProvider', () => { }, }; - await entityProvider.onEvent(event); + await events.publish(event); await new Promise(process.nextTick); expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(1); @@ -871,6 +882,7 @@ describe('GithubOrgEntityProvider', () => { }; const logger = getVoidLogger(); + const events = DefaultEventsService.create({ logger }); const gitHubConfig: GithubIntegrationConfig = { host: 'github.com', }; @@ -885,6 +897,7 @@ describe('GithubOrgEntityProvider', () => { }; const entityProvider = new GithubOrgEntityProvider({ + events, id: 'my-id', githubCredentialsProvider, orgUrl: 'https://github.com/backstage', @@ -965,7 +978,7 @@ describe('GithubOrgEntityProvider', () => { }); (graphql.defaults as jest.Mock).mockReturnValue(mockClient); - entityProvider.connect(entityProviderConnection); + await entityProvider.connect(entityProviderConnection); const event: EventParams = { topic: 'github.membership', @@ -989,7 +1002,7 @@ describe('GithubOrgEntityProvider', () => { }, }; - await entityProvider.onEvent(event); + await events.publish(event); await new Promise(process.nextTick); expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(1); @@ -1117,6 +1130,7 @@ describe('GithubOrgEntityProvider', () => { }; const logger = getVoidLogger(); + const events = DefaultEventsService.create({ logger }); const gitHubConfig: GithubIntegrationConfig = { host: 'github.com', }; @@ -1131,6 +1145,7 @@ describe('GithubOrgEntityProvider', () => { }; const entityProvider = new GithubOrgEntityProvider({ + events, id: 'my-id', githubCredentialsProvider, orgUrl: 'https://github.com/backstage', @@ -1187,7 +1202,7 @@ describe('GithubOrgEntityProvider', () => { }); (graphql.defaults as jest.Mock).mockReturnValue(mockClient); - entityProvider.connect(entityProviderConnection); + await entityProvider.connect(entityProviderConnection); const event: EventParams = { topic: 'github.membership', @@ -1211,7 +1226,7 @@ describe('GithubOrgEntityProvider', () => { }, }; - await entityProvider.onEvent(event); + await events.publish(event); await new Promise(process.nextTick); expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(1); diff --git a/plugins/catalog-backend-module-github/src/providers/GithubOrgEntityProvider.ts b/plugins/catalog-backend-module-github/src/providers/GithubOrgEntityProvider.ts index f23ef8a98b..ba7602f962 100644 --- a/plugins/catalog-backend-module-github/src/providers/GithubOrgEntityProvider.ts +++ b/plugins/catalog-backend-module-github/src/providers/GithubOrgEntityProvider.ts @@ -28,11 +28,7 @@ import { EntityProvider, EntityProviderConnection, } from '@backstage/plugin-catalog-node'; -import { - EventParams, - EventsService, - EventSubscriber, -} from '@backstage/plugin-events-node'; +import { EventParams, EventsService } from '@backstage/plugin-events-node'; import { graphql } from '@octokit/graphql'; import { MembershipEvent, @@ -138,9 +134,7 @@ export interface GithubOrgEntityProviderOptions { * * @public */ -export class GithubOrgEntityProvider - implements EntityProvider, EventSubscriber -{ +export class GithubOrgEntityProvider implements EntityProvider { private readonly credentialsProvider: GithubCredentialsProvider; private connection?: EntityProviderConnection; private scheduleFn?: () => Promise; @@ -268,8 +262,7 @@ export class GithubOrgEntityProvider markCommitComplete(); } - /** {@inheritdoc @backstage/plugin-events-node#EventSubscriber.onEvent} */ - async onEvent(params: EventParams): Promise { + private async onEvent(params: EventParams): Promise { const { logger } = this.options; logger.debug(`Received event from ${params.topic}`); @@ -335,11 +328,6 @@ export class GithubOrgEntityProvider return; } - /** {@inheritdoc @backstage/plugin-events-node#EventSubscriber.supportsEventTopics} */ - supportsEventTopics(): string[] { - return EVENT_TOPICS; - } - private async onTeamEditedInOrganization( event: TeamEditedEvent, createDeltaOperation: DeferredEntitiesBuilder,