diff --git a/src/reactions/gitlab/index.ts b/src/reactions/gitlab/index.ts new file mode 100644 index 0000000..68cb178 --- /dev/null +++ b/src/reactions/gitlab/index.ts @@ -0,0 +1,16 @@ +import { TwitchChat } from '../../services/TwitchChat'; +import { StreamLabs } from '../../services/StreamLabs'; +import { MergeRequestMerged } from './merge-request-merged'; +import { MergeRequestPayload } from '../../schemas/gitlab/merge-request-payload'; +import { MergeRequestOpened } from './merge-request-opened'; +import { Reaction } from '../github/reaction'; + +export const buildGitLabReactions = ( + twitchChat: TwitchChat, + streamlabs: StreamLabs, +): Reaction[] => { + return [ + new MergeRequestMerged(twitchChat, streamlabs), + new MergeRequestOpened(twitchChat, streamlabs), + ]; +}; diff --git a/src/routes/gitlab/index.ts b/src/routes/gitlab/index.ts index 7775891..f2448ed 100644 --- a/src/routes/gitlab/index.ts +++ b/src/routes/gitlab/index.ts @@ -1,7 +1,12 @@ import { ServerRoute, ResponseObject, Request, ResponseToolkit } from '@hapi/hapi'; import { gitlabHeader } from '../../schemas/gitlab/joi/gitlab-headers-schema'; +import { buildGitLabReactions } from '../../reactions/gitlab'; +import { TwitchChat } from '../../services/TwitchChat'; +import { Config } from '../../config'; +import { StreamLabs } from '../../services/StreamLabs'; +import { MergeRequestPayload } from '../../schemas/gitlab/merge-request-payload'; -export const routes = (): ServerRoute[] => { +export const routes = (config: Config): ServerRoute[] => { return [ { method: 'POST', @@ -11,9 +16,31 @@ export const routes = (): ServerRoute[] => { }, }, handler: async (request: Request, h: ResponseToolkit): Promise => { - const { headers } = request; + const { headers, payload } = (request as unknown) as { + headers: { 'x-gitlab-event': string }; + payload: MergeRequestPayload; + }; const event = headers['x-gitlab-event']; + const twitchChat = new TwitchChat({ + botName: config?.TWITCH_BOT_NAME || '', + botToken: config?.TWITCH_BOT_TOKEN || '', + channel: config?.TWITCH_BOT_CHANNEL || '', + }); + const streamlabs = new StreamLabs({ token: config?.STREAMLABS_TOKEN || '' }); + + const reactions = buildGitLabReactions(twitchChat, streamlabs).filter((reaction) => + reaction.canHandle({ event, payload, config }), + ); + + if (reactions.length > 0) { + const messages = await Promise.all( + reactions.map((reaction) => reaction.handle({ payload })), + ); + + return h.response({ messages }).code(200); + } + return h.response({ message: `Ignoring event: '${event}'` }).code(200); }, path: '/gitlab', diff --git a/src/routes/index.ts b/src/routes/index.ts index 164e799..e98fd73 100644 --- a/src/routes/index.ts +++ b/src/routes/index.ts @@ -4,5 +4,5 @@ import { routes as github } from './github'; import { Config } from '../config'; export const routes = (config: Config): ServerRoute[] => { - return [...github(config), ...gitlab()]; + return [...github(config), ...gitlab(config)]; }; diff --git a/test/routes/gitlab/merge-request-hook.spec.ts b/test/routes/gitlab/merge-request-hook.spec.ts new file mode 100644 index 0000000..b2531d6 --- /dev/null +++ b/test/routes/gitlab/merge-request-hook.spec.ts @@ -0,0 +1,70 @@ +import { getConfig } from '../../../src/config'; +import { initServer } from '../../../src/server'; +import { StreamLabs } from '../../../src/services/StreamLabs'; +import { TwitchChat } from '../../../src/services/TwitchChat'; +import { MergeRequestPayloadBuilder } from '../../builders/payload/gitlab/merge-request-payload-builder'; + +describe('POST /gitlab', () => { + let streamLabsSpy: jest.SpyInstance>; + let twitchChatSpy: jest.SpyInstance>; + + beforeEach(() => { + streamLabsSpy = jest.spyOn(StreamLabs.prototype, 'alert'); + streamLabsSpy.mockImplementationOnce(jest.fn()); + + twitchChatSpy = jest.spyOn(TwitchChat.prototype, 'send'); + twitchChatSpy.mockImplementationOnce(jest.fn()); + }); + + describe('Merge Request Hook', () => { + it('handles merge request merged event', async () => { + const subject = await initServer(getConfig()); + const payload = new MergeRequestPayloadBuilder() + .with({ object_attributes: { state: 'merged' } }) + .getInstance(); + + const { result } = await subject.inject({ + method: 'POST', + url: '/gitlab', + payload, + headers: { 'x-gitlab-event': 'Merge Request Hook' }, + }); + + expect(result).toEqual( + expect.objectContaining({ + messages: [ + expect.objectContaining({ + twitchChat: expect.anything(), + streamlabs: expect.anything(), + }), + ], + }), + ); + }); + + it('handles merge request opened event', async () => { + const subject = await initServer(getConfig()); + const payload = new MergeRequestPayloadBuilder() + .with({ object_attributes: { state: 'opened' } }) + .getInstance(); + + const { result } = await subject.inject({ + method: 'POST', + url: '/gitlab', + payload, + headers: { 'x-gitlab-event': 'Merge Request Hook' }, + }); + + expect(result).toEqual( + expect.objectContaining({ + messages: [ + expect.objectContaining({ + twitchChat: expect.anything(), + streamlabs: expect.anything(), + }), + ], + }), + ); + }); + }); +});