Skip to content

Commit b80e19b

Browse files
committed
Merge branch 'master' into 125-docs-install
# Conflicts: # README.md
2 parents c97e6e5 + caf586c commit b80e19b

File tree

9 files changed

+157
-17
lines changed

9 files changed

+157
-17
lines changed

.env.example

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,9 @@
1-
NODE_ENV=test
2-
STREAMLABS_TOKEN=xxxx.xxxx.xxxx
1+
NODE_ENV=development
2+
PORT=8080
3+
STREAMLABS_TOKEN=
4+
TWITCH_BOT_NAME=
5+
TWITCH_BOT_TOKEN=
6+
TWITCH_BOT_CHANNEL=
7+
NOTIFY_ISSUES_ASSIGNED_TO=
8+
IGNORE_PR_OPENED_BY=
9+
NOTIFY_CHECK_RUNS_FOR=

README.md

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,31 @@
99
![license](https://img.shields.io/github/license/streamdevs/webhook.svg)
1010
![Node.js CI](https://github.com/streamdevs/webhook/workflows/Node.js%20CI/badge.svg)
1111

12-
A webhook to forward GitHub events to StreamLabs Alerts and Twitch Chat.
12+
## Goal
1313

14-
![Apr-21-2020 9-18-24 PM](https://user-images.githubusercontent.com/7255298/79904917-bc816e00-8415-11ea-98ca-7525b169ef49.gif)
14+
A webhook to forward GitHub and GitLab events to StreamLabs Alerts and Twitch Chat.
1515

16-
## Deploy to Heroku
16+
This is a tool created with live-coding streamers in mind. The goal is to have another source of
17+
interaction and showcase relevant activity on GitHub to their audience on streaming platforms
18+
generating more interest in their Open Source projects.
19+
20+
![StreamDevs Webhook Demo](https://user-images.githubusercontent.com/7255298/79904917-bc816e00-8415-11ea-98ca-7525b169ef49.gif)
21+
22+
## Features
23+
24+
### GitHub
25+
26+
We support the following events:
27+
28+
- Stars
29+
- Forks
30+
- Releases
31+
- Issues
32+
- Opened
33+
- Assigned
34+
- Pull Requests
35+
- Opened
36+
- Merged
1737

1838
[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy)
1939

@@ -49,11 +69,6 @@ You can deploy this webhook in different ways
4969
```
5070
yarn install
5171
```
52-
53-
```
54-
55-
```
56-
5772
3. Create a .env file with your (configuration)[#configuration] and the edit it
5873
```
5974
cp .env.example .env
@@ -83,8 +98,6 @@ We make use of the following environment variables:
8398

8499
## How to configure the webhook in GitHub
85100

86-
### For sponsorships
87-
88101
### GitHub Configuration
89102

90103
#### Repositories
@@ -106,6 +119,8 @@ We make use of the following environment variables:
106119
8. Click on `Add webhook`
107120
9. You will receive your first notification on Twitch Chat and StreamLabs letting you now your webhook has been configured correctly.
108121

122+
### For sponsorships
123+
109124
[Check the GitHub documentation](https://help.github.com/en/github/supporting-the-open-source-community-with-github-sponsors/configuring-webhooks-for-events-in-your-sponsored-account)
110125

111126
## Contributing
@@ -158,3 +173,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
158173
<!-- prettier-ignore-end -->
159174

160175
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
176+
177+
## License
178+
179+
This project is under the [CC-BY 4.0](https://github.com/streamdevs/webhook/blob/master/license.md) license

lint-staged.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
module.exports = {
22
'*.{ts,js}': ['yarn format', 'yarn lint'],
3+
'*.{md}': ['yarn format'],
34
};

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"compile:check": "yarn compile --noEmit",
55
"test": "jest",
66
"test:watch": "jest --watch",
7-
"start": "node dist/index.js",
7+
"start": "node -r dotenv/config dist/index.js",
88
"ci:lint": "eslint --ext .ts --ignore-path .gitignore .",
99
"ci:format": "prettier --ignore-path .gitignore -l .",
1010
"lint": "yarn run ci:lint --fix",

src/config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export const getConfig = (): Config => {
3232
TWITCH_BOT_TOKEN: process.env['TWITCH_BOT_TOKEN'],
3333
TWITCH_BOT_CHANNEL: process.env['TWITCH_BOT_CHANNEL'],
3434
port: process.env['PORT'] || process.env['HTTP_PORT'] || 8080,
35-
NOTIFY_CHECK_RUNS_FOR: (process.env['NOTIFY_CHECK_RUNS_FOR'] || '').split(','),
35+
NOTIFY_CHECK_RUNS_FOR: process.env['NOTIFY_CHECK_RUNS_FOR']?.split(',') || [],
3636
NOTIFY_ISSUES_ASSIGNED_TO: process.env['NOTIFY_ISSUES_ASSIGNED_TO']?.split(',') || [],
3737
IGNORE_PR_OPENED_BY: process.env['IGNORE_PR_OPENED_BY']?.split(',') || [],
3838
};

src/reactions/gitlab/index.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { TwitchChat } from '../../services/TwitchChat';
2+
import { StreamLabs } from '../../services/StreamLabs';
3+
import { MergeRequestMerged } from './merge-request-merged';
4+
import { MergeRequestPayload } from '../../schemas/gitlab/merge-request-payload';
5+
import { MergeRequestOpened } from './merge-request-opened';
6+
import { Reaction } from '../github/reaction';
7+
8+
export const buildGitLabReactions = (
9+
twitchChat: TwitchChat,
10+
streamlabs: StreamLabs,
11+
): Reaction<MergeRequestPayload>[] => {
12+
return [
13+
new MergeRequestMerged(twitchChat, streamlabs),
14+
new MergeRequestOpened(twitchChat, streamlabs),
15+
];
16+
};

src/routes/gitlab/index.ts

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
import { ServerRoute, ResponseObject, Request, ResponseToolkit } from '@hapi/hapi';
22
import { gitlabHeader } from '../../schemas/gitlab/joi/gitlab-headers-schema';
3+
import { buildGitLabReactions } from '../../reactions/gitlab';
4+
import { TwitchChat } from '../../services/TwitchChat';
5+
import { Config } from '../../config';
6+
import { StreamLabs } from '../../services/StreamLabs';
7+
import { MergeRequestPayload } from '../../schemas/gitlab/merge-request-payload';
38

4-
export const routes = (): ServerRoute[] => {
9+
export const routes = (config: Config): ServerRoute[] => {
510
return [
611
{
712
method: 'POST',
@@ -11,9 +16,31 @@ export const routes = (): ServerRoute[] => {
1116
},
1217
},
1318
handler: async (request: Request, h: ResponseToolkit): Promise<ResponseObject> => {
14-
const { headers } = request;
19+
const { headers, payload } = (request as unknown) as {
20+
headers: { 'x-gitlab-event': string };
21+
payload: MergeRequestPayload;
22+
};
1523
const event = headers['x-gitlab-event'];
1624

25+
const twitchChat = new TwitchChat({
26+
botName: config?.TWITCH_BOT_NAME || '',
27+
botToken: config?.TWITCH_BOT_TOKEN || '',
28+
channel: config?.TWITCH_BOT_CHANNEL || '',
29+
});
30+
const streamlabs = new StreamLabs({ token: config?.STREAMLABS_TOKEN || '' });
31+
32+
const reactions = buildGitLabReactions(twitchChat, streamlabs).filter((reaction) =>
33+
reaction.canHandle({ event, payload, config }),
34+
);
35+
36+
if (reactions.length > 0) {
37+
const messages = await Promise.all(
38+
reactions.map((reaction) => reaction.handle({ payload })),
39+
);
40+
41+
return h.response({ messages }).code(200);
42+
}
43+
1744
return h.response({ message: `Ignoring event: '${event}'` }).code(200);
1845
},
1946
path: '/gitlab',

src/routes/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ import { routes as github } from './github';
44
import { Config } from '../config';
55

66
export const routes = (config: Config): ServerRoute[] => {
7-
return [...github(config), ...gitlab()];
7+
return [...github(config), ...gitlab(config)];
88
};
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import { getConfig } from '../../../src/config';
2+
import { initServer } from '../../../src/server';
3+
import { StreamLabs } from '../../../src/services/StreamLabs';
4+
import { TwitchChat } from '../../../src/services/TwitchChat';
5+
import { MergeRequestPayloadBuilder } from '../../builders/payload/gitlab/merge-request-payload-builder';
6+
7+
describe('POST /gitlab', () => {
8+
let streamLabsSpy: jest.SpyInstance<Promise<void>>;
9+
let twitchChatSpy: jest.SpyInstance<Promise<void>>;
10+
11+
beforeEach(() => {
12+
streamLabsSpy = jest.spyOn(StreamLabs.prototype, 'alert');
13+
streamLabsSpy.mockImplementationOnce(jest.fn());
14+
15+
twitchChatSpy = jest.spyOn(TwitchChat.prototype, 'send');
16+
twitchChatSpy.mockImplementationOnce(jest.fn());
17+
});
18+
19+
describe('Merge Request Hook', () => {
20+
it('handles merge request merged event', async () => {
21+
const subject = await initServer(getConfig());
22+
const payload = new MergeRequestPayloadBuilder()
23+
.with({ object_attributes: { state: 'merged' } })
24+
.getInstance();
25+
26+
const { result } = await subject.inject({
27+
method: 'POST',
28+
url: '/gitlab',
29+
payload,
30+
headers: { 'x-gitlab-event': 'Merge Request Hook' },
31+
});
32+
33+
expect(result).toEqual(
34+
expect.objectContaining({
35+
messages: [
36+
expect.objectContaining({
37+
twitchChat: expect.anything(),
38+
streamlabs: expect.anything(),
39+
}),
40+
],
41+
}),
42+
);
43+
});
44+
45+
it('handles merge request opened event', async () => {
46+
const subject = await initServer(getConfig());
47+
const payload = new MergeRequestPayloadBuilder()
48+
.with({ object_attributes: { state: 'opened' } })
49+
.getInstance();
50+
51+
const { result } = await subject.inject({
52+
method: 'POST',
53+
url: '/gitlab',
54+
payload,
55+
headers: { 'x-gitlab-event': 'Merge Request Hook' },
56+
});
57+
58+
expect(result).toEqual(
59+
expect.objectContaining({
60+
messages: [
61+
expect.objectContaining({
62+
twitchChat: expect.anything(),
63+
streamlabs: expect.anything(),
64+
}),
65+
],
66+
}),
67+
);
68+
});
69+
});
70+
});

0 commit comments

Comments
 (0)