我已經在Assembla上安裝了'ticket_status.rb'服務器端鉤子。雖然這正是我所期望的(理論上),但它在開發人員嘗試推送到服務器之前不會標記。如果他們在推送前進行了多次提交,那麼回顧其歷史記錄並編輯任何無效的提交消息變得令人難以置信的令人沮喪。在創建Git客戶端'commit-msg'鉤子時需要幫助
我正在創建一個客戶端鉤子,如果Assembla中的打開票未在提交消息中引用,它將拒絕開發者的提交。我假設,因爲它是客戶端,它將無法檢查票是否在Assembla項目空間中打開。但是,如果鉤子至少可以檢查'#n'是否已經包含在提交消息中(其中0 < n < 10,000),它應該捕獲大多數無效的提交消息。
GitHub爲客戶端'commit-msg'鉤子提供了示例代碼。我想協助修改下面的代碼,改爲搜索提交信息的准考證號(#N)(或Assembla項目空間的開放式票,如果可能的話):
#!/bin/sh
#
# An example hook script to check the commit log message.
# Called by "git commit" with one argument, the name of the file
# that has the commit message. The hook should exit with non-zero
# status after issuing an appropriate message if it wants to stop the
# commit. The hook is allowed to edit the commit message file.
#
# To enable this hook, rename this file to "commit-msg".
# Uncomment the below to add a Signed-off-by line to the message.
# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
# hook is more suited to it.
#
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
# This example catches duplicate Signed-off-by lines.
test "" = "$(grep '^Signed-off-by: ' "$1" |
sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || {
echo >&2 Duplicate Signed-off-by lines.
exit 1
}
我還提供爲服務器側鉤排斥提交,如果它不包含在提交消息(ticket_status.rb)有效的打開票號的源代碼:
#!/usr/bin/env ruby
# -*- encoding : utf-8 -*-
#
# Reject a push to a branch if it has commits that do refer a ticket in open state
#
# ref = ARGV[0]
sha_start = ARGV[1]
sha_end = ARGV[2]
# HOOK PARAMS
space = 'space-wiki-name'
api_key = 'user-api-key'
api_secret = 'user-api-secret'
# HOOK START, end of params block
require "net/https"
require "uri"
begin
require "json"
rescue LoadError
require 'rubygems'
require 'json'
end
# Check referred tickets that are in open stage
class TicketValidator
API_URL = "https://api.assembla.com"
attr_accessor :space, :api_key, :api_secret
def initialize()
@ticket_statuses = []
@tickets = {}
end
def init
init_http
load_statuses
end
def check(sha, comment)
comment.to_s.scan(/#\d+/).each do |t|
ticket = t.tr('#', '')
# Do not check it twice
next if @tickets[ticket]
ticket_js = api_call "/v1/spaces/#{space}/tickets/#{ticket}.json"
error = nil
if ticket_js['error'].nil?
unless @ticket_statuses.include? ticket_js['status'].downcase
error = "Ticket #{t} is not open!"
end
else
error = ticket_js['error']
end
if error
@tickets[ticket] = {:error => error, :sha => sha}
else
@tickets[ticket] = :ok
end
end
end
def load_statuses
statuses = api_call "/v1/spaces/#{space}/tickets/statuses.json"
statuses.each do |status|
if status["state"] == 1 # open
@ticket_statuses << status["name"].downcase
end
end
end
def api_call(uri)
request = Net::HTTP::Get.new(uri,
{'Content-Type' => 'application/json',
'X-Api-Key' => api_key,
'X-Api-Secret' => api_secret})
result = @http.request(request)
JSON.parse(result.body)
end
def init_http
uri = URI.parse(API_URL)
@http = Net::HTTP.new(uri.host, uri.port)
@http.use_ssl = true
@http.verify_mode = OpenSSL::SSL::VERIFY_NONE
end
def show_decision!
@tickets.reject! {|_, value| value == :ok }
unless @tickets.empty?
puts "You have references to tickets in closed state"
@tickets.each do |ticket, details|
puts "\t#{details[:sha]} - ##{ticket} #{details[:error]}"
end
puts "Valid statuses: #{@ticket_statuses.join(', ')}"
exit 1
end
end
end
class Parser
def initialize(text, validator)
@text = text
@validator = validator
end
def parse
commit = nil
comment = nil
@validator.init
@text.to_s.split("\n").each do |line|
if line =~ /^commit: ([a-z0-9]+)$/i
new_commit = $1
if comment
@validator.check(commit, comment)
comment = nil
end
commit = new_commit
else
comment = comment.to_s + line + "\n"
end
end
# Check last commit
@validator.check(commit, comment) if comment
end
end
text = `git log --pretty='format:commit: %h%n%B' #{sha_start}..#{sha_end}`
@validator = TicketValidator.new
@validator.space = space
@validator.api_key = api_key
@validator.api_secret = api_secret
Parser.new(text, @validator).parse
@validator.show_decision!
任何幫助十分讚賞。謝謝