class JiraCommentAddHook
The hook checks that commit message has one or more valid Jira ticket references. In general we can't always reject a commit. So we continue through the list of commits, check everything and report errors.
Constants
- Hook
applypatch-msg, pre-applypatch, post-applypatch prepare-commit-msg, commit-msg pre-rebase, post-checkout, post-merge, update, post-update, pre-auto-gc, post-rewrite
- OPTIONS
- VALID_ERROR_TYPES
Attributes
errors_to_report[RW]
Public Class Methods
new(options = {})
click to toggle source
# File lib/ruby_git_hooks/jira_add_comment.rb, line 31 def initialize(options = {}) bad_options = options.keys - OPTIONS raise "JiraCommentAddHook created with unrecognized options: " + "#{bad_options.inspect}!" if bad_options.size > 0 if !options.has_key?("username") || !options.has_key?("password") raise "You must provide Jira server user name and password in options" end @options = options @options["protocol"] ||= "https" @options["host"] ||= "jira" @options["api_path"] ||= "rest/api/latest/issue" @options["github"] ||= "github.com" @options["check_status"] = true if !@options.has_key? "check_status" # don't allow "closed" issues by default # options for error emailing @options["domain"] ||= "mydomain.com" @options["from"] ||= "Jira Jailer <noreply@#{@options["domain"]}>" @options["subject"] ||= "Use Jira Ticket Numbers, Please!" @options["via"] ||= "no_send" @options["via_options"] ||= {} @errors_to_report = {} # listed in hash indexed by user end
Public Instance Methods
add_comment(ticket, comment_text)
click to toggle source
# File lib/ruby_git_hooks/jira_add_comment.rb, line 199 def add_comment(ticket, comment_text) STDERR.puts "ADDING COMMENT for ticket #{ticket}" uri = build_uri(ticket, "comment") data = {"body" => comment_text} STDERR.puts comment_text if !@options["issues"] || @options["issues"].include?(ticket) # can limit to single issue until get the text right. resp = RestClient.post(uri, data.to_json, :content_type => :json, :accept=>:json) # hash = JSON.parse(resp) # do we need to check anything about the response to see if it went ok? # it will throw an error if ticket not found or something. end end
add_error_to_report(commit, msg, error_type = "no_jira")
click to toggle source
# File lib/ruby_git_hooks/jira_add_comment.rb, line 283 def add_error_to_report(commit, msg, error_type = "no_jira") # remember this error so we can report it later with others by this author # store the string we'd like to print out about this commit (commit link and msg) # to make it easier to print later # (could store commit and message separately and process later if necessary) # format: # {"email1@test.com"" => {"no_jira" => ["www.github.com/commit/1234 invalid commit message", # "www.github.com/commit/6789 also invalid"] # "invalid_jira" => ["www.github.com/commit/1212 ABC-123 invalid commit message"]} # "email2@test.com" => {...} } author_email = Hook.shell!("git log #{commit} -1 --pretty='%aN <%aE>'").chomp rescue "no email" errors_to_report[author_email] ||= {"no_jira" => [], "invalid_jira" => []} # in case first error for this author errors_to_report[author_email][error_type] << "#{build_commit_uri(commit[0..7])}\n#{msg}" end
build_commit_uri(commit)
click to toggle source
# File lib/ruby_git_hooks/jira_add_comment.rb, line 108 def build_commit_uri(commit) # like https://github.com/my_github_name/ruby_git_hooks/commit/b067c718a74315224bf88a267a82ac85054cdf6e uri = "#{repo_remote_path}/commit/#{commit}" end
build_message(no_jira = [], invalid_jira= [])
click to toggle source
Build the email message. use the remote repo path for the name of the repo since this is always run as post_receive, there should always be a remote path.
# File lib/ruby_git_hooks/jira_add_comment.rb, line 326 def build_message(no_jira = [], invalid_jira= []) description = @options["intro"] || "" description.concat <<DESCRIPTION This notice is to remind you that you need to include valid Jira ticket numbers in all of your Git commits! We encountered the following problems in your recent commits. DESCRIPTION if no_jira.size > 0 description.concat <<DESCRIPTION Commits with no reference to any jira tickets: #{no_jira.join("\n--\n ")} ----- DESCRIPTION end if invalid_jira.size > 0 description.concat <<DESCRIPTION Commits which reference invalid Jira ticket numbers that don't exist or have already been closed: #{invalid_jira.join("\n--\n ")} ----- DESCRIPTION end description.concat @options["conclusion"] if @options["conclusion"] description end
build_uri(ticket, command=nil)
click to toggle source
# File lib/ruby_git_hooks/jira_add_comment.rb, line 59 def build_uri(ticket, command=nil) uri = "#{@options['protocol']}://#{@options['username']}:#{@options['password']}@#{@options['host']}/#{@options['api_path']}/#{ticket}" uri = "#{uri}/#{command}" if command return uri end
check()
click to toggle source
# File lib/ruby_git_hooks/jira_add_comment.rb, line 66 def check # called with a list of commits to check, as post-receive. # consider it a success for now only if all commit checks are successful # may cause us to redo some of the checks. # but for now it's all or nothing. success = true commits.reverse_each do |commit| commit_message = RubyGitHooks::Hook.shell!("git log #{commit} -1 --pretty=%B").rstrip success = false unless check_one_commit(commit, commit_message ) end # send email regarding failed commits report_errors return success end
check_for_valid_ticket(ticket)
click to toggle source
# File lib/ruby_git_hooks/jira_add_comment.rb, line 214 def check_for_valid_ticket(ticket) begin uri = build_uri(ticket) resp = RestClient.get uri hash = JSON.parse(resp) if @options["check_status"] # Grab the Jira bug status, or fall back to allowing # if the format is unexpected. status = hash["fields"]["status"]["name"] rescue "open" if status.downcase == "closed" STDERR.puts "Issue #{ticket} is closed, not allowing." return false end end # The bug (probably) isn't closed (or we aren't checking),so we're valid! return true rescue SocketError STDERR.puts "SocketError finding '#{@options["host"]}': #{$!.inspect}" STDERR.puts "Is '#{@options["host"]}' the right Jira hostname? " STDERR.puts "I'm allowing this in case you're offline, but make sure" STDERR.puts "your hostname is right, please!" return true rescue RestClient::Exception if $!.http_code == 401 STDERR.puts "You're not authorized on this server!" STDERR.puts "Please set your username and password correctly." return false elsif $!.http_code == 404 # Nope, not a valid issue. Keep trying elsif $!.http_code == 407 STDERR.puts "We don't support proxies to Jira yet!" STDERR.puts "I'll give you the benefit of the doubt." return true elsif $!.http_code >= 500 STDERR.puts "Jira got a server error." STDERR.puts "I'll give you the benefit of the doubt." return true else STDERR.puts "Unexpected HTTP Error: #{$!.http_code}!" return false end rescue STDERR.puts "Unexpected exception: #{$!.inspect}!" return false end false # if we get to this point it's not a valid ticket end
check_one_commit(commit, commit_message)
click to toggle source
# File lib/ruby_git_hooks/jira_add_comment.rb, line 164 def check_one_commit(commit, commit_message) STDERR.puts "Checking #{commit[0..6]} #{commit_message.lines.first}" jira_tickets = commit_message.scan(JiraReferenceCheckHook::JIRA_TICKET_REGEXP).map(&:strip).uniq if jira_tickets.length == 0 STDERR.puts ">>Commit message must refer to a jira ticket" add_error_to_report(commit, commit_message, "no_jira") return false end # we know we have to add comments for at least one ticket # so build up the options with more info about the commit. # the comment will be the same in each ticket comment_text = get_comment_content(commit, commit_message) success = false jira_tickets.each do |ticket| valid_ticket = check_for_valid_ticket(ticket) if valid_ticket add_comment(ticket, comment_text) success = true end end unless success STDERR.puts ">>Commit message must refer to a valid jira ticket" add_error_to_report(commit, commit_message, "invalid_jira") end return success # did we find any valid tickets? end
commit_list()
click to toggle source
# File lib/ruby_git_hooks/jira_add_comment.rb, line 267 def commit_list # return the list of commits to display. We don't want to show them all # (it looks scary when there's a lot) # when there's only one, just return the commit # when more than one return first_commit..last_commit # use the shortened SHA-1 for readability return "" if !self.commits || self.commits.empty? if self.commits.size == 1 "#{self.commits.first[0..6]}" else "#{self.commits.last[0..6]}..#{self.commits.first[0..6]}" end end
get_change_list(commit)
click to toggle source
# File lib/ruby_git_hooks/jira_add_comment.rb, line 114 def get_change_list(commit) # we want changes from the previous commit, if any # ideally this list should be available from the ruby_git_hooks directly # since they go through this same process. # use --first-parent so it lists the correct files after a merge current, base = Hook.shell!("git log #{commit} --first-parent -2 --pretty=%H").split if !base # This is the initial commit so all files were added, but have to add the A ourselves files_with_status = Hook.shell!("git ls-tree --name-status -r #{commit}").split("\n") # put the A at the front files_with_status = files_with_status.map{|filename| "A\t" + filename}.join("\n") else files_with_status = Hook.shell!("git diff --name-status #{base}..#{current}") end files_with_status end
get_comment_content(commit, commit_message)
click to toggle source
# File lib/ruby_git_hooks/jira_add_comment.rb, line 139 def get_comment_content(commit, commit_message) # Needs to look like the git equivalent of this #/opt/svn/ops rev 37251 committed by john.doe (commit shah and committer) #http://viewvc.example.com/viewvc/ops?rev=37251&view=rev (github link) #BUG-3863 adding check to configs for testing (commit message and changes) # U /trunk/puppet/dist/nagios/nrpe.cfg # U /trunk/puppet/dist/nagios/ol_checks.cfg # return as a string # revision bac9b85f2 committed by Ruth Helfinstein # Fri Jul 12 13:57:28 2013 -0700 # https://github.com/ruth-helfinstein/ruth-test/commit/bac9b85f2c98ccdba8d25f0b9a6e855cd2535901 # BUG-5366 commit message # # M test.txt github_link = build_commit_uri(commit) # have to do this separately changes = get_change_list(commit) revision_and_date = Hook.shell!("git log #{commit} -1 --pretty='Revision: %h committed by %cn%nCommit date: %cd'") rescue "" branch = "Branch: #{get_commit_branch(commit)}\n" text = "#{revision_and_date}#{branch}#{github_link}\n\n#{commit_message}\n{noformat}\n#{changes}{noformat}" end
get_commit_branch(commit)
click to toggle source
# File lib/ruby_git_hooks/jira_add_comment.rb, line 131 def get_commit_branch(commit) # get the branch (list) for this commit # will usually be a single ref ([refs/heads/branch_name]). but could # theoretically be multiple if single commit is on several branches processed at the same time. refs = self.commit_ref_map[commit] refs ? refs.join(" ") : "" end
repo_remote_path()
click to toggle source
# File lib/ruby_git_hooks/jira_add_comment.rb, line 88 def repo_remote_path remote_urls = RubyGitHooks::Hook.shell!("git remote -v").split remote = remote_urls[1] # ["origin", "git@github.com:my_github_name/ruby_git_hooks.git", "fetch", ...] return "" if !remote # No remote. uri = URI.parse(remote) rescue nil if uri # "https://github.com/my_github_name/ruby_git_hooks.git " uri.to_s.sub(/.git\z/, "") else # "git@github.com:my_github_name/ruby_git_hooks.git" # ?? Can there be a "." in a repo name? path = remote[/:([\w\/.-]*)/,1] path.sub!(/.git\z/, "") if path "#{@options['protocol']}://#{@options['github']}/#{path}" end # in either case return "https://github.com/my_github_name/ruby_git_hooks" end
report_errors()
click to toggle source
# File lib/ruby_git_hooks/jira_add_comment.rb, line 301 def report_errors # report any errors we have reported require "pony" unless @options["no_send"] || @options["via"] == "no_send" # wait until we need it # NOTE: Pony breaks on Windows so don't use this option in Windows. errors_to_report.each do |email, details| desc = build_message(details["no_jira"], details["invalid_jira"]) STDERR.puts "Warnings for commit from Jira Add Comment Check:\n--" STDERR.puts "#{desc}\n--" unless @options["no_send"] || @options["via"] == "no_send" STDERR.puts "Sending warning email to #{email}" ret = Pony.mail :to => email, :from => @options["from"], :subject => @options["subject"], :body => desc, :via => @options["via"], :via_options => @options["via_options"] end end end
to_s()
click to toggle source
Do not show password when converting to string
# File lib/ruby_git_hooks/jira_add_comment.rb, line 83 def to_s "<JiraCommentAddHook:#{object_id} #{@options.merge("password" => :redacted)}>" end