Skip to content

Instantly share code, notes, and snippets.

@dpmcnevin
Created March 30, 2011 23:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save dpmcnevin/895521 to your computer and use it in GitHub Desktop.
Save dpmcnevin/895521 to your computer and use it in GitHub Desktop.
Git post-receive hook to modify stories in Pivotal Tracker
require 'rubygems'
require 'mail'
require 'pivotal_tracker'
require 'git'
class Pivotal
attr_reader :story, :project
def initialize(story_id)
@project = Pivotal.set_auth!
@story = @project.stories.find(story_id)
end
def self.set_auth!
## PivotalTracker::Client.token('user@example.com', 'secretpassword')
PivotalTracker::Client.token = '..........'
## project id for gobbler
PivotalTracker::Project.find(123456)
end
def self.create!(title, story_type = "feature")
@project = set_auth!
new_story = @project.stories.create(:name => title, :story_type => story_type, :estimate => 1)
puts new_story.id
end
def description
<<-EOP
#{@story.name}
Requested By: #{@story.requested_by} :: Owned By #{@story.owned_by}
#{@story.url}
EOP
end
def start!(note)
if @story.estimate >= 0 && @story.current_state == "unscheduled"
@story.update(:current_state => "started")
@story.notes.create(:text => note)
elsif @story.estimate == -1
warning_message("Story ID: ##{@story.id} does not have a points estimate\n\n#{@story.url}")
else
warning_message("Story ID: ##{@story.id} not marked as unscheduled (current: #{@story.current_state})\n\n#{@story.url}")
end
end
def finish!(note, params = {})
## Allow stories to be started if they aren't already
options = {:allow_unstarted => true}.merge(params)
if (@story.current_state == "unscheduled" && options[:allow_unstarted]) || @story.current_state == "started"
@story.update(:current_state => "finished")
@story.notes.create(:text => note)
else
warning_message("Story ID: ##{@story.id} not marked as started (current: #{@story.current_state})\n\n#{@story.url}")
end
end
def deliver!(note)
if @story.current_state == "finished"
@story.update(:current_state => "delivered")
@story.notes.create(:text => note)
else
warning_message("Story ID: ##{@story.id} not marked as finished (current: #{@story.current_state})\n\n#{@story.url}")
end
end
def warning_message(text)
puts "***********************************************"
puts text
puts "***********************************************"
end
end
#!/usr/bin/env ruby
require 'hooks/pivotal'
stdins = []; stdins << $_ while gets
stdins.each do |str|
arr = str.split
refs = arr[2].split('/')
@old_rev = arr[0]
@new_rev = arr[1]
@ref_type = refs[1]
@ref_name = refs[2]
end
## if we are pushing tags, we don't need to continue
exit unless @ref_type == "heads"
@stories = []
## If we want to get all of the commits, we need to have a big value for git log, doesn't look like you can disable it.
## We need to check to see if the original rev is all 0's, since git will pass that if it's the first commit.
@repo = Git.bare(".")
if @old_rev =~ /^00000/
@logs = @repo.log(10000)
else
@logs = @repo.log(10000).between(@old_rev, @new_rev)
end
@logs.each do |log|
log_stories = log.message.scan(/[\#|\/]([0-9]{8})/)
if log_stories.size > 0
@stories << {
:stories => log_stories,
:story_note => "SHA: #{log.sha}\nAuthor: #{log.committer.name}\n#{log.committer.date}\n\n#{log.message}"
}
end
end
if @ref_name == "release"
@resolved = @stories.map {|story| story[:stories] }.flatten.uniq
@message = "===> Pivotal Stories Resolved:\n"
@resolved.each do |story|
begin
@message << Pivotal.new(story).description
rescue
## uh oh
end
end
@message << "\n\n===> Git Commits:\n"
@logs.each do |log|
@message << "#{log.sha[0..6]} :: #{log.committer.email} :: #{log.message.gsub(/\n/," ")[0..70]}\n"
end
puts "====> Emailing about the commit to Release"
## Send mail
mail = Mail.new do
from "git@example.com"
to "all@example.com"
subject "[GIT] New Commit to Release Branch"
end
mail.body = "There has been a commit to the release branch. The release includes the following commits:\n\n#{@message}"
mail.delivery_method :sendmail
mail.deliver
else
@finished_stories = []
@stories.each do |match|
match[:stories].flatten.each do |story|
## Only perform actiion once per story
next if @finished_stories.include?(story)
@finished_stories << story
begin
pivotal_story = Pivotal.new(story)
if @ref_name == "rc"
puts "===> Delivering Story ##{story} in Pivotal Tracker"
pivotal_story.deliver!("Story merged into RC\n\n#{match[:story_note]}")
elsif @ref_name == "master"
puts "===> Finishing Story ##{story} in Pivotal Tracker"
pivotal_story.finish!("Story marked as finished\n\n#{match[:story_note]}")
end
rescue Exception => e
puts "====> There was an error with the story ##{story}"
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment