Skip to content

Commit 1d14332

Browse files
authored
feat: use async worker for processing issue comment (#81)
* feat: use async worker for processing issue comment * pr: remove /index * pr: processed comment * kill a file * delete index snap * test: get tests working * wip: get it working 🎉 * test: add tests for webhook * test: super basic test for serverless task * test: tests * test: tests
1 parent 5bebf13 commit 1d14332

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+296
-140
lines changed

.env.example

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
# The name that the app will respond to (change this for development). e.g. @all-contributors
2-
BOT_NAME=AllContributorsDev
31
# The ID of your GitHub App
42
APP_ID=
53
WEBHOOK_SECRET=development

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ package-lock.json # We use yarn ;)
55

66
.env
77
*.pem
8-
test-payload.json
8+
test-*-payload.json
9+
yarn-error.log

CONTRIBUTING.md

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,25 @@ Ideas not as issues yet:
2424

2525

2626
### Testing serverless locally
27-
`yarn add serverless-dotenv-plugin --dev`
2827

29-
in `serverless.yml` plugins add:
30-
`- serverless-dotenv-plugin`
31-
32-
33-
Create file test-file.json with payload
28+
#### Adding tasks to the queue
29+
Create file test-webhook-file.json with payload
3430
```
35-
curl -vX POST http://localhost:3000/ -d @test-payload.json \
31+
curl -vX POST http://localhost:3000/ -d @test-webhook-payload.json \
3632
--header "Content-Type: application/json" \
3733
--header "X-GitHub-Event: issue_comment"
3834
```
3935

36+
#### Executing tasks
37+
Create test-task-payload.json
38+
```
39+
yarn serverless invoke local \
40+
--function processIssueComment \
41+
--path test-task-payload.json
42+
```
43+
4044

41-
## Monitoring:
45+
## Production Monitoring:
4246
- [Sentry](https://sentry.io/all-contributors/github-bot/)
4347
- [AWS Lambda](https://console.aws.amazon.com/lambda/home?region=us-east-1#/functions/all-contributors-bot-prod-githubWebhook?tab=monitoring)
4448
- [Stats](https://gkioebvccg.execute-api.us-east-1.amazonaws.com/prod/stats)

package.json

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
{
2-
"name": "AllContributorsBot",
3-
"version": "0.0.1",
2+
"name": "all-contributors-bot",
3+
"version": "1.0.0",
44
"description": "A bot for automatically adding all your contributors",
5-
"author": "Jake Bolam <[email protected]> (https://all-contributors.js.org)",
6-
"repository": "https://github.com/all-contributors/bot.git",
7-
"homepage": "https://github.com/all-contributors/bot",
8-
"bugs": "https://github.com/all-contributors/bot/issues",
5+
"author": "Jake Bolam <[email protected]> (https://jakebolam.com)",
6+
"repository": "https://github.com/all-contributors/all-contributors-bot.git",
7+
"homepage": "https://github.com/all-contributors/all-contributors-bot",
8+
"bugs": "https://github.com/all-contributors/all-contributors-bot/issues",
99
"keywords": [
1010
"all-contributors",
1111
"probot",
@@ -14,7 +14,7 @@
1414
],
1515
"scripts": {
1616
"start": "nodemon",
17-
"start-probot": "probot run ./src/index.js",
17+
"start-probot": "probot run ./src/tasks/processIssueComment/probot-processIssueComment.js",
1818
"start-serverless": "serverless offline start",
1919
"lint": "eslint .",
2020
"lint-fix": "eslint --fix .",
@@ -24,6 +24,7 @@
2424
},
2525
"dependencies": {
2626
"all-contributors-cli": "^5.10.1",
27+
"aws-sdk": "^2.391.0",
2728
"compromise": "^11.13.0",
2829
"probot": "^8.0.0-octokit-16-preview"
2930
},
@@ -40,6 +41,7 @@
4041
"nodemon": "^1.17.2",
4142
"prettier": "^1.15.3",
4243
"serverless": "^1.35.1",
44+
"serverless-dotenv-plugin": "^2.0.1",
4345
"serverless-offline": "^4.0.0",
4446
"shelljs": "^0.8.3",
4547
"smee-client": "^1.0.2"

serverless.yml

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ service: all-contributors-bot
22
frameworkVersion: '=1.35.1'
33

44
plugins:
5+
- serverless-dotenv-plugin
56
- serverless-offline # must be last
67

78
custom:
@@ -24,16 +25,21 @@ provider:
2425
region: us-east-1
2526
runtime: nodejs8.10
2627
memorySize: 512
27-
timeout: 30
28+
timeout: 60
2829
environment:
29-
BOT_NAME: ${self:custom.botName.${self:custom.stage}}
3030
APP_ID: ${self:custom.appId.${self:custom.stage}}
3131
LOG_LEVEL: ${self:custom.logLevel.${self:custom.stage}}
3232
SENTRY_DSN: ${self:custom.sentryDsn.${self:custom.stage}}
3333
DISABLE_STATS: true
3434
INSTALLATION_TOKEN_TTL: 3540
3535
WEBHOOK_SECRET: ${env:WEBHOOK_SECRET}
3636
PRIVATE_KEY: ${env:PRIVATE_KEY}
37+
SERVICE_NAME_AND_STAGE: 'all-contributors-bot-${opt:stage, self:provider.stage}'
38+
iamRoleStatements:
39+
- Effect: Allow
40+
Action:
41+
- lambda:InvokeFunction
42+
Resource: '*'
3743

3844
functions:
3945
githubWebhook:
@@ -50,3 +56,7 @@ functions:
5056
path: /stats
5157
method: get
5258
cors: true
59+
60+
# Tasks
61+
processIssueComment:
62+
handler: src/tasks/processIssueComment/serverless-task.handler

src/index.js

Lines changed: 0 additions & 10 deletions
This file was deleted.

src/serverless-stats.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const getProbot = require('./probot/getProbot')
1+
const getProbot = require('./utils/getProbot')
22

33
async function getInstallations(app) {
44
const github = await app.auth()

src/serverless-webhook.js

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,70 @@
1-
const getProbot = require('./probot/getProbot')
2-
const appFn = require('./')
1+
/* eslint-disable no-comment */
2+
3+
const AWS = require('aws-sdk')
4+
const lambda = new AWS.Lambda()
5+
6+
const isMessageForBot = require('./utils/isMessageForBot')
37

48
module.exports.handler = async (event, context) => {
59
context.callbackWaitsForEmptyEventLoop = false
610

711
try {
8-
const probot = getProbot()
9-
probot.load(appFn)
10-
1112
const name =
1213
event.headers['x-github-event'] || event.headers['X-GitHub-Event']
1314
const payload =
1415
typeof event.body === 'string' ? JSON.parse(event.body) : event.body
15-
await probot.receive({
16+
17+
if (name !== 'issue_comment') {
18+
return {
19+
statusCode: 201,
20+
body: 'Not an issue comment, exiting',
21+
}
22+
}
23+
24+
if (payload.action !== 'created') {
25+
return {
26+
statusCode: 201,
27+
body: 'Not a comment creation, exiting',
28+
}
29+
}
30+
31+
if (payload.sender.type !== 'User') {
32+
return {
33+
statusCode: 201,
34+
body: 'Not from a user, exiting',
35+
}
36+
}
37+
38+
const commentBody = payload.comment.body
39+
if (!isMessageForBot(commentBody)) {
40+
return {
41+
statusCode: 202,
42+
body: 'Message not for us, exiting',
43+
}
44+
}
45+
46+
const processIssueCommentPayload = JSON.stringify({
1647
name,
1748
payload,
1849
})
50+
51+
lambda.invoke({
52+
FunctionName: `${
53+
process.env.SERVICE_NAME_AND_STAGE
54+
}-processIssueComment`,
55+
InvocationType: 'Event',
56+
LogType: 'None',
57+
Payload: new Buffer(processIssueCommentPayload),
58+
})
59+
1960
return {
2061
statusCode: 200,
21-
body: JSON.stringify({
22-
message: `Received ${name}.${payload.action}`,
23-
}),
62+
body: 'Accepted and processing comment',
2463
}
2564
} catch (error) {
2665
return {
2766
statusCode: 500,
28-
body: JSON.stringify(error.message),
67+
body: error.message,
2968
}
3069
}
3170
}

src/processIssueComment.js renamed to src/tasks/processIssueComment/probot-processIssueComment.js

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ const ContentFiles = require('./ContentFiles')
66
const getUserDetails = require('./utils/getUserDetails')
77
const parseComment = require('./utils/parse-comment')
88

9-
const isMessageForBot = require('./utils/isMessageForBot')
10-
const { GIHUB_BOT_NAME } = require('./utils/settings')
119
const {
1210
AllContributorBotError,
1311
ResourceNotFoundError,
@@ -67,7 +65,7 @@ async function processAddContributor({
6765
)
6866
}
6967

70-
async function processIssueComment({ context, commentReply }) {
68+
async function probotProcessIssueComment({ context, commentReply }) {
7169
const repository = new Repository({
7270
...context.repo(),
7371
github: context.github,
@@ -104,29 +102,18 @@ async function processIssueComment({ context, commentReply }) {
104102

105103
commentReply.reply(`I could not determine your intention.`)
106104
commentReply.reply(
107-
`Basic usage: @${GIHUB_BOT_NAME} please add jakebolam for code, doc and infra`,
105+
`Basic usage: @all-contributors please add @jakebolam for code, doc and infra`,
108106
)
109107
commentReply.reply(
110108
`For other usage see the [documentation](https://github.com/all-contributors/all-contributors-bot#usage)`,
111109
)
112110
return
113111
}
114112

115-
async function processIssueCommentSafe({ context }) {
116-
if (context.isBot) {
117-
context.log.debug('From a bot, exiting')
118-
return
119-
}
120-
121-
const commentBody = context.payload.comment.body
122-
if (!isMessageForBot(commentBody)) {
123-
context.log.debug('Message not for us, exiting')
124-
return
125-
}
126-
113+
async function probotProcessIssueCommentSafe({ context }) {
127114
const commentReply = new CommentReply({ context })
128115
try {
129-
await processIssueComment({ context, commentReply })
116+
await probotProcessIssueComment({ context, commentReply })
130117
} catch (error) {
131118
if (error.handled) {
132119
context.log.debug(error)
@@ -145,4 +132,13 @@ async function processIssueCommentSafe({ context }) {
145132
}
146133
}
147134

148-
module.exports = processIssueCommentSafe
135+
function processIssueCommentApp(app) {
136+
// issueComment.edited
137+
// Issue comments and PR comments both create issue_comment events
138+
app.on('issue_comment.created', async context => {
139+
app.log.trace(context)
140+
await probotProcessIssueCommentSafe({ context })
141+
})
142+
}
143+
144+
module.exports = processIssueCommentApp
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
const getProbot = require('../../utils/getProbot')
2+
const processIssueCommentApp = require('./probot-processIssueComment')
3+
4+
module.exports.handler = async (event, context) => {
5+
context.callbackWaitsForEmptyEventLoop = false
6+
7+
try {
8+
const probot = getProbot()
9+
probot.load(processIssueCommentApp)
10+
11+
await probot.receive({
12+
name: event.name,
13+
payload: event.payload,
14+
})
15+
return {
16+
statusCode: 200,
17+
body: 'Processed comment',
18+
}
19+
} catch (error) {
20+
return {
21+
statusCode: 500,
22+
body: error.message,
23+
}
24+
}
25+
}
File renamed without changes.
File renamed without changes.

src/utils/isMessageForBot.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
const { GIHUB_BOT_NAME } = require('./settings')
2-
31
function isMessageForBot(message) {
42
const isMessageForBot =
5-
message.includes(`@${GIHUB_BOT_NAME}`) ||
3+
message.includes(`@all-contributors`) ||
64
message.includes(`@allcontributors[bot]`)
75
return isMessageForBot
86
}

src/utils/settings.js

Lines changed: 0 additions & 5 deletions
This file was deleted.

test/fixtures/issue_comment.created.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@
7979
"created_at": "2019-01-10T08:36:52Z",
8080
"updated_at": "2019-01-10T08:36:52Z",
8181
"author_association": "MEMBER",
82-
"body": "@AllContributorsBotTest please add jakebolam for code, doc and infra"
82+
"body": "@all-contributors please add jakebolam for code, doc and infra"
8383
},
8484
"repository": {
8585
"id": 164268911,

test/processIssueComment.test.js

Lines changed: 0 additions & 40 deletions
This file was deleted.

0 commit comments

Comments
 (0)