From f5e4b67597e08980d8dba41300543ab8791efc18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Mart=C3=ADn=20Agra?= Date: Sun, 19 Apr 2020 22:31:32 +0200 Subject: [PATCH 1/8] chore: add new 'Reaction' abstract class --- src/reactions/github/reaction.ts | 69 ++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 src/reactions/github/reaction.ts diff --git a/src/reactions/github/reaction.ts b/src/reactions/github/reaction.ts new file mode 100644 index 0000000..fc4bdf0 --- /dev/null +++ b/src/reactions/github/reaction.ts @@ -0,0 +1,69 @@ +import { StreamLabs } from '../../services/StreamLabs'; +import { TwitchChat } from '../../services/TwitchChat'; + +export interface ReactionHandleOptions { + // FIXME: add Payload type + payload: any; +} + +export abstract class Reaction { + public constructor( + private twitchChat: TwitchChat, + private streamlabs: StreamLabs, + ) {} + + abstract getStreamLabsMessage({ payload }: ReactionHandleOptions): string; + abstract getTwitchChatMessage({ payload }: ReactionHandleOptions): string; + + private async notifyStreamlabs({ payload }: ReactionHandleOptions) { + try { + const message = this.getStreamLabsMessage({ payload }); + await this.streamlabs.alert({ + message, + }); + + return { + notified: true, + message, + }; + } catch { + // TODO: add logging + + return { + notified: false, + message: '', + }; + } + } + + private async notifyTwitch({ payload }: ReactionHandleOptions) { + try { + const message = this.getTwitchChatMessage({ payload }); + await this.twitchChat.send(message); + + return { + notified: true, + message, + }; + } catch { + // TODO: add logging + + return { + notified: false, + message: '', + }; + } + } + + public async handle({ payload }: ReactionHandleOptions) { + const [streamlabs, twitchChat] = await Promise.all([ + this.notifyStreamlabs({ payload }), + this.notifyTwitch({ payload }), + ]); + + return { + twitchChat, + streamlabs, + }; + } +} From 46cf886f5556890830d4d733e97f511408906dd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Mart=C3=ADn=20Agra?= Date: Sun, 19 Apr 2020 22:31:58 +0200 Subject: [PATCH 2/8] refactor: 'Ping' to extend 'Reaction' --- src/reactions/github/ping.ts | 76 +++--------------------------- test/reactions/github/ping.spec.ts | 12 ++--- 2 files changed, 12 insertions(+), 76 deletions(-) diff --git a/src/reactions/github/ping.ts b/src/reactions/github/ping.ts index a73ad97..31ba8f6 100644 --- a/src/reactions/github/ping.ts +++ b/src/reactions/github/ping.ts @@ -1,74 +1,10 @@ -import { StreamLabs } from '../../services/StreamLabs'; -import { TwitchChat } from '../../services/TwitchChat'; +import { Reaction, ReactionHandleOptions } from './reaction'; -interface PingConfig { - streamlabs: StreamLabs; - twitchChat: TwitchChat; -} - -interface HandleOptions { - // FIXME: add Payload type - payload: any; -} - -export class Ping { - private streamlabs: StreamLabs; - private twitchChat: TwitchChat; - - public constructor({ streamlabs, twitchChat }: PingConfig) { - this.streamlabs = streamlabs; - this.twitchChat = twitchChat; +export class Ping extends Reaction { + getStreamLabsMessage({ payload }: ReactionHandleOptions): string { + return `🎉 Your repo *${payload.repository.full_name}* is configured correctly for *${payload.hook.events}* events 🎉`; } - - private async notifyStreamlabs({ payload }: HandleOptions) { - try { - const streamlabsMessage = `🎉 Your repo *${payload.repository.full_name}* is configured correctly for *${payload.hook.events}* events 🎉`; - await this.streamlabs.alert({ - message: streamlabsMessage, - }); - - return { - notified: true, - message: streamlabsMessage, - }; - } catch { - // TODO: add logging - - return { - notified: false, - message: '', - }; - } - } - - private async notifyTwitch({ payload }: HandleOptions) { - try { - const message = `🎉 Your repo *${payload.repository.full_name}* is configured correctly for *${payload.hook.events}* events 🎉`; - await this.twitchChat.send(message); - - return { - notified: true, - message, - }; - } catch { - // TODO: add logging - - return { - notified: false, - message: '', - }; - } - } - - public async handle({ payload }: HandleOptions) { - const [streamlabs, twitchChat] = await Promise.all([ - this.notifyStreamlabs({ payload }), - this.notifyTwitch({ payload }), - ]); - - return { - twitchChat, - streamlabs, - }; + getTwitchChatMessage({ payload }: ReactionHandleOptions): string { + return `🎉 Your repo *${payload.repository.full_name}* is configured correctly for *${payload.hook.events}* events 🎉`; } } diff --git a/test/reactions/github/ping.spec.ts b/test/reactions/github/ping.spec.ts index 69402e7..3fcad62 100644 --- a/test/reactions/github/ping.spec.ts +++ b/test/reactions/github/ping.spec.ts @@ -25,7 +25,7 @@ describe('Ping', () => { }); it('calls StreamLabs with the expected message', async () => { - const subject = new Ping({ streamlabs, twitchChat }); + const subject = new Ping(twitchChat, streamlabs); await subject.handle({ payload }); @@ -35,7 +35,7 @@ describe('Ping', () => { }); it('calls TwitchChat with the expected message', async () => { - const subject = new Ping({ streamlabs, twitchChat }); + const subject = new Ping(twitchChat, streamlabs); await subject.handle({ payload }); @@ -45,7 +45,7 @@ describe('Ping', () => { }); it('returns the message that was send to Twitch', async () => { - const subject = new Ping({ streamlabs, twitchChat }); + const subject = new Ping(twitchChat, streamlabs); const { twitchChat: response } = await subject.handle({ payload: { @@ -63,7 +63,7 @@ describe('Ping', () => { }); it('returns the message that was send to StreamLabs', async () => { - const subject = new Ping({ streamlabs, twitchChat }); + const subject = new Ping(twitchChat, streamlabs); const { streamlabs: response } = await subject.handle({ payload: { @@ -84,7 +84,7 @@ describe('Ping', () => { jest.spyOn(streamlabs, 'alert').mockImplementationOnce(async () => { throw new Error('boom'); }); - const subject = new Ping({ streamlabs, twitchChat }); + const subject = new Ping(twitchChat, streamlabs); const { streamlabs: { notified }, @@ -97,7 +97,7 @@ describe('Ping', () => { jest.spyOn(twitchChat, 'send').mockImplementationOnce(async () => { throw new Error('boom'); }); - const subject = new Ping({ streamlabs, twitchChat }); + const subject = new Ping(twitchChat, streamlabs); const { twitchChat: { notified }, From b634dea0178c3bab9b380f196ae0fc6723f15f50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Mart=C3=ADn=20Agra?= Date: Sun, 19 Apr 2020 22:32:14 +0200 Subject: [PATCH 3/8] refactor: 'Star' to extend 'Reaction' --- src/reactions/github/star.ts | 64 ++++-------------------------------- 1 file changed, 6 insertions(+), 58 deletions(-) diff --git a/src/reactions/github/star.ts b/src/reactions/github/star.ts index 3e24d67..07d38a4 100644 --- a/src/reactions/github/star.ts +++ b/src/reactions/github/star.ts @@ -1,63 +1,11 @@ -import { TwitchChat } from '../../services/TwitchChat'; -import { StreamLabs } from '../../services/StreamLabs'; +import { Reaction, ReactionHandleOptions } from './reaction'; -interface HandleOptions { - payload: any; -} - -export class Star { - public constructor( - private twitchChat: TwitchChat, - private streamlabs: StreamLabs, - ) {} - - private async notifyTwitch({ payload }: HandleOptions) { - try { - const message = `*${payload.sender.login}* just starred ${payload.repository.html_url}`; - await this.twitchChat.send(message); - - return { - notified: true, - message, - }; - } catch { - // TODO: add logging - - return { - notified: false, - message: '', - }; - } +export class Star extends Reaction { + getStreamLabsMessage({ payload }: ReactionHandleOptions): string { + return `*${payload.sender.login}* just starred *${payload.repository.full_name}*`; } - private async notifyStreamLabs({ payload }: HandleOptions) { - try { - const message = `*${payload.sender.login}* just starred *${payload.repository.full_name}*`; - await this.streamlabs.alert({ message }); - - return { - notified: true, - message, - }; - } catch { - // TODO: add logging - - return { - notified: false, - message: '', - }; - } - } - - public async handle({ payload }: HandleOptions) { - const [twitchChat, streamlabs] = await Promise.all([ - this.notifyTwitch({ payload }), - this.notifyStreamLabs({ payload }), - ]); - - return { - twitchChat, - streamlabs, - }; + getTwitchChatMessage({ payload }: ReactionHandleOptions): string { + return `*${payload.sender.login}* just starred ${payload.repository.html_url}`; } } From a99fa6f5dd8ae63f89a292bdb0f8c9df253044a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Mart=C3=ADn=20Agra?= Date: Sun, 19 Apr 2020 22:35:20 +0200 Subject: [PATCH 4/8] refactor: 'PullRequestOpened' to extend 'Reaction' --- src/reactions/github/pull-request-opened.ts | 65 ++------------------- 1 file changed, 6 insertions(+), 59 deletions(-) diff --git a/src/reactions/github/pull-request-opened.ts b/src/reactions/github/pull-request-opened.ts index e006a95..d5a57eb 100644 --- a/src/reactions/github/pull-request-opened.ts +++ b/src/reactions/github/pull-request-opened.ts @@ -1,63 +1,10 @@ -import { TwitchChat } from '../../services/TwitchChat'; -import { StreamLabs } from '../../services/StreamLabs'; +import { Reaction, ReactionHandleOptions } from './reaction'; -interface HandleOptions { - payload: any; -} - -export class PullRequestOpened { - public constructor( - private twitchChat: TwitchChat, - private streamlabs: StreamLabs, - ) {} - - private async notifyTwitch({ payload }: HandleOptions) { - try { - const message = `*${payload.pull_request.user.login}* just opened a pull request in ${payload.repository.html_url}`; - await this.twitchChat.send(message); - - return { - notified: true, - message, - }; - } catch { - // TODO: add logging - - return { - notified: false, - message: '', - }; - } +export class PullRequestOpened extends Reaction { + getStreamLabsMessage({ payload }: ReactionHandleOptions): string { + return `*${payload.pull_request.user.login}* just opened a pull request in *${payload.repository.full_name}*`; } - - public async notifyStreamLabs({ payload }: HandleOptions) { - try { - const message = `*${payload.pull_request.user.login}* just opened a pull request in *${payload.repository.full_name}*`; - await this.streamlabs.alert({ message }); - - return { - notified: true, - message, - }; - } catch { - // TODO: add logging - - return { - notified: false, - message: '', - }; - } - } - - public async handle({ payload }: HandleOptions) { - const [twitchChat, streamlabs] = await Promise.all([ - this.notifyTwitch({ payload }), - this.notifyStreamLabs({ payload }), - ]); - - return { - twitchChat, - streamlabs, - }; + getTwitchChatMessage({ payload }: ReactionHandleOptions): string { + return `*${payload.pull_request.user.login}* just opened a pull request in ${payload.repository.html_url}`; } } From d81d7a1caf9d1ba53e3761df07949dedd3ea2295 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Mart=C3=ADn=20Agra?= Date: Sun, 19 Apr 2020 22:43:13 +0200 Subject: [PATCH 5/8] chore: add 'canHandle' method to 'Reaction' --- src/reactions/github/reaction.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/reactions/github/reaction.ts b/src/reactions/github/reaction.ts index fc4bdf0..c22fa1d 100644 --- a/src/reactions/github/reaction.ts +++ b/src/reactions/github/reaction.ts @@ -6,6 +6,11 @@ export interface ReactionHandleOptions { payload: any; } +export interface ReactionCanHandleOptions { + payload: any; + event: string; +} + export abstract class Reaction { public constructor( private twitchChat: TwitchChat, @@ -14,6 +19,7 @@ export abstract class Reaction { abstract getStreamLabsMessage({ payload }: ReactionHandleOptions): string; abstract getTwitchChatMessage({ payload }: ReactionHandleOptions): string; + abstract canHandle({ payload, event }: ReactionCanHandleOptions): boolean; private async notifyStreamlabs({ payload }: ReactionHandleOptions) { try { From 85ee4b7bfe71a2a89304b5bbbbd16e93510cbb70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Mart=C3=ADn=20Agra?= Date: Sun, 19 Apr 2020 22:43:29 +0200 Subject: [PATCH 6/8] chore: add 'canHandle' method to 'PullRequestOpened' --- src/reactions/github/pull-request-opened.ts | 9 ++++- .../github/pull-request-opened.spec.ts | 35 +++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/reactions/github/pull-request-opened.ts b/src/reactions/github/pull-request-opened.ts index d5a57eb..21b644e 100644 --- a/src/reactions/github/pull-request-opened.ts +++ b/src/reactions/github/pull-request-opened.ts @@ -1,6 +1,13 @@ -import { Reaction, ReactionHandleOptions } from './reaction'; +import { + Reaction, + ReactionCanHandleOptions, + ReactionHandleOptions, +} from './reaction'; export class PullRequestOpened extends Reaction { + canHandle({ payload, event }: ReactionCanHandleOptions): boolean { + return event === 'pull_request' && payload.action === 'opened'; + } getStreamLabsMessage({ payload }: ReactionHandleOptions): string { return `*${payload.pull_request.user.login}* just opened a pull request in *${payload.repository.full_name}*`; } diff --git a/test/reactions/github/pull-request-opened.spec.ts b/test/reactions/github/pull-request-opened.spec.ts index 39bd391..afa8878 100644 --- a/test/reactions/github/pull-request-opened.spec.ts +++ b/test/reactions/github/pull-request-opened.spec.ts @@ -79,4 +79,39 @@ describe('PullRequestOpened', () => { }); }); }); + + describe('#canHandle', () => { + it('returns true if the pull request is opened', () => { + const subject = new PullRequestOpened(null as any, null as any); + + const result = subject.canHandle({ + event: 'pull_request', + payload: { action: 'opened' }, + }); + + expect(result).toEqual(true); + }); + + it('returns false if the event is not pull request', () => { + const subject = new PullRequestOpened(null as any, null as any); + + const result = subject.canHandle({ + event: 'fork', + payload: { action: 'opened' }, + }); + + expect(result).toEqual(false); + }); + + it('returns false if the pull request is closed', () => { + const subject = new PullRequestOpened(null as any, null as any); + + const result = subject.canHandle({ + event: 'pull_request', + payload: { action: 'closed' }, + }); + + expect(result).toEqual(false); + }); + }); }); From 6876c9eb0f320239956e36288516151d5596a354 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Mart=C3=ADn=20Agra?= Date: Sun, 19 Apr 2020 22:50:16 +0200 Subject: [PATCH 7/8] chore: add 'canHandle' method to 'Ping' --- src/reactions/github/ping.ts | 14 +++++++- test/reactions/github/ping.spec.ts | 57 ++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/src/reactions/github/ping.ts b/src/reactions/github/ping.ts index 31ba8f6..bca8b01 100644 --- a/src/reactions/github/ping.ts +++ b/src/reactions/github/ping.ts @@ -1,6 +1,18 @@ -import { Reaction, ReactionHandleOptions } from './reaction'; +import { + Reaction, + ReactionCanHandleOptions, + ReactionHandleOptions, +} from './reaction'; export class Ping extends Reaction { + canHandle({ payload, event }: ReactionCanHandleOptions): boolean { + return ( + event === 'ping' && + (payload.hook.events.includes('star') || + payload.hook.events.includes('fork') || + payload.hook.events.includes('pull_request')) + ); + } getStreamLabsMessage({ payload }: ReactionHandleOptions): string { return `🎉 Your repo *${payload.repository.full_name}* is configured correctly for *${payload.hook.events}* events 🎉`; } diff --git a/test/reactions/github/ping.spec.ts b/test/reactions/github/ping.spec.ts index 3fcad62..e4ffe65 100644 --- a/test/reactions/github/ping.spec.ts +++ b/test/reactions/github/ping.spec.ts @@ -106,4 +106,61 @@ describe('Ping', () => { expect(notified).toEqual(false); }); }); + + describe('#canHandle', () => { + it('returns true if the event is ping and the hook.events array contains star', () => { + const subject = new Ping(null as any, null as any); + + const result = subject.canHandle({ + event: 'ping', + payload: { hook: { events: ['star'] } }, + }); + + expect(result).toEqual(true); + }); + + it('returns false if the event is not ping', () => { + const subject = new Ping(null as any, null as any); + + const result = subject.canHandle({ + event: 'fork', + payload: { hook: { events: ['star'] } }, + }); + + expect(result).toEqual(false); + }); + + it('returns false if the hook.events only contains status', () => { + const subject = new Ping(null as any, null as any); + + const result = subject.canHandle({ + event: 'ping', + payload: { hook: { events: ['status'] } }, + }); + + expect(result).toEqual(false); + }); + + it('returns true if the event is ping and the hook.events array contains fork', () => { + const subject = new Ping(null as any, null as any); + + const result = subject.canHandle({ + event: 'ping', + payload: { hook: { events: ['fork'] } }, + }); + + expect(result).toEqual(true); + }); + + it('returns true if the event is ping and the hook.events array contains pull_request', () => { + const subject = new Ping(null as any, null as any); + + const result = subject.canHandle({ + event: 'ping', + payload: { hook: { events: ['pull_request'] } }, + }); + + expect(result).toEqual(true); + }); + }); }); From 8079b7fec13bdc2c41fa6ab1911b0ec0cbb5d0be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Mart=C3=ADn=20Agra?= Date: Sun, 19 Apr 2020 22:53:43 +0200 Subject: [PATCH 8/8] chore: add 'canHandle' method to 'Star' --- src/reactions/github/star.ts | 10 +++++++++- test/reactions/github/star.spec.ts | 24 ++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/reactions/github/star.ts b/src/reactions/github/star.ts index 07d38a4..3d884a7 100644 --- a/src/reactions/github/star.ts +++ b/src/reactions/github/star.ts @@ -1,6 +1,14 @@ -import { Reaction, ReactionHandleOptions } from './reaction'; +import { + Reaction, + ReactionCanHandleOptions, + ReactionHandleOptions, +} from './reaction'; export class Star extends Reaction { + canHandle({ payload, event }: ReactionCanHandleOptions): boolean { + return event === 'star' && payload.action === 'created'; + } + getStreamLabsMessage({ payload }: ReactionHandleOptions): string { return `*${payload.sender.login}* just starred *${payload.repository.full_name}*`; } diff --git a/test/reactions/github/star.spec.ts b/test/reactions/github/star.spec.ts index 1592fb2..dc9ff34 100644 --- a/test/reactions/github/star.spec.ts +++ b/test/reactions/github/star.spec.ts @@ -81,4 +81,28 @@ describe('Star', () => { }); }); }); + + describe('#canHandle', () => { + it('returns true if the event is star and actions is created', () => { + const subject = new Star(null as any, null as any); + + const result = subject.canHandle({ + event: 'star', + payload: { action: 'created' }, + }); + + expect(result).toEqual(true); + }); + + it('returns false if the event is star and actions is removed', () => { + const subject = new Star(null as any, null as any); + + const result = subject.canHandle({ + event: 'star', + payload: { action: 'removed' }, + }); + + expect(result).toEqual(false); + }); + }); });