Skip to content

Commit 8824234

Browse files
committed
Merge pull request #12 from nodejs-github-bot/poll-travis-by-sha
Add support for polling Travis CI builds by SHA
2 parents 0088b5e + cf21a4f commit 8824234

File tree

2 files changed

+100
-6
lines changed

2 files changed

+100
-6
lines changed

lib/pollTravis.js

Lines changed: 98 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,33 @@ githubClient.authenticate({
2222
token: process.env.GITHUB_TOKEN
2323
})
2424

25-
function pollAndComment (owner, repoName, prId, checkNumber) {
25+
function pollThenComment (owner, repoName, prId) {
26+
const prInfo = prInfoStr({ owner, repoName, prId })
27+
28+
// we have to figure out what type of Travis polling we should perform,
29+
// either by PR #id (as for nodejs.org) or commit sha (for readable-stream)
30+
travisClient.repos(owner, repoName).builds.get((err, res) => {
31+
if (err) {
32+
return console.error(`! ${prInfo} Error while retrieving initial builds`, err.stack)
33+
}
34+
35+
const hasAnyPrBuilds = res.builds.some((build) => build.pull_request)
36+
37+
if (hasAnyPrBuilds) {
38+
pollByPrThenComment(owner, repoName, prId)
39+
} else {
40+
pollByCommitThenComment(owner, repoName, prId)
41+
}
42+
})
43+
}
44+
45+
/**
46+
* When Travis CI picks up our PR's, we can poll and match builds
47+
* by their related PR #id.
48+
*
49+
* That's the case for nodejs.org.
50+
*/
51+
function pollByPrThenComment (owner, repoName, prId, checkNumber) {
2652
checkNumber = checkNumber || 1
2753

2854
const prInfo = prInfoStr({ owner, repoName, prId })
@@ -56,7 +82,75 @@ function pollAndComment (owner, repoName, prId, checkNumber) {
5682
console.warn(`! ${prInfo} Was not able to find matching build, will do check #${checkNumber + 1} in 30 seconds`)
5783
}
5884

59-
setTimeout(pollAndComment, 30 * 1000, owner, repoName, prId, checkNumber + 1)
85+
setTimeout(pollByPrThenComment, 30 * 1000, owner, repoName, prId, checkNumber + 1)
86+
})
87+
}
88+
89+
/**
90+
* When Travis CI *doesn't* pick up our PR's, we have to poll and match builds
91+
* by the last commit SHA of the related PR.
92+
*
93+
* This is the case for readable-stream.
94+
*/
95+
function pollByCommitThenComment (owner, repoName, prId) {
96+
const prInfo = prInfoStr({ owner, repoName, prId })
97+
98+
githubClient.pullRequests.getCommits({
99+
user: owner,
100+
repo: repoName,
101+
number: prId
102+
}, (err, commitMetas) => {
103+
if (err) {
104+
return console.error(`! ${prInfo} Got error when retrieving GitHub commits for PR`, err.stack)
105+
}
106+
107+
const lastSha = commitMetas.pop().sha
108+
pollTravisBuildBySha({ owner, repoName, prId, lastSha })
109+
console.log(`* ${prInfo} Started polling Travis for build by commit ${lastSha.substr(0, 7)}`)
110+
})
111+
}
112+
113+
function pollTravisBuildBySha (options, checkNumber) {
114+
const createGhComment = createGhCommentFn(options)
115+
const prInfo = prInfoStr(options)
116+
const shaToMatch = options.lastSha
117+
118+
checkNumber = checkNumber || 1
119+
120+
if (checkNumber > 100) {
121+
console.warn(`* ${prInfo} Was not able to find matching build for PR, stopping poll now :(`)
122+
return
123+
}
124+
125+
travisClient.repos(options.owner, options.repoName).builds.get((err, res) => {
126+
if (err) {
127+
return console.error(`! ${prInfo} Got error when retrieving Travis builds`, err.stack)
128+
}
129+
130+
const matchingCommit = res.commits.find((commit) => commit.sha === shaToMatch)
131+
if (!matchingCommit) {
132+
console.warn(`! ${prInfo} Travis hasn't picked up last commit yet, will do check #${checkNumber + 1} in 30 seconds`)
133+
return setTimeout(pollTravisBuildBySha, 30 * 1000, options, checkNumber + 1)
134+
}
135+
136+
const lastBuildForCommit = res.builds.find((build) => build.commit_id === matchingCommit.id)
137+
if (lastBuildForCommit) {
138+
const lastState = lastBuildForCommit.state
139+
140+
if (lastState === 'passed') {
141+
return createGhComment(`[Travis build passed](https://travis-ci.org/${options.owner}/${options.repoName}/builds/${lastBuildForCommit.id}) :+1:`)
142+
} else if (lastState === 'failed') {
143+
return createGhComment(`[Travis build failed](https://travis-ci.org/${options.owner}/${options.repoName}/builds/${lastBuildForCommit.id}) :-1:`)
144+
} else if (~['created', 'started'].indexOf(lastState)) {
145+
console.log(`* ${prInfo} "${lastState}" build found, will do check #${checkNumber + 1} in 30 seconds`)
146+
} else {
147+
return console.log(`* ${prInfo} Unknown build state: "${lastState}", stopping polling`)
148+
}
149+
} else {
150+
console.warn(`! ${prInfo} Was not able to find matching build by last commit, will do check #${checkNumber + 1} in 30 seconds`)
151+
}
152+
153+
setTimeout(pollTravisBuildBySha, 30 * 1000, options, checkNumber + 1)
60154
})
61155
}
62156

@@ -71,7 +165,7 @@ function createGhCommentFn (options) {
71165
body: message
72166
}, (err, res) => {
73167
if (err) {
74-
return console.error(`! ${prInfo} Error from GitHub`, err.stack)
168+
return console.error(`! ${prInfo} Error while creating GitHub comment`, err.stack)
75169
}
76170
console.log(`* ${prInfo} Github comment created`)
77171
})
@@ -82,4 +176,4 @@ function prInfoStr (options) {
82176
return `${options.owner}/${options.repoName}/#${options.prId}`
83177
}
84178

85-
exports.pollAndComment = pollAndComment
179+
exports.pollThenComment = pollThenComment

server.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@ app.all('/hooks/github', (req, res) => {
1616
const repo = req.body.repository
1717

1818
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))
19+
pollTravis.pollThenComment(repo.owner.login, repo.name, parseInt(req.body.number))
2020
}
2121

2222
res.end()
2323
})
2424

2525
// to trigger polling manually
2626
app.get('/pr/:owner/:repo/:prId', (req, res) => {
27-
pollTravis.pollAndComment(req.params.owner, req.params.repo, parseInt(req.params.prId))
27+
pollTravis.pollThenComment(req.params.owner, req.params.repo, parseInt(req.params.prId))
2828
res.end()
2929
})
3030

0 commit comments

Comments
 (0)