Skip to content

Commit a18378f

Browse files
committed
Initial commit
0 parents  commit a18378f

File tree

5 files changed

+162
-0
lines changed

5 files changed

+162
-0
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
node_modules
2+
npm-debug.log
3+
4+
.DS_Store

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Node.js GitHub Bot
2+
3+
What's this?? ATM an experiment to see if a bot could be helpful for the Node.js project, to automate all the things!
4+
5+
## Contributing
6+
7+
Please do, contributions are more than welcome!
8+
9+
## License
10+
11+
MIT

lib/pollTravis.js

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
'use strict'
2+
3+
const GitHub = require('github')
4+
const Travis = require('travis-ci')
5+
6+
const travisClient = new Travis({
7+
version: '2.0.0',
8+
access_token: process.env.TRAVIS_CI_TOKEN
9+
})
10+
const githubClient = new GitHub({
11+
version: '3.0.0',
12+
protocol: 'https',
13+
host: 'api.github.com',
14+
timeout: 5 * 1000,
15+
headers: {
16+
'user-agent': 'Node.js GitHub Bot v1.0-beta'
17+
}
18+
})
19+
20+
githubClient.authenticate({
21+
type: 'oauth',
22+
token: process.env.GITHUB_TOKEN
23+
})
24+
25+
function pollAndComment (owner, repoName, prId, checkNumber) {
26+
checkNumber = checkNumber || 1
27+
28+
const prInfo = prInfoStr({ owner, repoName, prId })
29+
const createGhComment = createGhCommentFn({ owner, repoName, prId })
30+
31+
if (checkNumber > 100) {
32+
console.warn(`* ${prInfo} Was not able to find matching build for PR, stopping poll now :(`)
33+
return
34+
}
35+
36+
travisClient.repos(owner, repoName).builds.get((err, res) => {
37+
if (err) {
38+
return console.error(`! ${prInfo} Error while retrieving builds`, err.stack)
39+
}
40+
41+
const lastBuildForPr = res.builds.find((build) => build.pull_request_number === prId)
42+
43+
if (lastBuildForPr) {
44+
const lastState = lastBuildForPr.state
45+
46+
if (lastState === 'passed') {
47+
return createGhComment(`[Travis build passed](https://travis-ci.org/${owner}/${repoName}/builds/${lastBuildForPr.id}) :+1:`)
48+
} else if (lastState === 'failed') {
49+
return createGhComment(`[Travis build failed](https://travis-ci.org/${owner}/${repoName}/builds/${lastBuildForPr.id}) :-1:`)
50+
} else if (~['created', 'started'].indexOf(lastState)) {
51+
console.log(`* ${prInfo} "${lastState}" build found, will do check #${checkNumber + 1} in 30 seconds`)
52+
} else {
53+
return console.log(`* ${prInfo} Unknown build state: "${lastState}", stopping polling`)
54+
}
55+
} else {
56+
console.warn(`! ${prInfo} Was not able to find matching build, will do check #${checkNumber + 1} in 30 seconds`)
57+
}
58+
59+
setTimeout(pollAndComment, 30 * 1000, owner, repoName, prId, checkNumber + 1)
60+
})
61+
}
62+
63+
function createGhCommentFn (options) {
64+
const prInfo = prInfoStr(options)
65+
66+
return (message, cb) => {
67+
githubClient.issues.createComment({
68+
user: options.owner,
69+
repo: options.repoName,
70+
number: options.prId,
71+
body: message
72+
}, (err, res) => {
73+
if (err) {
74+
return console.error(`! ${prInfo} Error from GitHub`, err.stack)
75+
}
76+
console.log(`* ${prInfo} Github comment created`)
77+
})
78+
}
79+
}
80+
81+
function prInfoStr (options) {
82+
return `${options.owner}/${options.repoName}/#${options.prId}`
83+
}
84+
85+
exports.pollAndComment = pollAndComment

package.json

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"name": "nodejs-github-bot",
3+
"version": "1.0.0-beta1",
4+
"description": "Node.js GitHub Bot",
5+
"scripts": {
6+
"start": "node server.js",
7+
"test": "standard"
8+
},
9+
"engines": {
10+
"node": ">= 4.2.0"
11+
},
12+
"private": true,
13+
"license": "MIT",
14+
"dependencies": {
15+
"body-parser": "^1.15.0",
16+
"express": "^4.13.4",
17+
"github": "^0.2.4",
18+
"travis-ci": "^2.1.0"
19+
},
20+
"devDependencies": {
21+
"standard": "^6.0.7"
22+
}
23+
}

server.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
'use strict'
2+
3+
const express = require('express')
4+
const bodyParser = require('body-parser')
5+
6+
const pollTravis = require('./lib/pollTravis')
7+
8+
const app = express()
9+
10+
const port = process.env.PORT || 3000
11+
12+
app.use(bodyParser.json())
13+
14+
app.all('/hooks/github', (req, res) => {
15+
if (wasPullRequestOpened(req)) {
16+
const repo = req.body.repository
17+
18+
console.log(`* ${repo.owner.login}/${repo.name}/#${req.body.number} Opened, starting build checks!`)
19+
pollTravis.pollAndComment(repo.owner.login, repo.name, parseInt(req.body.number))
20+
}
21+
22+
res.end()
23+
})
24+
25+
// to trigger polling manually
26+
app.get('/pr/:owner/:repo/:prId', (req, res) => {
27+
pollTravis.pollAndComment(req.params.owner, req.params.repo, parseInt(req.params.prId))
28+
res.end()
29+
})
30+
31+
app.listen(process.env.PORT || 3000, () => {
32+
console.log('Example app listening on port', port)
33+
})
34+
35+
function wasPullRequestOpened (req) {
36+
const githubEvent = req.headers['x-github-event'] || ''
37+
const githubAction = req.body.action || ''
38+
return githubEvent === 'pull_request' && githubAction === 'opened'
39+
}

0 commit comments

Comments
 (0)