ruby_git_hooks 0.0.31
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/.gitignore +19 -0
- data/.yardopts +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +327 -0
- data/Rakefile +7 -0
- data/TODO +67 -0
- data/bin/git-add-hooks +111 -0
- data/bin/git-clone +57 -0
- data/bin/git-hclone +57 -0
- data/lib/ruby_git_hooks/all.rb +7 -0
- data/lib/ruby_git_hooks/case_clash.rb +30 -0
- data/lib/ruby_git_hooks/copyright_check.rb +181 -0
- data/lib/ruby_git_hooks/email_notify.rb +50 -0
- data/lib/ruby_git_hooks/git_ops.rb +93 -0
- data/lib/ruby_git_hooks/jira_add_comment.rb +354 -0
- data/lib/ruby_git_hooks/jira_ref_check.rb +32 -0
- data/lib/ruby_git_hooks/max_file_size.rb +32 -0
- data/lib/ruby_git_hooks/non_ascii.rb +33 -0
- data/lib/ruby_git_hooks/ruby_debug.rb +26 -0
- data/lib/ruby_git_hooks/version.rb +5 -0
- data/lib/ruby_git_hooks/watermark.rb +27 -0
- data/lib/ruby_git_hooks.rb +343 -0
- data/ruby_git_hooks.gemspec +37 -0
- data/test/basic_hook_test.rb +143 -0
- data/test/case_clash_hook_test.rb +58 -0
- data/test/copyright_check_test.rb +162 -0
- data/test/fake_curl +12 -0
- data/test/fake_mailer +5 -0
- data/test/jira_add_comment_test.rb +151 -0
- data/test/jira_ref_check_test.rb +37 -0
- data/test/max_file_size_hook_test.rb +52 -0
- data/test/multi_hook_test.rb +77 -0
- data/test/non_ascii_hook_test.rb +47 -0
- data/test/repos/.keep +0 -0
- data/test/test_helper.rb +17 -0
- data/test/watermark_test.rb +39 -0
- metadata +226 -0
@@ -0,0 +1,343 @@
|
|
1
|
+
# Copyright (C) 2013 OL2, Inc. See LICENSE.txt for details.
|
2
|
+
|
3
|
+
require "ruby_git_hooks/version"
|
4
|
+
|
5
|
+
# This module is the core of the ruby_git_hooks code. It includes the
|
6
|
+
# Git commands, the hook types and in general most of the interface.
|
7
|
+
# README.md is the best overall documentation for this package, but
|
8
|
+
# this is where you can dig into the lowest-level Git specifics.
|
9
|
+
|
10
|
+
module RubyGitHooks
|
11
|
+
# This isn't all hook names, just the ones we already support.
|
12
|
+
CAN_FAIL_HOOKS = [ "pre-commit", "pre-receive", "commit-msg" ]
|
13
|
+
NO_FAIL_HOOKS = [ "post-receive", "post-commit" ]
|
14
|
+
HOOK_NAMES = CAN_FAIL_HOOKS + NO_FAIL_HOOKS
|
15
|
+
# applypatch-msg, pre-applypatch, post-applypatch
|
16
|
+
# prepare-commit-msg, commit-msg
|
17
|
+
# pre-rebase, post-checkout, post-merge, update, post-update,
|
18
|
+
# pre-auto-gc, post-rewrite
|
19
|
+
|
20
|
+
class Hook
|
21
|
+
class << self
|
22
|
+
# What hooks are running
|
23
|
+
attr_reader :registered_hooks
|
24
|
+
|
25
|
+
# What command line was run
|
26
|
+
attr_reader :run_as
|
27
|
+
|
28
|
+
# What directory to run from
|
29
|
+
attr_reader :run_from
|
30
|
+
|
31
|
+
# What git hook is being run
|
32
|
+
attr_reader :run_as_hook
|
33
|
+
|
34
|
+
# Whether .run has ever been called
|
35
|
+
attr_reader :has_run
|
36
|
+
|
37
|
+
# Array of what files were changed
|
38
|
+
attr_accessor :files_changed
|
39
|
+
|
40
|
+
# Latest contents of all changed files
|
41
|
+
attr_accessor :file_contents
|
42
|
+
|
43
|
+
# A human-readable diff per file
|
44
|
+
attr_accessor :file_diffs
|
45
|
+
|
46
|
+
# All filenames in repo
|
47
|
+
attr_accessor :ls_files
|
48
|
+
|
49
|
+
# All current commits (sometimes empty)
|
50
|
+
attr_accessor :commits
|
51
|
+
|
52
|
+
# Commit message for current commit
|
53
|
+
attr_accessor :commit_message
|
54
|
+
|
55
|
+
# Commit message file for current commit
|
56
|
+
attr_accessor :commit_message_file
|
57
|
+
end
|
58
|
+
|
59
|
+
# Instances of Hook delegate these methods to the class methods.
|
60
|
+
HOOK_INFO = [ :files_changed, :file_contents, :file_diffs, :ls_files,
|
61
|
+
:commits, :commit_message, :commit_message_file ]
|
62
|
+
HOOK_INFO.each do |info_method|
|
63
|
+
define_method(info_method) do |*args, &block|
|
64
|
+
Hook.send(info_method, *args, &block)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
HOOK_TYPE_SETUP = {
|
69
|
+
|
70
|
+
# Pre-receive gets no args, but STDIN with a list of changes.
|
71
|
+
"pre-receive" => proc {
|
72
|
+
changes = []
|
73
|
+
STDIN.each_line do |line|
|
74
|
+
base, commit, ref = line.strip.split
|
75
|
+
changes.push [base, commit, ref]
|
76
|
+
end
|
77
|
+
self.commits = []
|
78
|
+
|
79
|
+
self.files_changed = []
|
80
|
+
self.file_contents = {}
|
81
|
+
self.file_diffs = {}
|
82
|
+
|
83
|
+
changes.each do |base, commit, ref|
|
84
|
+
no_base = false
|
85
|
+
if base =~ /\A0+\z/
|
86
|
+
# if base is 000... (initial commit), then all files were added, and git diff won't work
|
87
|
+
no_base = true
|
88
|
+
files_with_status = Hook.shell!("git ls-tree --name-status -r #{commit}").split("\n")
|
89
|
+
# put the A at the front
|
90
|
+
files_with_status.map!{|filename| "A\t" + filename}
|
91
|
+
else
|
92
|
+
files_with_status = Hook.shell!("git diff --name-status #{base}..#{commit}").split("\n")
|
93
|
+
end
|
94
|
+
|
95
|
+
files_with_status.each do |f|
|
96
|
+
status, file_changed = f.scan(/([ACDMRTUXB])\s+(\S+)$/).flatten
|
97
|
+
self.files_changed << file_changed
|
98
|
+
|
99
|
+
file_diffs[file_changed] = Hook.shell!("git log -p #{commit} -- #{file_changed}")
|
100
|
+
begin
|
101
|
+
file_contents[file_changed] = status == "D" ? "" : Hook.shell!("git show #{commit}:#{file_changed}")
|
102
|
+
rescue
|
103
|
+
# weird bug where some repos can't run the git show command even when it's not a deleted file.
|
104
|
+
# example: noah-gibbs/barkeep/test/fixtures/text_git_repo I haven't figured out what's
|
105
|
+
# weird about it yet but this fails, so put in a hack for now. May want to leave this since
|
106
|
+
# we'd rather continue without the changes than fail, right?
|
107
|
+
file_contents[file_changed] = ""
|
108
|
+
end
|
109
|
+
end
|
110
|
+
commit_range = no_base ? commit : "#{base}..#{commit}"
|
111
|
+
new_commits = Hook.shell!("git log --pretty=format:%H #{commit_range}").split("\n")
|
112
|
+
self.commits = self.commits | new_commits
|
113
|
+
end
|
114
|
+
|
115
|
+
if !self.commits.empty?
|
116
|
+
file_list_revision = self.commits.first # can't just use HEAD - remote may be on branch with no HEAD
|
117
|
+
self.ls_files = Hook.shell!("git ls-tree --full-tree --name-only -r #{file_list_revision}").split("\n")
|
118
|
+
# TODO should store ls_files per commit and ls_files with branch name (in case commits on multiple branches)?
|
119
|
+
end
|
120
|
+
|
121
|
+
|
122
|
+
|
123
|
+
},
|
124
|
+
|
125
|
+
"pre-commit" => proc {
|
126
|
+
files_with_status = Hook.shell!("git diff --name-status --cached").split("\n")
|
127
|
+
|
128
|
+
self.files_changed = []
|
129
|
+
self.file_contents = {}
|
130
|
+
self.file_diffs = {}
|
131
|
+
self.commits = []
|
132
|
+
|
133
|
+
files_with_status.each do |f|
|
134
|
+
status, file_changed = f.scan(/([ACDMRTUXB])\s+(\S+)$/).flatten
|
135
|
+
self.files_changed << file_changed
|
136
|
+
|
137
|
+
file_diffs[file_changed] = Hook.shell!("git diff --cached -- #{file_changed}")
|
138
|
+
file_contents[file_changed] = status == "D"? "": Hook.shell!("git show :#{file_changed}")
|
139
|
+
end
|
140
|
+
|
141
|
+
self.ls_files = Hook.shell!("git ls-files").split("\n")
|
142
|
+
},
|
143
|
+
|
144
|
+
"post-commit" => proc {
|
145
|
+
last_commit_files = Hook.shell!("git log --oneline --name-status -1")
|
146
|
+
# Split, cut off leading line to get actual files with status
|
147
|
+
files_with_status = last_commit_files.split("\n")[1..-1]
|
148
|
+
|
149
|
+
self.files_changed = []
|
150
|
+
self.commits = [ Hook.shell!("git log -n 1 --pretty=format:%H").chomp ]
|
151
|
+
self.file_contents = {}
|
152
|
+
self.file_diffs = {}
|
153
|
+
|
154
|
+
files_with_status.each do |f|
|
155
|
+
status, file_changed = f.scan(/([ACDMRTUXB])\s+(\S+)$/).flatten
|
156
|
+
self.files_changed << file_changed
|
157
|
+
|
158
|
+
file_diffs[file_changed] = Hook.shell!("git log --oneline -p -1 -- #{file_changed}")
|
159
|
+
file_contents[file_changed] = status == "D"? "": Hook.shell!("git show :#{file_changed}")
|
160
|
+
end
|
161
|
+
|
162
|
+
self.ls_files = Hook.shell!("git ls-files").split("\n")
|
163
|
+
self.commit_message = Hook.shell!("git log -1 --pretty=%B")
|
164
|
+
},
|
165
|
+
|
166
|
+
"commit-msg" => proc {
|
167
|
+
files_with_status = Hook.shell!("git diff --name-status --cached").split("\n")
|
168
|
+
|
169
|
+
self.files_changed = []
|
170
|
+
self.file_contents = {}
|
171
|
+
self.file_diffs = {}
|
172
|
+
self.commits = []
|
173
|
+
|
174
|
+
files_with_status.each do |f|
|
175
|
+
status, file_changed = f.scan(/([ACDMRTUXB])\s+(\S+)$/).flatten
|
176
|
+
self.files_changed << file_changed
|
177
|
+
|
178
|
+
file_diffs[file_changed] = Hook.shell!("git diff --cached -- #{file_changed}")
|
179
|
+
file_contents[file_changed] = status == "D"? "": Hook.shell!("git show :#{file_changed}")
|
180
|
+
end
|
181
|
+
|
182
|
+
self.ls_files = Hook.shell!("git ls-files").split("\n")
|
183
|
+
self.commit_message = File.read(ARGV[0])
|
184
|
+
self.commit_message_file = ARGV[0]
|
185
|
+
}
|
186
|
+
}
|
187
|
+
HOOK_TYPE_SETUP["post-receive"] = HOOK_TYPE_SETUP["pre-receive"]
|
188
|
+
|
189
|
+
def self.initial_setup
|
190
|
+
return if @run_from
|
191
|
+
|
192
|
+
@run_from = Dir.getwd
|
193
|
+
@run_as = $0
|
194
|
+
end
|
195
|
+
|
196
|
+
def setup
|
197
|
+
Dir.chdir Hook.run_from do
|
198
|
+
yield
|
199
|
+
end
|
200
|
+
|
201
|
+
ensure
|
202
|
+
# Nothing yet
|
203
|
+
end
|
204
|
+
|
205
|
+
def self.get_hooks_to_run(hook_specs)
|
206
|
+
@registered_hooks ||= {}
|
207
|
+
|
208
|
+
if hook_specs.empty?
|
209
|
+
return @registered_hooks.values.inject([], &:+)
|
210
|
+
end
|
211
|
+
|
212
|
+
hook_specs.flat_map do |spec|
|
213
|
+
if @registered_hooks[spec]
|
214
|
+
@registered_hooks[spec]
|
215
|
+
elsif spec.is_a?(Hook)
|
216
|
+
[ spec ]
|
217
|
+
elsif spec.is_a?(String)
|
218
|
+
# A string is assumed to be a class name
|
219
|
+
@registered_hooks[Object.const_get(spec)]
|
220
|
+
else
|
221
|
+
raise "Can't find hook for specification: #{spec.inspect}!"
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
# Run takes a list of hook specifications.
|
227
|
+
# Those can be Hook classnames or instances of type
|
228
|
+
# Hook.
|
229
|
+
#
|
230
|
+
# @param hook_specs Array[Hook or Class or String] A list of hooks or hook classes
|
231
|
+
def self.run(*hook_specs)
|
232
|
+
if @has_run
|
233
|
+
STDERR.puts <<ERR
|
234
|
+
In this version, you can't call .run more than once. For now, please
|
235
|
+
register your hooks individually and then call .run with no args, or
|
236
|
+
else call .run with both as arguments. This may be fixed in a future
|
237
|
+
version. Sorry!
|
238
|
+
ERR
|
239
|
+
exit 1
|
240
|
+
end
|
241
|
+
@has_run = true
|
242
|
+
|
243
|
+
initial_setup
|
244
|
+
|
245
|
+
run_as_specific_githook
|
246
|
+
|
247
|
+
# By default, run all hooks
|
248
|
+
hooks_to_run = get_hooks_to_run(hook_specs.flatten)
|
249
|
+
|
250
|
+
failed_hooks = []
|
251
|
+
val = nil
|
252
|
+
hooks_to_run.each do |hook|
|
253
|
+
begin
|
254
|
+
hook.setup { val = hook.check } # Re-init each time, just in case
|
255
|
+
failed_hooks.push(hook) unless val
|
256
|
+
rescue
|
257
|
+
# Failed. Return non-zero if that makes a difference.
|
258
|
+
STDERR.puts "Hook #{hook.inspect} raised exception: #{$!.inspect}!\n#{$!.backtrace.join("\n")}"
|
259
|
+
failed_hooks.push hook
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
if CAN_FAIL_HOOKS.include?(@run_as_hook) && failed_hooks.size > 0
|
264
|
+
STDERR.puts "Hooks failed: #{failed_hooks}"
|
265
|
+
STDERR.puts "Use 'git commit -eF .git/COMMIT_EDITMSG' to restore your commit message" if commit_message
|
266
|
+
STDERR.puts "Exiting!"
|
267
|
+
exit 1
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
def self.run_as_specific_githook
|
272
|
+
return if @run_as_hook # Already did this
|
273
|
+
|
274
|
+
self.initial_setup # Might have already done this
|
275
|
+
|
276
|
+
if ARGV.include? "--hook"
|
277
|
+
idx = ARGV.find_index "--hook"
|
278
|
+
@run_as_hook = ARGV[idx + 1]
|
279
|
+
2.times { ARGV.delete_at(idx) }
|
280
|
+
else
|
281
|
+
@run_as_hook = HOOK_NAMES.detect { |hook| @run_as.include?(hook) }
|
282
|
+
end
|
283
|
+
|
284
|
+
unless @run_as_hook
|
285
|
+
STDERR.puts "Name #{@run_as.inspect} doesn't include " +
|
286
|
+
"any of: #{HOOK_NAMES.inspect}"
|
287
|
+
exit 1
|
288
|
+
end
|
289
|
+
|
290
|
+
unless HOOK_TYPE_SETUP[@run_as_hook]
|
291
|
+
STDERR.puts "No setup defined for hook type #{@run_as_hook.inspect}!"
|
292
|
+
exit 1
|
293
|
+
end
|
294
|
+
self.instance_eval(&HOOK_TYPE_SETUP[@run_as_hook])
|
295
|
+
end
|
296
|
+
|
297
|
+
def self.register(hook)
|
298
|
+
@registered_hooks ||= {}
|
299
|
+
@registered_hooks[hook.class.name] ||= []
|
300
|
+
@registered_hooks[hook.class.name].push hook
|
301
|
+
|
302
|
+
# Figure out when to set this up...
|
303
|
+
#at_exit do
|
304
|
+
# unless RubyGitHooks::Hook.has_run
|
305
|
+
# STDERR.puts "No call to RubyGitHooks.run happened, so no hooks ran!"
|
306
|
+
# end
|
307
|
+
#end
|
308
|
+
end
|
309
|
+
|
310
|
+
def self.shell!(*args)
|
311
|
+
output = `#{args.join(" ")}`
|
312
|
+
|
313
|
+
unless $?.success?
|
314
|
+
STDERR.puts "Job #{args.inspect} failed in dir #{Dir.getwd.inspect}"
|
315
|
+
STDERR.puts "Failed job output:\n#{output}\n======"
|
316
|
+
raise "Exec of #{args.inspect} failed: #{$?}!"
|
317
|
+
end
|
318
|
+
|
319
|
+
output
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
# Forward these calls from RubyGitHooks to RubyGitHooks::Hook
|
324
|
+
class << self
|
325
|
+
[ :run, :register, :run_as ].each do |method|
|
326
|
+
define_method(method) do |*args, &block|
|
327
|
+
RubyGitHooks::Hook.send(method, *args, &block)
|
328
|
+
end
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
def self.shebang
|
333
|
+
ENV['RUBYGITHOOKS_SHEBANG']
|
334
|
+
end
|
335
|
+
|
336
|
+
def self.current_hook
|
337
|
+
RubyGitHooks::Hook.run_as_specific_githook
|
338
|
+
RubyGitHooks::Hook.run_as_hook
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
# Default to /usr/bin/env ruby for shebang line
|
343
|
+
ENV['RUBYGITHOOKS_SHEBANG'] ||= "#!/usr/bin/env ruby"
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'ruby_git_hooks/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "ruby_git_hooks"
|
8
|
+
spec.version = RubyGitHooks::VERSION
|
9
|
+
spec.authors = ["Noah Gibbs", "Ruth Helfinstein", "Alex Snyatkov"]
|
10
|
+
spec.email = ["noah@onlive.com", "ruth.helfinstein@onlive.com",
|
11
|
+
"alex.snyatkov@onlive.com"]
|
12
|
+
spec.description = <<DESC
|
13
|
+
Ruby_git_hooks is a library to allow easy writing and installing of
|
14
|
+
git hooks in Ruby. It abstracts away the differences between
|
15
|
+
different hook interfaces and supplies implementations of some common
|
16
|
+
Git hooks. It allows overriding "git clone" to automatically
|
17
|
+
install your prefered hooks.
|
18
|
+
DESC
|
19
|
+
spec.summary = %q{DSL and manager for git hooks in Ruby.}
|
20
|
+
spec.homepage = ""
|
21
|
+
spec.license = "MIT"
|
22
|
+
|
23
|
+
spec.files = `git ls-files`.split($/)
|
24
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
25
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
26
|
+
spec.require_paths = ["lib"]
|
27
|
+
spec.bindir = "bin"
|
28
|
+
|
29
|
+
spec.add_runtime_dependency "pony" # For email
|
30
|
+
spec.add_runtime_dependency "rest-client"
|
31
|
+
spec.add_runtime_dependency "json"
|
32
|
+
|
33
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
34
|
+
spec.add_development_dependency "minitest"
|
35
|
+
spec.add_development_dependency "rr"
|
36
|
+
spec.add_development_dependency "rake"
|
37
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
# Copyright (C) 2013 OL2, Inc. See LICENSE.txt for details.
|
2
|
+
|
3
|
+
require "test_helper"
|
4
|
+
|
5
|
+
require "minitest/autorun"
|
6
|
+
|
7
|
+
class BasicHookTest < HookTestCase
|
8
|
+
REPOS_DIR = File.expand_path File.join(File.dirname(__FILE__), "repos")
|
9
|
+
TEST_PATH = File.join(REPOS_DIR, "hook_test_file")
|
10
|
+
TEST_HOOK_BODY = <<HOOK
|
11
|
+
#{RubyGitHooks.shebang}
|
12
|
+
require "ruby_git_hooks"
|
13
|
+
|
14
|
+
class TestHook < RubyGitHooks::Hook
|
15
|
+
def check
|
16
|
+
File.open("#{TEST_PATH}", "w") do |f|
|
17
|
+
f.puts files_changed.inspect, file_contents.inspect
|
18
|
+
end
|
19
|
+
|
20
|
+
puts "Test hook runs!"
|
21
|
+
true
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
RubyGitHooks.run TestHook.new
|
26
|
+
HOOK
|
27
|
+
|
28
|
+
TEST_HOOK_COMMIT_MSG = <<HOOK
|
29
|
+
#{RubyGitHooks.shebang}
|
30
|
+
require "ruby_git_hooks"
|
31
|
+
|
32
|
+
class TestHook < RubyGitHooks::Hook
|
33
|
+
def check
|
34
|
+
File.open("#{TEST_PATH}", "w") do |f|
|
35
|
+
f.puts commit_message
|
36
|
+
end
|
37
|
+
|
38
|
+
puts "Test hook runs!"
|
39
|
+
true
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
RubyGitHooks.run TestHook.new
|
44
|
+
HOOK
|
45
|
+
|
46
|
+
def setup(do_first_commit = true)
|
47
|
+
# Empty out the test repos dir
|
48
|
+
Hook.shell! "rm -rf #{File.join(REPOS_DIR, "*")}"
|
49
|
+
|
50
|
+
# Create local parent and child repos with a single shared commit
|
51
|
+
Dir.chdir REPOS_DIR
|
52
|
+
|
53
|
+
new_bare_repo
|
54
|
+
clone_repo
|
55
|
+
if do_first_commit
|
56
|
+
new_single_file_commit
|
57
|
+
git_push
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_simple_pre_commit
|
62
|
+
add_hook("child_repo", "pre-commit", TEST_HOOK_BODY)
|
63
|
+
|
64
|
+
new_single_file_commit "child_repo"
|
65
|
+
|
66
|
+
assert File.exist?(TEST_PATH), "Test pre-commit hook didn't run!"
|
67
|
+
assert File.read(TEST_PATH).include?("Single-file commit"),
|
68
|
+
"No file contents reached pre-commit hook!"
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_pre_commit_with_delete
|
72
|
+
add_hook("child_repo", "pre-commit", TEST_HOOK_BODY)
|
73
|
+
new_commit "child_repo", "file_to_delete"
|
74
|
+
git_delete "child_repo", "file_to_delete"
|
75
|
+
git_commit "child_repo", "Deleted file_to_delete"
|
76
|
+
|
77
|
+
assert File.exist?(TEST_PATH), "Test pre-commit hook didn't run!"
|
78
|
+
assert File.read(TEST_PATH).include?('"file_to_delete"=>""'),
|
79
|
+
"File not deleted properly"
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_pre_commit_with_rename
|
83
|
+
add_hook("child_repo", "pre-commit", TEST_HOOK_BODY)
|
84
|
+
new_commit "child_repo", "file_to_rename"
|
85
|
+
git_rename "child_repo", "file_to_rename", "renamed_file"
|
86
|
+
new_commit "child_repo", "renamed_file", nil, "Renamed file"
|
87
|
+
|
88
|
+
assert File.exist?(TEST_PATH), "Test pre-commit hook didn't run!"
|
89
|
+
assert File.read(TEST_PATH).include?('"file_to_rename"=>""'),
|
90
|
+
"File not deleted properly"
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_simple_pre_receive
|
94
|
+
add_hook("parent_repo.git", "pre-receive", TEST_HOOK_BODY)
|
95
|
+
|
96
|
+
new_single_file_commit "child_repo"
|
97
|
+
git_push("child_repo")
|
98
|
+
|
99
|
+
assert File.exist?(TEST_PATH), "Test pre-receive hook didn't run!"
|
100
|
+
assert File.read(TEST_PATH).include?("Single-file commit"),
|
101
|
+
"No file contents reached pre-receive hook!"
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
def test_pre_receive_with_delete
|
106
|
+
add_hook("parent_repo.git", "pre-receive", TEST_HOOK_BODY)
|
107
|
+
|
108
|
+
new_commit "child_repo", "file_to_delete"
|
109
|
+
git_push "child_repo"
|
110
|
+
|
111
|
+
|
112
|
+
git_delete "child_repo", "file_to_delete"
|
113
|
+
git_commit "child_repo", "Deleted file_to_delete"
|
114
|
+
git_push "child_repo"
|
115
|
+
|
116
|
+
|
117
|
+
assert File.exist?(TEST_PATH), "Test pre-receive hook didn't run!"
|
118
|
+
assert File.read(TEST_PATH).include?('"file_to_delete"=>""'),
|
119
|
+
"File deletion did not reach pre-receive hook!"
|
120
|
+
end
|
121
|
+
|
122
|
+
def test_commit_msg
|
123
|
+
add_hook("child_repo", "commit-msg", TEST_HOOK_COMMIT_MSG)
|
124
|
+
new_commit "child_repo", "my_file", "Commit contents", "This is my commit message"
|
125
|
+
assert File.exist?(TEST_PATH), "Test commit-msg hook didn't run!"
|
126
|
+
assert File.read(TEST_PATH).include?("This is my commit message"),
|
127
|
+
"Commit message did not reach commit-msg hook"
|
128
|
+
end
|
129
|
+
|
130
|
+
def test_post_commit_has_commit_msg
|
131
|
+
add_hook("child_repo", "post-commit", TEST_HOOK_COMMIT_MSG)
|
132
|
+
new_commit "child_repo", "my_file", "Commit contents", "This is my commit message"
|
133
|
+
assert File.exist?(TEST_PATH), "Test post-commit hook didn't run!"
|
134
|
+
assert File.read(TEST_PATH).include?("This is my commit message"),
|
135
|
+
"Commit message did not reach post-commit hook"
|
136
|
+
end
|
137
|
+
|
138
|
+
def test_first_pre_receive
|
139
|
+
setup(false) # don't do first commit
|
140
|
+
test_simple_pre_receive
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# Copyright (C) 2013 OL2, Inc. See LICENSE.txt for details.
|
2
|
+
|
3
|
+
require "test_helper"
|
4
|
+
|
5
|
+
require "minitest/autorun"
|
6
|
+
|
7
|
+
class CaseClashHookTest < HookTestCase
|
8
|
+
REPOS_DIR = File.expand_path File.join(File.dirname(__FILE__), "repos")
|
9
|
+
TEST_HOOK_BODY = <<TEST
|
10
|
+
#{RubyGitHooks.shebang}
|
11
|
+
require "ruby_git_hooks/case_clash"
|
12
|
+
|
13
|
+
RubyGitHooks.run CaseClashHook.new
|
14
|
+
TEST
|
15
|
+
|
16
|
+
def setup
|
17
|
+
# Empty out the test repos dir
|
18
|
+
Hook.shell! "rm -rf #{File.join(REPOS_DIR, "*")}"
|
19
|
+
|
20
|
+
# Create local parent and child repos with a single shared commit
|
21
|
+
Dir.chdir REPOS_DIR
|
22
|
+
|
23
|
+
new_bare_repo
|
24
|
+
clone_repo
|
25
|
+
new_commit "child_repo", "README"
|
26
|
+
git_push
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_case_clash_pre_commit
|
30
|
+
add_hook("child_repo", "pre-commit", TEST_HOOK_BODY)
|
31
|
+
|
32
|
+
new_commit "child_repo", "CaseClashFile1"
|
33
|
+
case1_sha = last_commit_sha
|
34
|
+
rewind_one_commit
|
35
|
+
|
36
|
+
new_commit "child_repo", "CASECLASHFILE1"
|
37
|
+
case2_sha = last_commit_sha
|
38
|
+
|
39
|
+
# Cherry-pick new content into place -- this means both files.
|
40
|
+
Hook.shell!("cd child_repo && git cherry-pick #{case1_sha}")
|
41
|
+
case_both = last_commit_sha
|
42
|
+
|
43
|
+
rewind_one_commit
|
44
|
+
|
45
|
+
# Soft-reset so content is still present
|
46
|
+
Hook.shell!("cd child_repo && git reset #{case_both}")
|
47
|
+
|
48
|
+
# Should reject w/ pre-commit hook
|
49
|
+
assert_raises RuntimeError do
|
50
|
+
Hook.shell!("cd child_repo && git commit -m \"Message\"")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
#def test_case_clash_pre_receive
|
55
|
+
# add_hook("parent_repo.git", "pre-receive", TEST_HOOK_BODY)
|
56
|
+
#end
|
57
|
+
|
58
|
+
end
|