Skip to content

Instantly share code, notes, and snippets.

@dvdsgl
Created February 25, 2012 21:58
Show Gist options
  • Star 18 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save dvdsgl/1911084 to your computer and use it in GitHub Desktop.
Save dvdsgl/1911084 to your computer and use it in GitHub Desktop.
Automated Jenkins Comments on GitHub Pull Requests

Configure the post-build hook and launch it on Heroku:

$ git clone git://gist.github.com/1911084.git jenkins-comments
$ cd jenkins-comments
$ heroku create --stack cedar
$ heroku config:add NODE_ENV=production
$ heroku config:add GITHUB_USER_LOGIN=...
$ heroku config:add GITHUB_USER_PASSWORD=...
$ heroku config:add JENKINS_URL=...
$ git push heroku master
$ heroku ps:scale web=1

Then configure your Jenkins job to call the post-build hook to report job status:

$ curl "http://your.herokuapp.com/jenkins/post_build?\
    user=$GITHUB_USER\
    &repo=$GITHUB_REPO\
    &sha=$GIT_COMMIT\
    &status=$BUILD_STATUS\
    &job=$BUILD_NUMBER"

You'll have to specify GITHUB_USER, GITHUB_REPO, and your build should set BUILD_STATUS=success if the build succeeded.

async = require 'async'
request = require 'request'
express = require 'express'
_ = require 'underscore'
_s = require 'underscore.string'
class PullRequestCommenter
BUILDREPORT = "**Build Status**:"
constructor: (@sha, @job, @user, @repo, @succeeded) ->
@job_url = "#{process.env.JENKINS_URL}/job/#{@repo}/#{@job}"
@api = "https://#{process.env.GITHUB_USER_LOGIN}:#{process.env.GITHUB_USER_PASSWORD}@api.github.com/#{@user}/#{@repo}"
post: (path, obj, cb) =>
request.post { uri: "#{@api}#{path}", json: obj }, (e, r, body) ->
cb e, body
get: (path, cb) =>
request.get { uri: "#{@api}#{path}", json: true }, (e, r, body) ->
cb e, body
del: (path, cb) =>
request.del { uri: "#{@api}#{path}" }, (e, r, body) ->
cb e, body
getCommentsForIssue: (issue, cb) =>
@get "/issues/#{issue}/comments", cb
deleteComment: (id, cb) =>
@del "/issues/comments/#{id}", cb
getPulls: (cb) =>
@get "/pulls", cb
getPull: (id, cb) =>
@get "/pulls/#{id}", cb
commentOnIssue: (issue, comment) =>
@post "/repos/#{@user}/#{@repo}/issues/#{issue}/comments", (body: comment), (e, body) ->
console.log e if e?
successComment: ->
"#{BUILDREPORT} `Succeeded` (#{@sha}, [job info](#{@job_url}))"
errorComment: ->
"#{BUILDREPORT} `Failed` (#{@sha}, [job info](#{@job_url}))"
# Find the first open pull with a matching HEAD sha
findMatchingPull: (pulls, cb) =>
pulls = _.filter pulls, (p) => p.state is 'open'
async.detect pulls, (pull, detect_if) =>
@getPull pull.number, (e, { head }) =>
return cb e if e?
detect_if head.sha is @sha
, (match) =>
return cb "No pull request for #{@sha} found" unless match?
cb null, match
removePreviousPullComments: (pull, cb) =>
@getCommentsForIssue pull.number, (e, comments) =>
return cb e if e?
old_comments = _.filter comments, ({ body }) -> _s.include body, BUILDREPORT
async.forEach old_comments, (comment, done_delete) =>
@deleteComment comment.id, done_delete
, () -> cb null, pull
makePullComment: (pull, cb) =>
comment = if @succeeded then @successComment() else @errorComment()
@commentOnIssue pull.number, comment
cb()
updateComments: (cb) ->
async.waterfall [
@getPulls
@findMatchingPull
@removePreviousPullComments
@makePullComment
], cb
app = module.exports = express.createServer()
app.configure 'development', ->
app.set "port", 3000
app.configure 'production', ->
app.use express.errorHandler()
app.set "port", parseInt process.env.PORT
# Jenkins lets us know when a build has failed or succeeded.
app.get '/jenkins/post_build', (req, res) ->
sha = req.param 'sha'
job = parseInt req.param 'job'
user = req.param 'user'
repo = req.param 'repo'
succeeded = req.param('status') is 'success'
# Look for an open pull request with this SHA and make comments.
commenter = new PullRequestCommenter sha, job, user, repo, succeeded
commenter.updateComments (e, r) -> console.log e if e?
res.send 'Ok', 200
app.listen app.settings.port
{
"name": "jenkins-pull-request-commenter"
, "version": "0.0.1"
, "private": true
, "dependencies": {
"express": "2.5.7"
, "jade": ">= 0.0.1"
, "coffee-script": "1.2.x"
, "underscore": "*"
, "underscore.string": "*"
, "request": "*"
, "async": "*"
}
}
web: node server.js
require('coffee-script');
require('./app');
@justincampbell
Copy link

We modified this to store Jenkins' results in Redis and insta-comment when a pull is opened if you're interested: https://github.com/cramerdev/jenkins-comments

@dvdsgl
Copy link
Author

dvdsgl commented Apr 30, 2012 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment