rgithook 3.0.2
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.tar.gz.sig +0 -0
- data/CHANGELOG +3 -0
- data/Manifest +42 -0
- data/README.rdoc +12 -0
- data/Rakefile +22 -0
- data/TODO.txt +4 -0
- data/bin/rgithook +13 -0
- data/lib/plugins/custom.rb +18 -0
- data/lib/plugins/db.rb +34 -0
- data/lib/plugins/email.rb +39 -0
- data/lib/plugins/html.rb +53 -0
- data/lib/plugins/html/commit.html.erb +26 -0
- data/lib/plugins/html/diff.html.erb +16 -0
- data/lib/plugins/rake.rb +14 -0
- data/lib/plugins/spec/rgithook_formatter.rb +74 -0
- data/lib/plugins/spec/spec_result.rb +5 -0
- data/lib/plugins/temp.rb +41 -0
- data/lib/plugins/test.rb +37 -0
- data/lib/plugins/twitter.rb +13 -0
- data/lib/rgithook.rb +36 -0
- data/lib/rgithook/command_line.rb +47 -0
- data/lib/rgithook/hook.rb +39 -0
- data/lib/rgithook/plugin.rb +105 -0
- data/lib/rgithook/rgithook.rb +229 -0
- data/lib/rgithook/runner.rb +178 -0
- data/lib/rgithook/templates/hook.rb +6 -0
- data/lib/rgithook/templates/rgithook.rb +18 -0
- data/lib/rgithook/test/unit.rb +70 -0
- data/rgithook.gemspec +42 -0
- data/test/fixtures/sample_plugin.rb +28 -0
- data/test/fixtures/sample_repo.zip +0 -0
- data/test/integration/test_install.rb +68 -0
- data/test/integration/test_pull_and_push.rb +20 -0
- data/test/plugins/test_email.rb +8 -0
- data/test/plugins/test_html.rb +6 -0
- data/test/plugins/test_spec.rb +6 -0
- data/test/plugins/test_test.rb +14 -0
- data/test/test_helper.rb +12 -0
- data/test/unit/test_command_line.rb +59 -0
- data/test/unit/test_hook.rb +31 -0
- data/test/unit/test_plugin.rb +36 -0
- data/test/unit/test_rgithook.rb +143 -0
- data/test/unit/test_runner.rb +95 -0
- metadata +174 -0
- metadata.gz.sig +2 -0
data/lib/plugins/test.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
module RGitHook
|
2
|
+
class TestSuite < Plugin
|
3
|
+
|
4
|
+
module RunnerMethods
|
5
|
+
def test(commit)
|
6
|
+
commit.properties['testing'] = true
|
7
|
+
commit.save_properties
|
8
|
+
in_temp_commit(commit) do |new_repo|
|
9
|
+
# Some hacks to migrate rails app if found.
|
10
|
+
if File.file?('./config/environment.rb')
|
11
|
+
commit.properties['db:migrate'] = rake('db:migrate')
|
12
|
+
commit.properties['db:test:prepare'] = rake('db:test:prepare')
|
13
|
+
end
|
14
|
+
commit.properties['spec'] = test_spec(repo) if File.directory? File.join(repo.working_dir,'spec')
|
15
|
+
commit.properties['cucumber'] = test_cucumber(repo) if File.directory? File.join(repo.working_dir,'features')
|
16
|
+
commit.properties['test_unit'] = test_unit(repo) if File.directory? File.join(repo.working_dir,'test')
|
17
|
+
end
|
18
|
+
commit.properties["status"] = %w(spec cucumber test_unit).map{|t|commit.properties[t][1].exitstatus}.max
|
19
|
+
ensure
|
20
|
+
commit.properties.delete 'testing'
|
21
|
+
commit.save_properties
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_spec(repo)
|
25
|
+
[%x(spec spec/),$?]
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_cucumber(repo)
|
29
|
+
[%x(cucumber features/),$?]
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_unit(repo)
|
33
|
+
[%x(testrb `find test -name '*.rb'`),$?]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/rgithook.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__)
|
2
|
+
|
3
|
+
begin
|
4
|
+
|
5
|
+
module RGitHook
|
6
|
+
VERSION='3.0.2'
|
7
|
+
PATH=File.dirname(File.expand_path(__FILE__))
|
8
|
+
end
|
9
|
+
|
10
|
+
require 'rubygems'
|
11
|
+
gem 'mojombo-grit'
|
12
|
+
require 'grit'
|
13
|
+
|
14
|
+
require File.join('rgithook', 'runner')
|
15
|
+
|
16
|
+
require File.join('rgithook', 'rgithook')
|
17
|
+
require File.join('rgithook', 'hook')
|
18
|
+
RGitHook.autoload(:Plugin, File.join(RGitHook::PATH,'rgithook','plugin'))
|
19
|
+
RGitHook.autoload(:CommandLine, File.join(RGitHook::PATH,'rgithook','command_line'))
|
20
|
+
|
21
|
+
Dir.glob(File.join(File.dirname(__FILE__),'plugins','*.rb')).each do |plugin|
|
22
|
+
begin
|
23
|
+
require plugin
|
24
|
+
rescue LoadError => e
|
25
|
+
puts "Failed to load some plugin #{plugin}\n#{e.to_s}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
rescue LoadError => e
|
31
|
+
puts 'Imposible to load some gem'
|
32
|
+
puts e.message
|
33
|
+
exit -1
|
34
|
+
end
|
35
|
+
|
36
|
+
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'ostruct'
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
module RGitHook
|
6
|
+
class CommandLine
|
7
|
+
|
8
|
+
# Parse command line options and execute
|
9
|
+
def self.execute(args)
|
10
|
+
options = parse_options(args)
|
11
|
+
|
12
|
+
case options.command
|
13
|
+
when :install,:fetch,:edit
|
14
|
+
ret_val = RGitHook.new(options.path).send(options.command)
|
15
|
+
exit 0
|
16
|
+
when :version
|
17
|
+
puts 'Version 3.0.0'
|
18
|
+
exit 0
|
19
|
+
end
|
20
|
+
|
21
|
+
rescue Grit::InvalidGitRepositoryError
|
22
|
+
puts "Invalid Git repository:\n#{@options.path}"
|
23
|
+
exit 1
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
def self.parse_options(args)
|
28
|
+
options = OpenStruct.new
|
29
|
+
options.command = :help
|
30
|
+
options.path = Dir.pwd
|
31
|
+
|
32
|
+
opts = OptionParser.new do |opts|
|
33
|
+
opts.banner = "Usage #{File.basename $0} [options]"
|
34
|
+
opts.on_head("-i","--install", "Install hooks on current dir") { options.command = :install }
|
35
|
+
opts.on_head("-f","--fetch", "Fetch remote origin and run hooks") { options.command = :fetch }
|
36
|
+
opts.on_head("-e","--edit", "Edit your hooks file with your EDITOR") { options.command = :edit }
|
37
|
+
opts.on("-p","--path=[path]", "Run in another path insted of current path") { |path| options.path = path }
|
38
|
+
opts.on_tail("--version", "Print current version and exit") {options.command = :version }
|
39
|
+
opts.on_tail("-h","--help", "Print help message")
|
40
|
+
end
|
41
|
+
opts.parse!(args)
|
42
|
+
(puts opts and exit 0) if options.command == :help
|
43
|
+
options
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module RGitHook
|
2
|
+
# Interface from git-commands to RGitHook
|
3
|
+
class Hook #::nodoc::
|
4
|
+
def self.execute
|
5
|
+
puts "Executing #{File.basename($0)} hook"
|
6
|
+
self.send File.basename($0).tr('-','_')
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.post_receive
|
10
|
+
packs = STDIN.read.split("\n")
|
11
|
+
ret_vals = []
|
12
|
+
|
13
|
+
rgithook = RGitHook.new repo_path
|
14
|
+
|
15
|
+
packs.each do |pack|
|
16
|
+
oldrev, newrev, ref = pack.split(' ')
|
17
|
+
ret_vals << rgithook.post_receive(oldrev,newrev,ref).first[1].to_i
|
18
|
+
end
|
19
|
+
return ret_vals.max
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.method_missing(method_name)
|
23
|
+
RGitHook.new(repo_path).send(method_name)
|
24
|
+
0
|
25
|
+
rescue
|
26
|
+
-1
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
def self.repo_path
|
31
|
+
if File.basename(File.expand_path(ENV['GIT_DIR'])) == '.git'
|
32
|
+
repo_path = File.join(ENV['GIT_DIR'],'..')
|
33
|
+
else
|
34
|
+
repo_path = ENV['GIT_DIR']
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
@@ -0,0 +1,105 @@
|
|
1
|
+
|
2
|
+
module RGitHook
|
3
|
+
|
4
|
+
class Plugin
|
5
|
+
include ::RGitHook
|
6
|
+
class Option #::nodoc::
|
7
|
+
attr_reader :name,:description,:default,:type
|
8
|
+
def initialize(name,description,default,type)
|
9
|
+
@name, @description, @default, @type = name,description,default,type
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class NoOptionError < Exception ; end
|
14
|
+
|
15
|
+
class OptionGroup #::nodoc::
|
16
|
+
# Todo: Make OptionGroup be an option of OptionGroup
|
17
|
+
attr_reader :name,:description
|
18
|
+
attr_reader :options
|
19
|
+
def initialize(name,description)
|
20
|
+
@name,@description = name,description
|
21
|
+
@options = []
|
22
|
+
end
|
23
|
+
|
24
|
+
def option(name,desc,default,type)
|
25
|
+
@options << Option.new(name,desc,default,type)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Rertun a hash with default options
|
29
|
+
#
|
30
|
+
def options_to_hash
|
31
|
+
group_options = {}
|
32
|
+
@options.each do |option|
|
33
|
+
group_options[option.name]= option.default
|
34
|
+
end
|
35
|
+
group_options
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# ::nodoc::
|
40
|
+
# Return raw options
|
41
|
+
def self.options
|
42
|
+
@@options
|
43
|
+
end
|
44
|
+
|
45
|
+
# Initialize Plugin system by including each plugin modules to the Module
|
46
|
+
# It also load the defaults from a yaml file.
|
47
|
+
# You can change the default yaml file to load another file
|
48
|
+
def self.load!
|
49
|
+
@@plugins ||=[]
|
50
|
+
@@plugins.each do |plugin|
|
51
|
+
if defined?(plugin::RunnerMethods)
|
52
|
+
Runner.class_eval do
|
53
|
+
include plugin::RunnerMethods
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
if defined?(plugin::GritCommit)
|
58
|
+
::Grit::Commit.class_eval do
|
59
|
+
include plugin::GritCommit
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
# Return a hash with the default options
|
67
|
+
def self.options_to_hash
|
68
|
+
options = {}
|
69
|
+
@@options.each do |plugin,plugin_options|
|
70
|
+
plugin_opts = {}
|
71
|
+
plugin_options.each do |option|
|
72
|
+
plugin_opts[option.name]=option.default.is_a?(OptionGroup) ? option.default.options_to_hash : option.default
|
73
|
+
end
|
74
|
+
options[plugin]=plugin_opts
|
75
|
+
end
|
76
|
+
options
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
# Define a new option
|
82
|
+
def self.option(name,desc,default,type)
|
83
|
+
@@options[get_plugin_name(self)] << Option.new(name,desc,default,type)
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.option_group(name,desc,&block)
|
87
|
+
opt_group = OptionGroup.new(name,desc)
|
88
|
+
yield opt_group
|
89
|
+
option(name,desc,opt_group,OptionGroup)
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.inherited(base)
|
93
|
+
@@plugins ||=[]
|
94
|
+
@@plugins << base
|
95
|
+
@@options ||={}
|
96
|
+
@@options[get_plugin_name(base)]=[]
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
def self.get_plugin_name(kmod)
|
101
|
+
kmod.to_s[/(.*\::)?(.*)/,2].to_sym
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
@@ -0,0 +1,229 @@
|
|
1
|
+
module RGitHook
|
2
|
+
HOOKS = %w(applypatch_msg
|
3
|
+
commit_msg
|
4
|
+
post_commit
|
5
|
+
post_receive
|
6
|
+
post_update
|
7
|
+
pre_applypatch
|
8
|
+
pre_commit
|
9
|
+
pre_rebase
|
10
|
+
prepare_commit_msg
|
11
|
+
update)
|
12
|
+
|
13
|
+
class RGitHook
|
14
|
+
attr_reader :repo
|
15
|
+
|
16
|
+
# Install RGitHook in the given repo/path
|
17
|
+
# if confirmation_needed it will ask to overwrite the existing hooks
|
18
|
+
def self.install(path_or_repo, verbose=true)
|
19
|
+
repo = parse_path path_or_repo
|
20
|
+
|
21
|
+
if verbose
|
22
|
+
puts "Welcome to RGitHook.
|
23
|
+
|
24
|
+
These will install rgithook for the next Git Repo
|
25
|
+
/Users/guillermo/Sites/
|
26
|
+
|
27
|
+
These will overwrite all the current hooks and
|
28
|
+
create .git/hooks/rgithook.rb file.
|
29
|
+
|
30
|
+
In that file you will define your hooks in ruby.
|
31
|
+
".gsub(/^ /,'')
|
32
|
+
return -1 unless prompt('Continue?')
|
33
|
+
end
|
34
|
+
hooks_dir = File.join(repo.path,'hooks')
|
35
|
+
FileUtils.mkdir hooks_dir unless File.exist? hooks_dir
|
36
|
+
|
37
|
+
install_template(repo,'rgithook.rb')
|
38
|
+
|
39
|
+
HOOKS.each do |hook_name|
|
40
|
+
install_template(repo,'hook.rb',hook_name.tr('_','-'),0555)
|
41
|
+
end
|
42
|
+
|
43
|
+
if verbose
|
44
|
+
puts "RGitHook Installed.
|
45
|
+
Now you can:
|
46
|
+
* Edit the hooks file by running
|
47
|
+
rgithook --edit
|
48
|
+
|
49
|
+
* Install the hooks file inside the repo. So all
|
50
|
+
contributors can run hooks.
|
51
|
+
mv .git/hooks/rgithook.rb ./config/rgithook.rb && \
|
52
|
+
ln -s ./config/rgithook.rb
|
53
|
+
|
54
|
+
or
|
55
|
+
|
56
|
+
mv .git/hooks/rgithook.rb ./config/rgithook.rb && \
|
57
|
+
ln -s ./.rgithook.rb
|
58
|
+
|
59
|
+
* Fetch changes from origin
|
60
|
+
rgithook --fetch
|
61
|
+
".gsub(/^ /,'')
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Install RGitHook in the given repo/path
|
66
|
+
# if confirmation_needed it will ask to overwrite the existing hooks
|
67
|
+
def install(confirmation_needed = true)
|
68
|
+
self.class.install(@repo,confirmation_needed)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Return true if rgithook is installed in the given repo
|
72
|
+
def self.installed? (path_or_repo)
|
73
|
+
File.file?(hooks_file(path_or_repo))
|
74
|
+
end
|
75
|
+
|
76
|
+
# Return true if rgithook is installed
|
77
|
+
def installed?
|
78
|
+
self.class.installed?(@repo)
|
79
|
+
end
|
80
|
+
|
81
|
+
#Extract the projects name
|
82
|
+
def project_name
|
83
|
+
if @repo.bare
|
84
|
+
File.basename(@repo.path) =~ /(.*).git/
|
85
|
+
$1 || @repo.bare
|
86
|
+
else
|
87
|
+
File.basename(@repo.working_dir)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# Returns the path of the current repo
|
92
|
+
def path
|
93
|
+
@repo.path
|
94
|
+
end
|
95
|
+
|
96
|
+
# Returns the path of the working dir or nil if it is a bare repo
|
97
|
+
def working_path
|
98
|
+
@repo.working_dir
|
99
|
+
end
|
100
|
+
|
101
|
+
# Returns true on bare repo.
|
102
|
+
def bare?
|
103
|
+
@repo.bare
|
104
|
+
end
|
105
|
+
|
106
|
+
# Open the editor with the config file
|
107
|
+
def self.call_editor(path_or_repo)
|
108
|
+
repo = parse_path path_or_repo
|
109
|
+
system(ENV['EDITOR'] || 'vi',conf_file)
|
110
|
+
end
|
111
|
+
|
112
|
+
# Open the editor with the config file
|
113
|
+
def call_editor
|
114
|
+
self.class.call_editor(@repo)
|
115
|
+
end
|
116
|
+
|
117
|
+
# Get the config file of the current repo or path
|
118
|
+
def self.conf_file(path_or_repo)
|
119
|
+
repo = parse_path path_or_repo
|
120
|
+
File.join(repo.path,'hooks','rgithook.rb')
|
121
|
+
end
|
122
|
+
|
123
|
+
# Get the config file of the current repo or path
|
124
|
+
def conf_file
|
125
|
+
self.class.conf_file(@repo)
|
126
|
+
end
|
127
|
+
|
128
|
+
#TODO: Make a reload method, to reload conf_file and hooks_file
|
129
|
+
|
130
|
+
HOOKS.each do |hook_name|
|
131
|
+
start_line = __LINE__
|
132
|
+
hook_methods =<<-EOHM
|
133
|
+
def self.#{hook_name}(path_or_repo,*args)
|
134
|
+
RGitHook.new(path_or_repo).#{hook_name}(*args)
|
135
|
+
end
|
136
|
+
|
137
|
+
def #{hook_name}(*args)
|
138
|
+
@runner.run_hooks(:#{hook_name.to_sym},*args)
|
139
|
+
end
|
140
|
+
|
141
|
+
EOHM
|
142
|
+
eval(hook_methods,binding,__FILE__,start_line+2)
|
143
|
+
end
|
144
|
+
|
145
|
+
|
146
|
+
# Call post_receive hooks
|
147
|
+
def self.post_receive(path_or_repo,oldrev,newrev,ref)
|
148
|
+
r = RGitHook.new(path_or_repo)
|
149
|
+
r.post_receive(oldrev,newrev,ref)
|
150
|
+
end
|
151
|
+
|
152
|
+
# Call post_receive hooks
|
153
|
+
def post_receive(oldrev,newrev,ref)
|
154
|
+
@runner.run_hooks(:post_receive,oldrev,newrev,ref)
|
155
|
+
end
|
156
|
+
|
157
|
+
def save_plugin_options
|
158
|
+
File.open(plugin_conf_file,'w') {|f| f.write @runner.options.to_yaml }
|
159
|
+
end
|
160
|
+
|
161
|
+
# Run some code in the runner binding
|
162
|
+
def run(code,file=nil,line=nil)
|
163
|
+
@runner.run(code,file,line)
|
164
|
+
end
|
165
|
+
|
166
|
+
def self.hooks_file(repo_or_path)
|
167
|
+
File.join(parse_path(repo_or_path).path,'hooks','rgithook.rb')
|
168
|
+
end
|
169
|
+
|
170
|
+
def hooks_file
|
171
|
+
self.class.hooks_file(@repo)
|
172
|
+
end
|
173
|
+
|
174
|
+
def self.plugin_conf_file(repo_or_path)
|
175
|
+
File.join(parse_path(repo_or_path).path,'hooks','rgithook.yaml')
|
176
|
+
end
|
177
|
+
|
178
|
+
def plugin_conf_file
|
179
|
+
self.class.plugin_conf_file(@repo)
|
180
|
+
end
|
181
|
+
|
182
|
+
|
183
|
+
private
|
184
|
+
|
185
|
+
def self.prompt(message)
|
186
|
+
while true
|
187
|
+
puts message+' [yn]'
|
188
|
+
return 'yY'.include?($1) ? true : false if $stdin.gets.strip =~ /([yYnN])/
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
|
193
|
+
def self.parse_path(path)
|
194
|
+
case path
|
195
|
+
when ::Grit::Repo
|
196
|
+
path
|
197
|
+
when String
|
198
|
+
::Grit::Repo.new(path)
|
199
|
+
end
|
200
|
+
rescue Grit::InvalidGitRepositoryError
|
201
|
+
raise ArgumentError, 'path is not a valid git repo'
|
202
|
+
end
|
203
|
+
|
204
|
+
|
205
|
+
# Contains the current runner with the hooks
|
206
|
+
attr_reader :runner
|
207
|
+
|
208
|
+
|
209
|
+
def self.install_template(path_or_repo, from,to=nil,mode = 0600)
|
210
|
+
to = from if to.nil?
|
211
|
+
repo = parse_path(path_or_repo)
|
212
|
+
|
213
|
+
from = File.join(PATH,'rgithook','templates',from)
|
214
|
+
to = File.join(repo.path,'hooks',to)
|
215
|
+
FileUtils.install(from,to, :mode => mode)
|
216
|
+
end
|
217
|
+
|
218
|
+
# Initialize a new instance of rgithook in the given repo or path
|
219
|
+
def initialize(repo_or_path)
|
220
|
+
@repo = self.class.parse_path(repo_or_path)
|
221
|
+
Plugin.load!
|
222
|
+
@runner = Runner.new(@repo)
|
223
|
+
@runner.load_options(plugin_conf_file)
|
224
|
+
@runner.load(hooks_file)
|
225
|
+
end
|
226
|
+
|
227
|
+
|
228
|
+
end
|
229
|
+
end
|