28 May 2009 - San Antonio
Using the following code:
#!/usr/bin/env ruby
require 'rubygems'
require 'net/http'
require 'net/https'
require 'json'
# EDIT POST_RECEIVE_URL
POST_RECEIVE_URL = 'https://my.domain.com/application_name/push'
old_head, new_head, ref = STDIN.gets.split
#puts "old_head: #{old_head}"
#puts "new_head: #{new_head}"
#puts "ref: #{ref}"
revision_text = `git-rev-list --pretty=format:'Author: %an <%ae>%nDate: %cd%n%s%n' #{new_head} ^#{old_head}`
revisions = []
revision_text.split(/\n\n/).each { |commit|
s = commit.split(/\n/)
s[0] =~ /commit (\w+)/
sha1 = $1
s[1] =~ /Author: (.*) <(.+?)>/
author_name, author_email = $1, $2
s[2] =~ /Date: +(.+?) -0/
timestamp = $1
message = s[3].strip
revisions << {
'id' => sha1,
'author' => {
'email' => author_email,
'name' => author_name,
},
'message' => message,
'timestamp' => timestamp,
}
}
if revisions.empty?
exit 0
end
payload = {
'payload' => {
"ref" => ref,
"commits" => revisions,
}.to_json
}
if pid = fork
Process.detach pid
else
uri = URI.parse(POST_RECEIVE_URL)
post_req = Net::HTTP::Post.new(uri.path)
post_req.basic_auth '53cr3t', 'p@55w0rd'
post_req.set_form_data(payload, ';')
req = Net::HTTP.new(uri.host, uri.port)
req.use_ssl = true
req.verify_mode = OpenSSL::SSL::VERIFY_NONE
req.start {|http| http.request(post_req)}
end
puts "Running Integrity CI build for application_name application"
This git post-receive hook script queries the latest commit, gets the revision changes, and then passes that payload (via json) to a net/https POST call. I setup our Integrity CI server with a self-signed certificate and HTTP basic authentication.
The Net::HTTP::Post.new instantiation group handles populating the basic authentication information and putting the payload into the form data of the request. The Net::HTTP.new group handles telling the request that it will be via SSL (443) and to not verify the SSL certificate (since I’m using a self-signed certificate; otherwise, I’d get a warning and kill my automation process)
The other important part is the “if pid = fork”. The ruby fork command allows code to happen in the background, in the case the POST call, and therefore make the call synchronous. Otherwise, when the developers commit their code to the repository, they will have to wait for the build to finish before their prompt will be returned to them. fork will return zero (0) if it fails to create the background process.
I’m still checking whether the zombie process warning in the rdoc (for the fork command) is a problem. I’ll update this if it is.
The last line is notification for the user so they know what’s going on. Always good to keep the user in the loop. :)