-
-
Save elskwid/404280 to your computer and use it in GitHub Desktop.
This file contains 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 | |
# | |
# Update JIRA with git commit messages | |
# | |
# == Usage == | |
# | |
# To update a JIRA issue, prepend the first line of your git commit message | |
# with the issue key and a colon: | |
# | |
# $ git commit -m "GIT-1: Updates something" | |
# | |
# A comment will be added to the GIT-1 issue that looks something like: | |
# | |
# Commit: <Hash> | |
# Author: Bob Example <[email protected]> | |
# Date: Mon Jul 14 14:00:00 -0400 2008 | |
# | |
# GIT-1: Updates something | |
# | |
# To change an issue's status, append an action string: | |
# | |
# GIT-1 resolved: Updates something | |
# GIT-1 closed: Finishes this | |
# GIT-1 reopen: Starting work on this | |
# | |
# To update multiple issues, separate them with a comma: | |
# | |
# GIT-1, GIT-2: Adds comments to GIT-1 and GIT-2 | |
# GIT-1, GIT-2 resolved: Updates GIT-1 and resolves GIT-2 | |
# | |
# == Installation == | |
# | |
# To get this working, first install a few gems: | |
# | |
# $ gem install soap4r | |
# | |
# Now, jira4r, which has to be pulled down from subversion: | |
# | |
# $ svn co http://svn.rubyhaus.org/jira4r/trunk jira4r | |
# $ cd jira4r | |
# $ gem build jira4r.gemspec | |
# $ gem install jira4r-*.gem | |
# | |
# And finally, grit, a Ruby git library. As of today (July 14, 2008), | |
# the most updated fork is being maintained by Scott Chacon on github. | |
# For whatever reason, my attempt to install the gem directly wasn't | |
# working (doesn't appear to be exposed?), so I cloned and installed | |
# directly: | |
# | |
# $ git clone git://github.com/schacon/grit.git | |
# $ cd grit | |
# $ gem build grit.gemspec | |
# $ gem install grit-*.gem | |
# | |
# When the gem gets fixed, it should be a simple: | |
# | |
# $ gem sources --add http://gems.github.com | |
# $ gem install schacon-grit | |
# | |
# Now just copy/symlink/move an executable copy of this file into your | |
# .git/hooks directory (be sure not to overwrite an existing hook): | |
# | |
# $ cp jira-post-receive /path/to/repository/.git/hooks/post-receive | |
# | |
# And don't forget to update some globals below. Voila. You should be | |
# in business. | |
# | |
# == TODO == | |
# | |
# * Get status changes with comments working. | |
# | |
require "rubygems" | |
require "jira4r/jira_tool" | |
require "grit" | |
# Don't forget to set these. | |
# | |
# I'd recommend creating a dedicated user in JIRA to execute these updates. | |
# That user will need permissions to: | |
# | |
# * Browse Projects | |
# * Resolve Issues | |
# * Close Issues | |
# * Add Comments | |
# | |
# (I think that's comprehensive.) | |
JIRA_ADDRESS = "http://yourserver.com/jira" | |
JIRA_PROJECT = "DEWEBMO" | |
JIRA_USERNAME = "user" | |
JIRA_PASSWORD = "password" | |
class JiraPostReceive | |
def initialize(old_commit, new_commit, ref) | |
@old_commit = old_commit | |
@new_commit = new_commit | |
@ref = ref | |
@repo = Grit::Repo.new(".") | |
end | |
def jira | |
unless @jira | |
@jira = Jira4R::JiraTool.new(2, JIRA_ADDRESS) | |
@jira.logger = Logger.new("/dev/null") | |
@jira.login(JIRA_USERNAME, JIRA_PASSWORD) | |
end | |
@jira | |
end | |
def run | |
unless issues.empty? | |
jira # Sets up access to Jira4R::V2 constants | |
issues.each do |issue| | |
begin | |
send_comment(issue) | |
send_new_status(issue) if issue[:new_status] | |
rescue | |
next | |
end | |
end | |
end | |
end | |
# Adds a comment to the JIRA issue | |
# | |
# Unfortunately, all comments originate from the dedicated JIRA user | |
# that's used to post the comment. It's possible to set a different | |
# author for the comment, but looking one up via email in JIRA doesn't | |
# seem possible without giving the user administrative rights. | |
def send_comment(issue) | |
comment = Jira4R::V2::RemoteComment.new | |
comment.author = JIRA_USERNAME | |
comment.body = generate_comment(issue[:commit]) | |
jira.addComment(issue[:key], comment) | |
end | |
def send_new_status(issue) | |
status_string = case issue[:new_status] | |
when "resolved" then "Resolve Issue" | |
when "closed" then "Close Issue" | |
when "reopen" then "Reopen Issue" | |
end | |
if status = jira.getAvailableActions(issue[:key]). | |
find { |a| a.name == status_string } | |
jira.progressWorkflowAction(issue[:key], status.id.to_s, []) | |
end | |
end | |
def issues | |
issues = [] | |
issued_commits.each do |commit| | |
issue_string = commit.short_message.match(/(.*?):/)[1] | |
issue_string.split(",").each do |snippet| | |
snippet.strip! | |
snippet =~ /(#{JIRA_PROJECT}-\d+)\s?(resolved|closed|reopen)?/i | |
issues << { :key => $1, :new_status => $2, :commit => commit } | |
end | |
end | |
issues | |
end | |
def issued_commits | |
new_commits.select do |commit| | |
commit.short_message =~ /(#{JIRA_PROJECT}-\d+)(.*):/ | |
end | |
end | |
# Fetch commits that are new to the repository | |
# | |
# That super-piped git command makes sure that we only update JIRA with | |
# commits that are new, and haven't been seen in any other branches. | |
# It's lifted verbatim from the post-receive-email hook that's shipped | |
# in the git repository (contrib/hooks/post-receive-email). | |
def new_commits | |
common_cmd = "git rev-parse --not --branches | " + | |
"grep -v $(git rev-parse #{@ref}) | " + | |
"git rev-list --stdin " | |
commit_ids = if branch_created? | |
`#{common_cmd} #{@new_commit}`.split | |
elsif branch_updated? | |
`#{common_cmd} #{@old_commit}..#{@new_commit}`.split | |
else | |
[] | |
end | |
commit_ids.map { |id| @repo.commit(id) }.reverse | |
end | |
def generate_comment(commit) | |
<<-EOS | |
Commit: #{commit.id} | |
Author: #{commit.author.name} <#{commit.author.email}> | |
Date: #{commit.authored_date} | |
#{commit.message} | |
EOS | |
end | |
def branch_created? | |
@ref =~ /refs\/heads/ && @old_commit =~ /^0+$/ | |
end | |
def branch_updated? | |
@ref =~ /refs\/heads/ && @old_commit !~ /^0+$/ && @new_commit !~ /^0+$/ | |
end | |
end | |
old_commit, new_commit, ref = STDIN.gets.split | |
JiraPostReceive.new(old_commit, new_commit, ref).run | |
exit 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment