14

有没有人有我可以使用的 git commit 钩子来确保签入消息中出现 JIRA 问题编号?我没有从 git commit 钩子驱动 JIRA 的经验,所以任何帮助都将不胜感激——工作源更是如此!

4

4 回答 4

18

首先,使钩子可执行:

chmod a+x .git/hooks/commit-msg

附加以下行,用您的项目代码替换 PROJECT。

test "" != "$(grep 'PROJECT-' "$1")" || {
        echo >&2 "ERROR: Commit message is missing Jira issue number."
        exit 1
}
于 2009-12-11T01:06:20.973 回答
1
#!/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 <bob@example.com>
#     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/repo/.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  = "DEMO"
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
于 2010-09-15T22:26:12.113 回答
0

Ops,我从来没有,仍然,使用 git,但是一个朋友制作了 SVN-Hooks,一个用于创建 Subversion 钩子的框架。它是用 perl 编码的。也许这有任何帮助。在那里看一下:

http://code.google.com/p/svn-hooks/source/browse/trunk/t/02-jiraacceptance.t

如果您需要尽快致电我们,我们将很乐意提供帮助。

于 2009-10-01T11:11:45.413 回答
-1

我会编写一个提交挂钩,以确保看起来像 JIRA 问题编号的内容出现在提交消息中的某处。为此,一个简单的正则表达式匹配就可以了:

/[A-Z0-9]+-\d+/

如果您愿意,为了额外的错字保护,您可以确保第一部分与您在 JIRA 中设置的某些项目标识符匹配:

/(ABC|XYZ|PONIES)-\d+/

我发现尝试确保其中的数字部分指的是有效的问题编号没有什么价值。实际上没有任何方法可以确定用户是否输入了正确的问题编号(即使您设法将其限制为未解决的问题,用户仍然可以输入不相关的未解决问题编号)。用户在提交代码时应该小心谨慎。

于 2009-10-09T07:56:57.827 回答