Created
April 6, 2011 16:51
-
-
Save mmrwoods/906027 to your computer and use it in GitHub Desktop.
Capistrano Lighthouse integration script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
# this simple script takes two arguments, the rails environment we're deploying to and a commit range to be passed to git-log | |
# The commit range MUST be in the format <full sha of previous revision>..<full sha of current revision>, otherwise the world will end | |
# It looks at git commit messages between the previous and current revision, extracts lighthouse ticket numbers where they are provided | |
# in the commit message; updates the ticket in lighthouse, changing the state to 'resolved' for deploys to production, both changing | |
# state to 'uat' and re-assigning the ticket to the creator for deploys to stage; then sends an email listing the deployed tickets. | |
# Note: if rails environment is edge, does a dummy run as if it was deploying to stage, but doesn't save updates to tickets or send the email | |
LH_TOKEN = YOUR-LIGHTHOUSE-API-TOKEN | |
LH_ACCOUNT = YOUR-LIGHTHOUSE-ACCOUNT-NAME | |
LH_PROJECT_ID = nil # set to project id if account has more than one project (we just get the first by default) | |
MAIL_TO = NOTIFICATION-EMAIL | |
QA_MAIL_TO = nil # set if you need QA notifications sent to a different address | |
SMTP_SERVER = "localhost" | |
puts "Executing script/deploy_lighthouse #{ARGV.join(' ')}" | |
if ARGV.length < 2 | |
puts "ERROR: deploy_lighthouse script needs two arguments, the rails environment and the commit range (previous_revision_sha..current_revision_sha)" | |
exit # be nice to cap, and exit 0 | |
end | |
unless %w{ edge stage production }.include? ARGV[0] | |
puts "Rails environment isn't edge, stage or production, nothing to do" | |
exit # be nice to cap, and exit 0 | |
end | |
begin | |
require File.dirname(__FILE__) + "/../config/init" # override rubygems and use aspire's gem bundling | |
require 'fileutils' | |
require 'lighthouse' | |
Lighthouse.token = LH_TOKEN | |
Lighthouse.account = LH_ACCOUNT | |
rails_env = ARGV[0] | |
git_commit_range = ARGV[1] | |
# only tickets with one of these previous states will be updated | |
# note: sequence important, we have to loop over this array and get tickets at each state | |
previous_states = %w{deploy uat qa coding-done query} | |
# new state after we update the ticket depends on environment | |
if %w{ edge stage }.include? rails_env | |
new_state = 'qa' | |
mail_to = QA_MAIL_TO || MAIL_TO | |
else | |
new_state = 'resolved' | |
mail_to = MAIL_TO | |
end | |
puts "=== Rails env is edge - dummy run, changes to tickets will not be saved ===" if rails_env == 'edge' | |
# ensure we are in root of the project | |
Dir.chdir(File.join(File.dirname(__FILE__), "..")) | |
# extract ticket numbers from commit messages between previous and current revision | |
puts "extracting ticket numbers from commit messages between previous and current revision ..." | |
ticket_numbers = [] | |
messages = `git log #{git_commit_range} --pretty=format:%s`.split("\n") | |
messages.each { |message| ticket_numbers << message.match(/(\[#)(\d+)/)[2].to_i if message =~ /(\[#)(\d+)/ } | |
ticket_numbers.uniq! | |
puts "Found #{messages.size} log messages containing #{ticket_numbers.size} ticket numbers" | |
puts "Ticket numbers are #{ticket_numbers.inspect}" | |
# update tickets in lighthouse... | |
puts "updating tickets in lighthouse..." | |
project = LH_PROJECT_ID.to_s.match(/^[0-9]+$/) ? Lighthouse::Project.find(LH_PROJECT_ID.to_i) : Lighthouse::Project.find(:first) | |
ticket_info = {} | |
previous_states.each do |previous_state| | |
project.tickets(:q => "state:#{previous_state}").each do |ticket| | |
next unless ticket_numbers.include? ticket.number | |
ticket.state = new_state | |
ticket_info[ticket.number] = "#{ticket.title} -> state:#{ticket.state}" + ( new_state != 'resolved' ? ", responsible:#{ticket.user_name}" : '') | |
puts "Saving ticket ##{ticket.number} #{ticket_info[ticket.number]}" | |
begin | |
ticket.save unless rails_env == 'edge' | |
rescue Exception => e | |
puts "ERROR #{e}, failed to save ticket ##{ticket.number}, please update this ticket manually" | |
ticket_info.delete(ticket.number) | |
next | |
end | |
end | |
end | |
if rails_env != 'edge' && ticket_info.size > 0 && !mail_to.nil? && mail_to.length > 0 # um, is there a need to be any smarter here? | |
puts "Sending summary of lighthouse updates to #{mail_to}" | |
begin | |
require 'socket' | |
require 'net/smtp' | |
host_name = Socket.gethostbyname(Socket.gethostname).first rescue Socket.gethostname | |
mail_from = "deploy@#{host_name}" | |
subject = "#{rails_env.capitalize} deploy lighthouse tickets" | |
headers = <<-HEADERS_END | |
From: #{project.name} <#{mail_from}> | |
To: #{mail_to} | |
Subject: #{subject} | |
Content-type: text/html | |
HEADERS_END | |
headers.gsub!(/^(\s+)(.*)$/,'\2') # trash the leading spaces | |
ticket_base_url = "https://#{LH_ACCOUNT}.lighthouseapp.com/projects/#{project.id}/tickets/" | |
message = "<p>The following items have been deployed to #{rails_env}...</p><ul>" | |
ticket_info.each do |k, v| | |
message << "<li><a href='#{ticket_base_url}#{k}'>#{k}</a> - #{v}</li>" | |
end | |
message << "</ul>" | |
# add footer if new state is uat or qa | |
if new_state == 'uat' | |
message << %q{ | |
<p> | |
<strong>If you are responsible for a ticket, according to the above list (that is, you're the person who created the ticket)...</strong><br> | |
We'd like you to work out who should do the UAT and make sure it gets done. That's probably the person who asked you to create the ticket, or it might be you. | |
</p> | |
<p> | |
<strong>If you are a stakeholder (of the new feature) or reporter (of the bug)...</strong><br> | |
Someone will be in touch soon to get you involved in the UAT. Please review the changes on stage as soon as you can. If you need any assistance, are unsure of what has been fixed or are unhappy with the work, please let us know. | |
</p> | |
<p> | |
<strong>If you're not a stakeholder, BUT you or the team you manage might be impacted by the changes...</strong><br> | |
Please make time to review the changes on stage (with developer help if required). | |
</p> | |
<p> | |
Thanks | |
</p> | |
} | |
elsif new_state == 'qa' | |
message << %q{ | |
<p> | |
Tickets are now in QA guys, you know what to do. | |
</p> | |
<p> | |
Thanks, Robot | |
</p> | |
} | |
end | |
Net::SMTP.start(SMTP_SERVER) do |smtp| | |
smtp.send_message headers + "\n" + message, mail_from, mail_to | |
end | |
puts "Message has been passed to #{SMTP_SERVER} for delivery" | |
rescue Exception => e | |
puts "ERROR #{e}, sending output via email failed, it's time to copy 'n' paste" | |
end | |
end | |
rescue Exception => e | |
puts "Exception #{e}..." | |
puts e.backtrace | |
exit # note: a non-zero exit code results in capistrano raising an exception, which we don't want | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment