git_hooks 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +20 -0
- data/README.rdoc +31 -0
- data/bin/hook-post-receive +10 -0
- data/lib/git_hooks.rb +30 -0
- data/lib/git_hooks/git_adapter.rb +68 -0
- data/lib/git_hooks/logger.rb +23 -0
- data/lib/git_hooks/notifier.rb +2 -0
- data/lib/git_hooks/notifier/jabber_client.rb +99 -0
- data/lib/git_hooks/notifier/tracker_client.rb +45 -0
- data/lib/git_hooks/post_receive_hook.rb +28 -0
- data/lib/git_hooks/utils.rb +13 -0
- data/lib/git_hooks/utils/config.rb +57 -0
- data/spec/config_spec.rb +74 -0
- data/spec/git_adapter_spec.rb +28 -0
- data/spec/git_hooks_spec.rb +22 -0
- data/spec/jabber_client_spec.rb +122 -0
- data/spec/post_receive_hook_spec.rb +37 -0
- data/spec/spec_helper.rb +28 -0
- data/spec/tracker_client_spec.rb +68 -0
- data/spec/utils_spec.rb +9 -0
- metadata +163 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Dirk Breuer
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
= git-hooks
|
2
|
+
|
3
|
+
This is a small library which allows you to easily build Git hooks. The
|
4
|
+
interaction with Git is done through the Grit library, which allows a clean
|
5
|
+
and straight forward Ruby way of talking with Git.
|
6
|
+
|
7
|
+
== Config Example
|
8
|
+
|
9
|
+
:post_receive_hooks:
|
10
|
+
- :jabber:
|
11
|
+
:jid: JABBER_USERNAME
|
12
|
+
:password: JABBER_PASSWORD
|
13
|
+
:server: JABBER_SERVER
|
14
|
+
:recipients: [ "recipient@jabber.id" ]
|
15
|
+
|
16
|
+
- :pivotal_tracker:
|
17
|
+
:api_key: API_KEY
|
18
|
+
|
19
|
+
== Note on Patches/Pull Requests
|
20
|
+
|
21
|
+
* Fork the project.
|
22
|
+
* Make your feature addition or bug fix.
|
23
|
+
* Add tests for it. This is important so I don't break it in a
|
24
|
+
future version unintentionally.
|
25
|
+
* Commit, do not mess with rakefile, version, or history.
|
26
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
27
|
+
* Send me a pull request. Bonus points for topic branches.
|
28
|
+
|
29
|
+
== Copyright
|
30
|
+
|
31
|
+
Copyright (c) 2010 Dirk Breuer. See LICENSE for details.
|
@@ -0,0 +1,10 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'git_hooks'
|
5
|
+
|
6
|
+
# will receive something like this: 034e985b8c1df2869aff99017b66600acb052617 462b4131bf6dd2fea41e3959b2b22380fd10be99 refs/heads/master
|
7
|
+
|
8
|
+
GitHooks::Logger.info "running hooks (#{File.basename(__FILE__)}) ..."
|
9
|
+
|
10
|
+
GitHooks.run_hook(:post_receive)
|
data/lib/git_hooks.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__) # For use/testing when no gem is installed
|
2
|
+
|
3
|
+
require 'active_support/core_ext/string'
|
4
|
+
|
5
|
+
require 'git_hooks/notifier'
|
6
|
+
require 'git_hooks/git_adapter'
|
7
|
+
require 'git_hooks/post_receive_hook'
|
8
|
+
require 'git_hooks/logger'
|
9
|
+
require 'git_hooks/utils'
|
10
|
+
|
11
|
+
module GitHooks
|
12
|
+
|
13
|
+
class <<self
|
14
|
+
attr_writer :config_file
|
15
|
+
|
16
|
+
def config
|
17
|
+
@config_instance ||= Utils::Config.new(config_file)
|
18
|
+
end
|
19
|
+
|
20
|
+
def config_file
|
21
|
+
@config_file || "~/.git_hooks_config"
|
22
|
+
end
|
23
|
+
|
24
|
+
def run_hook(name_of_hook, *args)
|
25
|
+
hook = "GitHooks::#{name_of_hook.to_s.camelize}Hook".constantize.new
|
26
|
+
hook.run(*args)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'grit'
|
2
|
+
|
3
|
+
module GitHooks
|
4
|
+
class GitAdapter
|
5
|
+
include Grit
|
6
|
+
|
7
|
+
class Commits
|
8
|
+
include Enumerable
|
9
|
+
|
10
|
+
attr_reader :ref_name, :repo_name
|
11
|
+
|
12
|
+
def initialize(commits, ref_name, repo)
|
13
|
+
@commits = commits
|
14
|
+
self.ref_name = ref_name
|
15
|
+
self.repo_name = repo
|
16
|
+
end
|
17
|
+
|
18
|
+
def each
|
19
|
+
@commits.each { |commit| yield commit }
|
20
|
+
end
|
21
|
+
|
22
|
+
def size
|
23
|
+
@commits.size
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def ref_name=(ref_name)
|
29
|
+
@ref_name ||= ref_name.split("/").last
|
30
|
+
end
|
31
|
+
|
32
|
+
def repo_name=(repo)
|
33
|
+
return @repo if @repo
|
34
|
+
|
35
|
+
splitted_path = repo.path.split("/")
|
36
|
+
@repo_name = if (splitted_path.last =~ /\.git/) > 0
|
37
|
+
splitted_path.last.split(".").first
|
38
|
+
else
|
39
|
+
splitted_path[-2]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
attr_reader :repo
|
46
|
+
|
47
|
+
def initialize
|
48
|
+
@repo = Repo.new(GitAdapter.find_git_root)
|
49
|
+
end
|
50
|
+
|
51
|
+
def find_commits_since_last_receive(prev_rev, current_rev, ref_name = 'master')
|
52
|
+
commits = repo.commits_between(prev_rev, current_rev)
|
53
|
+
|
54
|
+
return Commits.new(commits, ref_name, @repo)
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.find_git_root
|
58
|
+
current_dir = Dir.pwd.split('/')
|
59
|
+
while current_dir.last !~ /\.git/
|
60
|
+
current_dir.pop
|
61
|
+
break if current_dir.empty?
|
62
|
+
end
|
63
|
+
|
64
|
+
return current_dir.join('/')
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module GitHooks
|
4
|
+
class Logger
|
5
|
+
include Singleton
|
6
|
+
|
7
|
+
class <<self
|
8
|
+
def method_missing(meth, *args, &blk)
|
9
|
+
if instance.logger.respond_to? meth
|
10
|
+
instance.logger.send(meth, *args)
|
11
|
+
else
|
12
|
+
super
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_reader :logger
|
18
|
+
|
19
|
+
def initialize
|
20
|
+
@logger = ::Logger.new("/tmp/git_hooks.log")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'xmpp4r'
|
2
|
+
require 'xmpp4r/roster'
|
3
|
+
|
4
|
+
module GitHooks
|
5
|
+
module Notifier
|
6
|
+
class JabberClient
|
7
|
+
include Jabber
|
8
|
+
|
9
|
+
class Buddy
|
10
|
+
attr_reader :jid
|
11
|
+
|
12
|
+
def initialize(jid, roster_reference)
|
13
|
+
@jid = Jabber::JID.new(jid)
|
14
|
+
@roster = roster_reference
|
15
|
+
end
|
16
|
+
|
17
|
+
def subscribed?
|
18
|
+
roster_item = @roster[jid]
|
19
|
+
if roster_item
|
20
|
+
return roster_item.subscription == :both ? true : false
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def initialize(jabber_options)
|
26
|
+
@jabber_options = jabber_options
|
27
|
+
init_jabber_backend!
|
28
|
+
end
|
29
|
+
|
30
|
+
def create_recipients(recipients)
|
31
|
+
[recipients].flatten.map do |recipient|
|
32
|
+
recipient.is_a?(Buddy) ? recipient : Buddy.new(recipient, roster)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def buddies
|
37
|
+
roster.items.map { |roster_item| Buddy.new(roster_item.last.jid, roster) }
|
38
|
+
end
|
39
|
+
|
40
|
+
def roster
|
41
|
+
@roster ||= Roster::Helper.new(backend)
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.deliver(options)
|
45
|
+
commits = options.delete(:commits)
|
46
|
+
recipients = options.delete(:recipients)
|
47
|
+
|
48
|
+
client_instance = new(options)
|
49
|
+
client_instance.deliver(commits, recipients)
|
50
|
+
end
|
51
|
+
|
52
|
+
def deliver(commits, recipients)
|
53
|
+
send_message_to create_message(commits), recipients
|
54
|
+
true
|
55
|
+
end
|
56
|
+
|
57
|
+
private unless $TESTING
|
58
|
+
|
59
|
+
def init_jabber_backend!
|
60
|
+
@backend = Client.new(JID.new(@jabber_options[:jid]))
|
61
|
+
@backend.connect(@jabber_options[:server])
|
62
|
+
@backend.auth(@jabber_options[:password])
|
63
|
+
end
|
64
|
+
|
65
|
+
def backend
|
66
|
+
@backend
|
67
|
+
end
|
68
|
+
|
69
|
+
def create_message(from_commits)
|
70
|
+
message = "[#{GitHooks::Utils.hostname}] #{from_commits.size} commits have been pushed to '#{from_commits.repo_name}' on '#{from_commits.ref_name}':\n"
|
71
|
+
from_commits.each do |commit|
|
72
|
+
message << "\t#{commit.id[0...5]}...: '#{commit.short_message}' by #{commit.author.name}\n"
|
73
|
+
end
|
74
|
+
|
75
|
+
message
|
76
|
+
end
|
77
|
+
|
78
|
+
def request_authorization_of(recipient)
|
79
|
+
request = Jabber::Presence.new
|
80
|
+
request.to = recipient.respond_to?(:jid) ? recipient.jid : recipient
|
81
|
+
request.type = :subscribe
|
82
|
+
backend.send request
|
83
|
+
end
|
84
|
+
|
85
|
+
def send_message_to(message, recipients)
|
86
|
+
create_recipients(recipients).each do |recipient|
|
87
|
+
subject = "Git commit notification"
|
88
|
+
|
89
|
+
request_authorization_of(recipient) unless recipient.subscribed?
|
90
|
+
|
91
|
+
msg = Message::new(recipient.jid, message).set_type(:normal).set_id('1').set_subject(subject)
|
92
|
+
GitHooks::Logger.debug "msg: #{msg}"
|
93
|
+
backend.send msg
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'curb'
|
2
|
+
|
3
|
+
module GitHooks
|
4
|
+
module Notifier
|
5
|
+
class TrackerClient
|
6
|
+
|
7
|
+
attr_reader :curl
|
8
|
+
|
9
|
+
def self.deliver(options)
|
10
|
+
commits = options.delete(:commits)
|
11
|
+
|
12
|
+
client_instance = new(options)
|
13
|
+
client_instance.deliver(commits)
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(tracker_options)
|
17
|
+
@curl = Curl::Easy.new("http://www.pivotaltracker.com/services/v3/source_commits") do |curl|
|
18
|
+
curl.headers["X-TrackerToken"] = tracker_options[:api_key]
|
19
|
+
curl.headers["Content-type"] = "application/xml"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def deliver(commits)
|
24
|
+
create_payloads(commits) do |payload|
|
25
|
+
curl.http_post(payload)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def create_payloads(commits, &block)
|
30
|
+
payloads = commits.map do |commit|
|
31
|
+
<<-XML
|
32
|
+
<source_commit>
|
33
|
+
<message>#{commit.message}</message>
|
34
|
+
<author>#{commit.author.name}</author>
|
35
|
+
<commit_id>#{commit.id}</commit_id>
|
36
|
+
</source_commit>
|
37
|
+
XML
|
38
|
+
end
|
39
|
+
|
40
|
+
payloads.each(&block)
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module GitHooks
|
2
|
+
class PostReceiveHook
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@git_adapter = GitAdapter.new
|
6
|
+
end
|
7
|
+
|
8
|
+
def run(*args)
|
9
|
+
arguments = read_arguments_from_stdin
|
10
|
+
commits = @git_adapter.find_commits_since_last_receive(*arguments)
|
11
|
+
|
12
|
+
GitHooks.config.post_receive_hooks.each do |hook|
|
13
|
+
hook.hook_class.deliver(hook.options.merge(:commits => commits))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def read_arguments_from_stdin
|
18
|
+
arguments = []
|
19
|
+
|
20
|
+
while arguments << STDIN.gets
|
21
|
+
break if arguments.last.nil?
|
22
|
+
end
|
23
|
+
|
24
|
+
arguments.compact.first.split(" ")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module GitHooks
|
4
|
+
module Utils
|
5
|
+
|
6
|
+
class Config
|
7
|
+
|
8
|
+
class HookWrapper
|
9
|
+
|
10
|
+
attr_reader :options
|
11
|
+
|
12
|
+
def initialize(options)
|
13
|
+
@hook_class_name = options.keys.first
|
14
|
+
@options = options.values.first
|
15
|
+
end
|
16
|
+
|
17
|
+
def hook_class
|
18
|
+
@hook_class ||= "GitHooks::Notifier::#{@hook_class_name.to_s.camelize}Client".constantize
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
attr_reader :config
|
24
|
+
|
25
|
+
def initialize(config_file)
|
26
|
+
@config = if config_file.respond_to?(:read)
|
27
|
+
YAML.load(config_file.read)
|
28
|
+
else
|
29
|
+
YAML.load_file(File.expand_path(config_file))
|
30
|
+
end
|
31
|
+
rescue Errno::ENOENT
|
32
|
+
GitHooks::Logger.error("Config File '#{config_file}' couldn't be loaded!")
|
33
|
+
raise "Config File '#{config_file}' couldn't be loaded!"
|
34
|
+
end
|
35
|
+
|
36
|
+
def method_missing(hook_name, *args, &blk)
|
37
|
+
if hook_definitions = config[hook_name]
|
38
|
+
|
39
|
+
hooks = hook_definitions.map { |hook_definition| HookWrapper.new(hook_definition) }
|
40
|
+
instance_variable_set("@#{hook_name}", hooks)
|
41
|
+
|
42
|
+
instance_eval <<-RUBY
|
43
|
+
def #{hook_name}
|
44
|
+
@#{hook_name}
|
45
|
+
end
|
46
|
+
RUBY
|
47
|
+
|
48
|
+
send(hook_name)
|
49
|
+
else
|
50
|
+
super
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
data/spec/config_spec.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "Utils" do
|
4
|
+
|
5
|
+
describe "Config" do
|
6
|
+
|
7
|
+
it "should have read from a config file located in the home directory" do
|
8
|
+
File.should_receive(:expand_path).with("~/.git_hooks_config").and_return(path_to_config = "/Users/dbreuer/.git_hooks_config")
|
9
|
+
YAML.should_receive(:load_file).with(path_to_config).and_return({:post_receive_hooks => [{:jabber => {:jid => "jabber@example.com", :password => "password"}}]})
|
10
|
+
|
11
|
+
config_instance = GitHooks::Utils::Config.new("~/.git_hooks_config")
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should alternatively init the config from a YAML StringIO" do
|
15
|
+
config_yaml = StringIO.new <<-YAML
|
16
|
+
:post_receive_hooks:
|
17
|
+
- :jabber:
|
18
|
+
:jid: JABBER_USERNAME
|
19
|
+
:password: JABBER_PASSWORD
|
20
|
+
:server: JABBER_SERVER
|
21
|
+
:recipients:
|
22
|
+
:group: [ "recipient@jabber.id" ]
|
23
|
+
|
24
|
+
- :pivotal_tracker:
|
25
|
+
:api_key: API_KEY
|
26
|
+
YAML
|
27
|
+
|
28
|
+
config_instance = GitHooks::Utils::Config.new(config_yaml)
|
29
|
+
config_instance.config.should be_a_kind_of(Hash)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should return all available hooks as an array of hook wrapper classes" do
|
33
|
+
GitHooks.config.post_receive_hooks.each do |hook|
|
34
|
+
hook.should be_a_kind_of(GitHooks::Utils::Config::HookWrapper)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "HookWrapper" do
|
39
|
+
|
40
|
+
before(:each) do
|
41
|
+
hook_options = {
|
42
|
+
:jabber => {
|
43
|
+
:jid => "jabber@example.com",
|
44
|
+
:password => "password",
|
45
|
+
:recipients => [
|
46
|
+
"bender.rodriguez@planetexpress.com"
|
47
|
+
]
|
48
|
+
}
|
49
|
+
}
|
50
|
+
|
51
|
+
@hook_wrapper = GitHooks::Utils::Config::HookWrapper.new(hook_options)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should know its backing class" do
|
55
|
+
@hook_wrapper.hook_class.should == GitHooks::Notifier::JabberClient
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should know the options for this hook" do
|
59
|
+
expected_options = {
|
60
|
+
:jid => "jabber@example.com",
|
61
|
+
:password => "password",
|
62
|
+
:recipients => [
|
63
|
+
"bender.rodriguez@planetexpress.com"
|
64
|
+
]
|
65
|
+
}
|
66
|
+
|
67
|
+
@hook_wrapper.options.should == expected_options
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "GitAdapter" do
|
4
|
+
it "should initialize with a Grit repository" do
|
5
|
+
GitHooks::GitAdapter.should_receive(:find_git_root)
|
6
|
+
Grit::Repo.should_receive(:new)
|
7
|
+
|
8
|
+
git_adapter = GitHooks::GitAdapter.new
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should find the Git root directory based on the current directory" do
|
12
|
+
git_adapter = GitHooks::GitAdapter.new
|
13
|
+
commits = git_adapter.find_commits_since_last_receive("7eb08614", "58c3455c")
|
14
|
+
commits.size.should be(2)
|
15
|
+
commits.ref_name.should == "master"
|
16
|
+
commits.repo_name.should =~ /(git_hooks|workspace)/
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should find commits since last commit" do
|
20
|
+
Dir.should_receive(:pwd).and_return("/srv/example.com/git/repositories/git_hooks.git/hooks")
|
21
|
+
git_root = GitHooks::GitAdapter.find_git_root
|
22
|
+
git_root.should == "/srv/example.com/git/repositories/git_hooks.git"
|
23
|
+
|
24
|
+
Dir.should_receive(:pwd).and_return("/home/dbreuer/projects/git_hooks/.git/hooks")
|
25
|
+
git_root = GitHooks::GitAdapter.find_git_root
|
26
|
+
git_root.should == "/home/dbreuer/projects/git_hooks/.git"
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "GitHooks" do
|
4
|
+
|
5
|
+
it "should run a hook identified by a symbol" do
|
6
|
+
post_receive_hook_mock = mock("PostReceiveHook")
|
7
|
+
post_receive_hook_mock.should_receive(:run)
|
8
|
+
GitHooks::PostReceiveHook.should_receive(:new).and_return(post_receive_hook_mock)
|
9
|
+
|
10
|
+
GitHooks.run_hook(:post_receive)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should provide access to a config instance" do
|
14
|
+
GitHooks.config.should be_a_kind_of(GitHooks::Utils::Config)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should provide a setter for the config file path" do
|
18
|
+
GitHooks.config_file = "/path/to/config.yml"
|
19
|
+
GitHooks.config_file.should == "/path/to/config.yml"
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "JabberClient" do
|
4
|
+
|
5
|
+
describe "Buddy" do
|
6
|
+
|
7
|
+
it "should have a JID and a roster reference" do
|
8
|
+
buddy = GitHooks::Notifier::JabberClient::Buddy.new("lela.starr@jabber.org", mock("RosterMock"))
|
9
|
+
buddy.jid.should be_a_kind_of(Jabber::JID)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should should know if already subscribed" do
|
13
|
+
roster_mock = mock("RosterMock")
|
14
|
+
|
15
|
+
roster_mock.should_receive(:[]).with(Jabber::JID.new("lela.starr@jabber.org")).and_return(mock("RosterItemMock", :subscription => :both))
|
16
|
+
buddy = GitHooks::Notifier::JabberClient::Buddy.new("lela.starr@jabber.org", roster_mock)
|
17
|
+
buddy.subscribed?.should be(true)
|
18
|
+
|
19
|
+
roster_mock.should_receive(:[]).with(Jabber::JID.new("lela.starr@jabber.org")).and_return(mock("RosterItemMock", :subscription => :none))
|
20
|
+
buddy = GitHooks::Notifier::JabberClient::Buddy.new("lela.starr@jabber.org", roster_mock)
|
21
|
+
buddy.subscribed?.should be(false)
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
before(:each) do
|
27
|
+
@jabber_client_opts = GitHooks.config.post_receive_hooks.first.options
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should initialize with a XMPP client" do
|
31
|
+
Jabber::JID.should_receive(:new).and_return(jid_mock = mock("JIDMock"))
|
32
|
+
Jabber::Client.should_receive(:new).with(jid_mock).and_return(client_mock = mock("ClientMock"))
|
33
|
+
client_mock.should_receive(:connect).with("JABBER_SERVER")
|
34
|
+
client_mock.should_receive(:auth)
|
35
|
+
|
36
|
+
jabber_client = GitHooks::Notifier::JabberClient.new(@jabber_client_opts)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should transform a collection of Jabber IDs to Buddy objects" do
|
40
|
+
GitHooks::Notifier::JabberClient.any_instance.stubs(:init_jabber_backend!)
|
41
|
+
jabber_client = GitHooks::Notifier::JabberClient.new(@jabber_client_opts)
|
42
|
+
jabber_client.should_receive(:roster)
|
43
|
+
|
44
|
+
|
45
|
+
jabber_client.create_recipients(["bender.rodriguez@planetexpress.com"]).each do |buddy|
|
46
|
+
buddy.should be_a_kind_of(GitHooks::Notifier::JabberClient::Buddy)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should not transform recipients that are already Buddy objects" do
|
51
|
+
GitHooks::Notifier::JabberClient.any_instance.stubs(:init_jabber_backend!)
|
52
|
+
jabber_client = GitHooks::Notifier::JabberClient.new(@jabber_client_opts)
|
53
|
+
jabber_client.should_receive(:roster)
|
54
|
+
|
55
|
+
buddy = GitHooks::Notifier::JabberClient::Buddy.new("fry@planetexpress.com", nil)
|
56
|
+
|
57
|
+
jabber_client.create_recipients(["bender.rodriguez@planetexpress.com", buddy]).each do |buddy|
|
58
|
+
buddy.should be_a_kind_of(GitHooks::Notifier::JabberClient::Buddy)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should have a list of buddies" do
|
63
|
+
GitHooks::Notifier::JabberClient.any_instance.stubs(:init_jabber_backend!)
|
64
|
+
jabber_client = GitHooks::Notifier::JabberClient.new(@jabber_client_opts)
|
65
|
+
jabber_client.should_receive(:roster).
|
66
|
+
at_least(2).times.
|
67
|
+
and_return(roster_mock = mock("RosterMock"))
|
68
|
+
|
69
|
+
GitHooks::Notifier::JabberClient::Buddy.should_receive(:new).
|
70
|
+
with("lela.starr@jabber.org", roster_mock).
|
71
|
+
and_return(lela_starr = mock("BuddyMock"))
|
72
|
+
|
73
|
+
roster_mock.should_receive(:items).
|
74
|
+
and_return({:jabber_internal => mock("RosterItem", :jid => "lela.starr@jabber.org")})
|
75
|
+
|
76
|
+
jabber_client.buddies.should == [lela_starr]
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should create a message out of a bunch of commits" do
|
80
|
+
GitHooks::Notifier::JabberClient.any_instance.stubs(:init_jabber_backend!)
|
81
|
+
jabber_client = GitHooks::Notifier::JabberClient.new(@jabber_client_opts)
|
82
|
+
|
83
|
+
commit = mock("CommitMock")
|
84
|
+
commit.should_receive(:id).and_return("c1be3c82cafc755754ee2247ec8dae1e6a64857f")
|
85
|
+
commit.should_receive(:short_message).and_return("This was a simple test commit.")
|
86
|
+
commit.should_receive(:author).and_return(mock("Author", :name => "Dirk Breuer"))
|
87
|
+
|
88
|
+
commits = mock("CommitsMock")
|
89
|
+
commits.should_receive(:ref_name).and_return("master")
|
90
|
+
commits.should_receive(:repo_name).and_return("git_hooks")
|
91
|
+
commits.should_receive(:each).and_yield(commit)
|
92
|
+
commits.should_receive(:size).and_return(1)
|
93
|
+
|
94
|
+
jabber_client.create_message(commits)
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should request a recipient for authorization if she is not a subscribed buddy" do
|
98
|
+
GitHooks::Notifier::JabberClient.any_instance.stubs(:init_jabber_backend!)
|
99
|
+
jabber_client = GitHooks::Notifier::JabberClient.new(@jabber_client_opts)
|
100
|
+
jabber_client.should_receive(:backend).and_return(mock("JabberBackend", :send => true))
|
101
|
+
|
102
|
+
jabber_client.should_receive(:roster).and_return(roster_mock = mock("RosterMock"))
|
103
|
+
|
104
|
+
GitHooks::Notifier::JabberClient::Buddy.should_receive(:new).
|
105
|
+
with("lela.starr@jabber.org", roster_mock).
|
106
|
+
and_return(buddy = mock("BuddyMock", :subscribed? => false, :jid => "lela.starr@jabber.org"))
|
107
|
+
|
108
|
+
jabber_client.should_receive(:request_authorization_of).with(buddy)
|
109
|
+
|
110
|
+
jabber_client.send_message_to "My testing message", "lela.starr@jabber.org"
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should send the notification based on the given options" do
|
114
|
+
GitHooks::Notifier::JabberClient.any_instance.stubs(:init_jabber_backend!)
|
115
|
+
jabber_client = GitHooks::Notifier::JabberClient.new(@jabber_client_opts)
|
116
|
+
commits = [mock("Commit")]
|
117
|
+
jabber_client.should_receive(:create_message).with(commits).and_return(message = "Message")
|
118
|
+
jabber_client.should_receive(:send_message_to).with(message, "lela.starr@jabber.org")
|
119
|
+
jabber_client.deliver(commits, "lela.starr@jabber.org")
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "PostReceiveHook" do
|
4
|
+
|
5
|
+
it "should should read arguments given by Git from stdin" do
|
6
|
+
STDIN.expects(:gets).times(2).returns("old_sha new_sha refs/head/master\n").then.returns(nil)
|
7
|
+
|
8
|
+
post_receive_hook = GitHooks::PostReceiveHook.new
|
9
|
+
arguments = post_receive_hook.read_arguments_from_stdin
|
10
|
+
arguments.should == ["old_sha", "new_sha", "refs/head/master"]
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should promote the received commits to all registered post_receive hooks" do
|
14
|
+
post_receive_hook = GitHooks::PostReceiveHook.new
|
15
|
+
|
16
|
+
post_receive_hook.should_receive(:read_arguments_from_stdin).
|
17
|
+
and_return(["old_sha", "new_sha", "refs/head/master"])
|
18
|
+
|
19
|
+
GitHooks::GitAdapter.any_instance.
|
20
|
+
expects(:find_commits_since_last_receive).
|
21
|
+
with("old_sha", "new_sha", "refs/head/master").
|
22
|
+
returns(commits = [mock("Commit")])
|
23
|
+
|
24
|
+
jabber_hook = mock("HookMock")
|
25
|
+
jabber_hook.should_receive(:hook_class).and_return(GitHooks::Notifier::JabberClient)
|
26
|
+
jabber_hook.should_receive(:options).and_return({:other_jabber_option => "Option"})
|
27
|
+
|
28
|
+
post_receive_hooks = [jabber_hook]
|
29
|
+
|
30
|
+
GitHooks.config.should_receive(:post_receive_hooks).and_return(post_receive_hooks)
|
31
|
+
|
32
|
+
GitHooks::Notifier::JabberClient.should_receive(:deliver).with({:other_jabber_option => "Option", :commits => commits})
|
33
|
+
|
34
|
+
post_receive_hook.run
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'spec'
|
3
|
+
require 'spec/autorun'
|
4
|
+
require 'mocha'
|
5
|
+
|
6
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
7
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
8
|
+
|
9
|
+
$TESTING = true
|
10
|
+
|
11
|
+
require 'git_hooks'
|
12
|
+
|
13
|
+
# init the config class with testing config
|
14
|
+
config_yaml = StringIO.new <<-YAML
|
15
|
+
:post_receive_hooks:
|
16
|
+
- :jabber:
|
17
|
+
:jid: JABBER_USERNAME
|
18
|
+
:password: JABBER_PASSWORD
|
19
|
+
:server: JABBER_SERVER
|
20
|
+
:recipients: [ "recipient@jabber.id" ]
|
21
|
+
|
22
|
+
- :pivotal_tracker:
|
23
|
+
:api_key: API_KEY
|
24
|
+
YAML
|
25
|
+
GitHooks.config_file = config_yaml
|
26
|
+
|
27
|
+
Spec::Runner.configure do |config|
|
28
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "TrackerClient" do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@tracker_options = { :api_key => "MY_API_KEY" }
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should create a pivotal tracker ready payload for each passed commit" do
|
10
|
+
commit = mock("CommitMock")
|
11
|
+
commit.should_receive(:id).and_return("SHA_ID")
|
12
|
+
commit.should_receive(:message).and_return("[#1234] Commit Message")
|
13
|
+
commit.should_receive(:author).and_return(mock("AuthorMock", :name => "Seras Victoria"))
|
14
|
+
|
15
|
+
expected_payload = <<-XML
|
16
|
+
<source_commit>
|
17
|
+
<message>[#1234] Commit Message</message>
|
18
|
+
<author>Seras Victoria</author>
|
19
|
+
<commit_id>SHA_ID</commit_id>
|
20
|
+
</source_commit>
|
21
|
+
XML
|
22
|
+
|
23
|
+
client = GitHooks::Notifier::TrackerClient.new(@tracker_options)
|
24
|
+
client.create_payloads([commit]) do |payload|
|
25
|
+
payload.should == expected_payload
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should send commit messages to pivotal tracker" do
|
30
|
+
commits = [mock("CommitMock")]
|
31
|
+
payload = "some test payload"
|
32
|
+
curl = mock("CurlMock")
|
33
|
+
curl.should_receive(:http_post).with(payload)
|
34
|
+
|
35
|
+
client = GitHooks::Notifier::TrackerClient.new(@tracker_options)
|
36
|
+
client.should_receive(:create_payloads).with(commits).and_yield(payload)
|
37
|
+
client.should_receive(:curl).and_return(curl)
|
38
|
+
|
39
|
+
client.deliver(commits)
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should initialize client with a curb client ready to post to pivotal tracker" do
|
43
|
+
curb = mock("CurbMock")
|
44
|
+
headers = {}
|
45
|
+
curb.should_receive(:headers).twice.and_return(headers)
|
46
|
+
|
47
|
+
Curl::Easy.should_receive(:new).with("http://www.pivotaltracker.com/services/v3/source_commits").and_yield(curb)
|
48
|
+
|
49
|
+
client = GitHooks::Notifier::TrackerClient.new(@tracker_options)
|
50
|
+
|
51
|
+
headers["X-TrackerToken"].should == @tracker_options[:api_key]
|
52
|
+
headers["Content-type"].should == "application/xml"
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should provide class level deliver methods" do
|
56
|
+
deliver_options = {
|
57
|
+
:commits => [mock("CommitMock")],
|
58
|
+
:api_key => "MY_API_KEY"
|
59
|
+
}
|
60
|
+
|
61
|
+
client = mock("TrackerClientMock")
|
62
|
+
client.should_receive(:deliver).with(deliver_options[:commits])
|
63
|
+
GitHooks::Notifier::TrackerClient.should_receive(:new).with({:api_key => "MY_API_KEY"}).and_return(client)
|
64
|
+
|
65
|
+
GitHooks::Notifier::TrackerClient.deliver(deliver_options)
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
data/spec/utils_spec.rb
ADDED
metadata
ADDED
@@ -0,0 +1,163 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: git_hooks
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 2
|
8
|
+
- 0
|
9
|
+
version: 0.2.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Dirk Breuer
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-05-10 00:00:00 +02:00
|
18
|
+
default_executable: hook-post-receive
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: grit
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 2
|
29
|
+
- 0
|
30
|
+
- 0
|
31
|
+
version: 2.0.0
|
32
|
+
type: :runtime
|
33
|
+
version_requirements: *id001
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: xmpp4r
|
36
|
+
prerelease: false
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
segments:
|
42
|
+
- 0
|
43
|
+
- 5
|
44
|
+
version: "0.5"
|
45
|
+
type: :runtime
|
46
|
+
version_requirements: *id002
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: curb
|
49
|
+
prerelease: false
|
50
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
segments:
|
55
|
+
- 0
|
56
|
+
- 7
|
57
|
+
- 1
|
58
|
+
version: 0.7.1
|
59
|
+
type: :runtime
|
60
|
+
version_requirements: *id003
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: activesupport
|
63
|
+
prerelease: false
|
64
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
segments:
|
69
|
+
- 3
|
70
|
+
- 0
|
71
|
+
- 0
|
72
|
+
- beta
|
73
|
+
version: 3.0.0.beta
|
74
|
+
type: :runtime
|
75
|
+
version_requirements: *id004
|
76
|
+
- !ruby/object:Gem::Dependency
|
77
|
+
name: rspec
|
78
|
+
prerelease: false
|
79
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
segments:
|
84
|
+
- 1
|
85
|
+
- 2
|
86
|
+
- 9
|
87
|
+
version: 1.2.9
|
88
|
+
type: :development
|
89
|
+
version_requirements: *id005
|
90
|
+
- !ruby/object:Gem::Dependency
|
91
|
+
name: mocha
|
92
|
+
prerelease: false
|
93
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
segments:
|
98
|
+
- 0
|
99
|
+
- 9
|
100
|
+
- 8
|
101
|
+
version: 0.9.8
|
102
|
+
type: :development
|
103
|
+
version_requirements: *id006
|
104
|
+
description: The goal is to provide a pluggable hook infrastructure, where you can easily use different hooks for different purposes.
|
105
|
+
email: dirk.breuer@gmail.com
|
106
|
+
executables:
|
107
|
+
- hook-post-receive
|
108
|
+
extensions: []
|
109
|
+
|
110
|
+
extra_rdoc_files:
|
111
|
+
- LICENSE
|
112
|
+
- README.rdoc
|
113
|
+
files:
|
114
|
+
- README.rdoc
|
115
|
+
- lib/git_hooks.rb
|
116
|
+
- lib/git_hooks/git_adapter.rb
|
117
|
+
- lib/git_hooks/logger.rb
|
118
|
+
- lib/git_hooks/notifier.rb
|
119
|
+
- lib/git_hooks/notifier/jabber_client.rb
|
120
|
+
- lib/git_hooks/notifier/tracker_client.rb
|
121
|
+
- lib/git_hooks/post_receive_hook.rb
|
122
|
+
- lib/git_hooks/utils.rb
|
123
|
+
- lib/git_hooks/utils/config.rb
|
124
|
+
- LICENSE
|
125
|
+
has_rdoc: true
|
126
|
+
homepage: http://github.com/railsbros/git-hooks
|
127
|
+
licenses: []
|
128
|
+
|
129
|
+
post_install_message:
|
130
|
+
rdoc_options:
|
131
|
+
- --charset=UTF-8
|
132
|
+
require_paths:
|
133
|
+
- lib
|
134
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
segments:
|
139
|
+
- 0
|
140
|
+
version: "0"
|
141
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
segments:
|
146
|
+
- 0
|
147
|
+
version: "0"
|
148
|
+
requirements: []
|
149
|
+
|
150
|
+
rubyforge_project:
|
151
|
+
rubygems_version: 1.3.6
|
152
|
+
signing_key:
|
153
|
+
specification_version: 3
|
154
|
+
summary: A small Gem to provide various Git-Hooks based on Grit.
|
155
|
+
test_files:
|
156
|
+
- spec/config_spec.rb
|
157
|
+
- spec/git_adapter_spec.rb
|
158
|
+
- spec/git_hooks_spec.rb
|
159
|
+
- spec/jabber_client_spec.rb
|
160
|
+
- spec/post_receive_hook_spec.rb
|
161
|
+
- spec/spec_helper.rb
|
162
|
+
- spec/tracker_client_spec.rb
|
163
|
+
- spec/utils_spec.rb
|