gitty 0.1.0 → 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/assets/hooks/{git-post-checkout-submodules → auto-submodules} +28 -2
- data/assets/hooks/{prevent-nocommit-tags → nocommit} +0 -0
- data/bin/git-hook +1 -1
- data/lib/gitty.rb +1 -24
- data/lib/gitty/commands/init.rb +2 -2
- data/lib/gitty/commands/install.rb +32 -0
- data/lib/gitty/commands/list.rb +17 -29
- data/lib/gitty/commands/publish.rb +1 -1
- data/lib/gitty/commands/shell.rb +1 -1
- data/lib/gitty/commands/uninstall.rb +39 -0
- data/lib/gitty/helpers.rb +4 -0
- data/lib/gitty/hook.rb +132 -32
- data/lib/gitty/hook_command.rb +42 -0
- data/spec/gitty/hook_spec.rb +139 -0
- data/spec/gitty_spec.rb +0 -35
- data/spec/spec.opts +7 -0
- data/spec/spec_helper.rb +26 -3
- metadata +10 -9
- data/lib/gitty/commands/add.rb +0 -26
- data/lib/gitty/commands/manager.rb +0 -50
- data/lib/gitty/commands/remove.rb +0 -17
- data/spec/gitty/commands/add_spec.rb +0 -5
@@ -39,6 +39,7 @@ module GitMethods
|
|
39
39
|
end
|
40
40
|
end
|
41
41
|
include GitMethods
|
42
|
+
HELPERS = File.expand_path(ENV['HELPERS'], Dir.pwd)
|
42
43
|
|
43
44
|
chdir_parent
|
44
45
|
current_submodules = list_submodules('HEAD')
|
@@ -65,10 +66,35 @@ previous_submodules = list_submodules('HEAD@{1}')
|
|
65
66
|
when rev != current_submodules[path]
|
66
67
|
output_submodule_header(path)
|
67
68
|
# it should be updated to the latest
|
68
|
-
# Fetch if it the change doesn't exist
|
69
69
|
Dir.chdir(path) do
|
70
|
+
# Fetch if it the change doesn't exist
|
70
71
|
system("(git show '#{current_submodules[path]}' 2> /dev/null 1> /dev/null) || git fetch")
|
71
|
-
|
72
|
+
|
73
|
+
current_rev = current_submodules[path]
|
74
|
+
STDERR.puts("submodule is pointing to #{rev}")
|
75
|
+
rev, ref_kind, ref = %x{git for-each-ref}.split("\n").map { |l| l.split(" ") }.detect {|l| l.first == current_rev }
|
76
|
+
|
77
|
+
if ref.nil?
|
78
|
+
STDERR.puts "no known branch is currently at #{current_rev}, so we had to detach your HEAD."
|
79
|
+
STDERR.puts "here are some suggestions: "
|
80
|
+
system("git branch --contains #{current_rev} -a | egrep -v 'no branch|HEAD' 1>&2")
|
81
|
+
exit 1
|
82
|
+
end
|
83
|
+
if ref.match(/^refs\/heads/)
|
84
|
+
exec("git checkout '#{File.basename(ref)}'")
|
85
|
+
end
|
86
|
+
|
87
|
+
if ref.match(/^refs\/remotes/) then
|
88
|
+
local_ref=File.basename(ref)
|
89
|
+
|
90
|
+
STDERR.puts "Remote branch #{ref} matches"
|
91
|
+
divergent_commits=%x{git rev-list #{ref}..#{local_ref}}.strip
|
92
|
+
if divergent_commits.empty?
|
93
|
+
STDERR.puts "fastforwarding #{local_ref} to #{ref}"
|
94
|
+
system("git branch -f #{local_ref} #{ref}")
|
95
|
+
exec("git checkout #{local_ref}")
|
96
|
+
end
|
97
|
+
end
|
72
98
|
end
|
73
99
|
end
|
74
100
|
end
|
File without changes
|
data/bin/git-hook
CHANGED
data/lib/gitty.rb
CHANGED
@@ -25,31 +25,8 @@ module Gitty
|
|
25
25
|
end
|
26
26
|
nil
|
27
27
|
end
|
28
|
-
|
29
|
-
def self.creating_dir_if_nonexistant(dir)
|
30
|
-
FileUtils.mkdir_p(dir)
|
31
|
-
Pathname.new(dir)
|
32
|
-
end
|
33
|
-
|
34
|
-
def self.extract_meta_data(string_or_io)
|
35
|
-
io = string_or_io.respond_to?(:readline) ? string_or_io : StringIO.new(string_or_io)
|
36
|
-
meta_yaml = ""
|
37
|
-
begin
|
38
|
-
while line = io.readline
|
39
|
-
next unless line.match(/^# (description.+)/)
|
40
|
-
meta_yaml = "#{$1}\n"
|
41
|
-
break
|
42
|
-
end
|
43
|
-
|
44
|
-
while line = io.readline
|
45
|
-
break unless line.match(/^# (.+)/)
|
46
|
-
meta_yaml << "#{$1}\n"
|
47
|
-
end
|
48
|
-
rescue EOFError
|
49
|
-
end
|
50
|
-
meta_yaml.empty? ? nil : YAML.load(meta_yaml)
|
51
|
-
end
|
52
28
|
end
|
53
29
|
|
54
30
|
require "gitty/runner.rb"
|
55
31
|
require "gitty/hook.rb"
|
32
|
+
require "gitty/hook_command.rb"
|
data/lib/gitty/commands/init.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'fileutils'
|
2
|
-
class Gitty::
|
2
|
+
class Gitty::HookCommand::Init < Gitty::Runner
|
3
3
|
include ::Gitty::Helpers
|
4
4
|
|
5
5
|
CLIENT_HOOKS = %w[
|
@@ -34,7 +34,7 @@ class Gitty::Hook::Init < Gitty::Runner
|
|
34
34
|
cmd(*%w[git symbolic-ref HEAD refs/heads/--hooks--])
|
35
35
|
cmd(*%w[git commit --allow-empty -m initial\ commit])
|
36
36
|
end
|
37
|
-
cmd(*%w[git reset --hard]
|
37
|
+
cmd(*%w[git reset --hard] + hooks_rev) if hooks_rev
|
38
38
|
end
|
39
39
|
end
|
40
40
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class Gitty::HookCommand::Install < Gitty::Runner
|
2
|
+
include FileUtils
|
3
|
+
def initialize(args, stdout = STDOUT, stderr = STDERR)
|
4
|
+
super
|
5
|
+
@hookname = args.shift
|
6
|
+
end
|
7
|
+
|
8
|
+
def run
|
9
|
+
hook = Gitty::Hook.find(@hookname, :installed => false)
|
10
|
+
if hook.nil?
|
11
|
+
stderr.puts "no hook named '#{@hookname}' found."
|
12
|
+
exit 1
|
13
|
+
end
|
14
|
+
|
15
|
+
hook.install(options[:kind])
|
16
|
+
if options[:kind] == :shared
|
17
|
+
stdout.puts "To propagate this change other developers, run 'git hook publish -m \"added #{hook.name}...\""
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def options
|
22
|
+
@options ||= super.update(:kind => :local)
|
23
|
+
end
|
24
|
+
|
25
|
+
def option_parser
|
26
|
+
@option_parser ||= super.tap do |opts|
|
27
|
+
opts.banner = "Usage: git hook install [opts] hook-name"
|
28
|
+
opts.on("-l", "--local", "Local hook (default)") { |l| options[:kind] = :local }
|
29
|
+
opts.on("-s", "--shared", "Remote hook") { |l| options[:kind] = :shared }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/gitty/commands/list.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
require 'fileutils'
|
2
|
-
class Gitty::
|
2
|
+
class Gitty::HookCommand::List < Gitty::Runner
|
3
3
|
include ::Gitty::Helpers
|
4
4
|
include FileUtils
|
5
|
-
KINDS = [:local, :shared, :
|
5
|
+
KINDS = [:local, :shared, :uninstalled]
|
6
6
|
|
7
7
|
def run
|
8
8
|
stdout.puts "Listing hooks"
|
@@ -11,17 +11,19 @@ class Gitty::Hook::List < Gitty::Runner
|
|
11
11
|
which_to_show.each { |w| show_hooks(w) }
|
12
12
|
end
|
13
13
|
|
14
|
+
def all_hooks
|
15
|
+
@all_hooks = Gitty::Hook.find_all
|
16
|
+
end
|
17
|
+
|
14
18
|
def show_hooks(which)
|
15
19
|
case which
|
16
|
-
when :local
|
17
|
-
when :
|
18
|
-
when :available then show_available_hooks
|
20
|
+
when :local, :shared then show_local_or_shared_hooks(which)
|
21
|
+
when :uninstalled then show_uninstalled_hooks
|
19
22
|
end
|
20
23
|
end
|
21
24
|
|
22
25
|
def show_local_or_shared_hooks(which)
|
23
|
-
hook_names =
|
24
|
-
return if hook_names.empty?
|
26
|
+
hook_names = all_hooks.select { |h| h.install_kind == which.to_sym }.map(&:name)
|
25
27
|
puts "#{which}:\n#{listify(hook_names)}\n\n"
|
26
28
|
end
|
27
29
|
|
@@ -29,25 +31,11 @@ class Gitty::Hook::List < Gitty::Runner
|
|
29
31
|
hooks.map { |h| "- #{h}" }.join("\n")
|
30
32
|
end
|
31
33
|
|
32
|
-
def
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
else
|
38
|
-
[]
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def installed_hooks_path(which)
|
43
|
-
Pathname.new(".git/hooks/#{which}/hooks")
|
44
|
-
end
|
45
|
-
|
46
|
-
def show_available_hooks
|
47
|
-
all_hooks = Gitty.asset_paths.map {|asset_path| filenames_in(asset_path + "hooks")}.flatten
|
48
|
-
installed_hooks = [:local, :shared].map { |which| filenames_in(installed_hooks_path(which)) }.flatten
|
49
|
-
available_hooks = all_hooks.sort - installed_hooks.sort
|
50
|
-
puts "available:\n#{listify(available_hooks)}\n\n"
|
34
|
+
def show_uninstalled_hooks
|
35
|
+
available_hook_names = all_hooks.select { |h| ! h.installed? }.map(&:name)
|
36
|
+
installed_hook_names = all_hooks.select { |h| h.installed? }.map(&:name)
|
37
|
+
uninstalled_hooks = (available_hook_names - installed_hook_names).sort
|
38
|
+
puts "uninstalled:\n#{listify(uninstalled_hooks)}\n\n"
|
51
39
|
end
|
52
40
|
|
53
41
|
def option_parser
|
@@ -56,11 +44,11 @@ class Gitty::Hook::List < Gitty::Runner
|
|
56
44
|
opts.on("-l", "--local", "Show local hooks") do
|
57
45
|
options[:local] = true
|
58
46
|
end
|
59
|
-
opts.on("-
|
47
|
+
opts.on("-s", "--shared", "Show shared hooks") do
|
60
48
|
options[:shared] = true
|
61
49
|
end
|
62
|
-
opts.on("-
|
63
|
-
options[:
|
50
|
+
opts.on("-u", "--uninstalled", "Show uninstalled hooks") do
|
51
|
+
options[:uninstalled] = true
|
64
52
|
end
|
65
53
|
end
|
66
54
|
end
|
data/lib/gitty/commands/shell.rb
CHANGED
@@ -0,0 +1,39 @@
|
|
1
|
+
class Gitty::HookCommand::Uninstall < Gitty::Runner
|
2
|
+
include FileUtils
|
3
|
+
def initialize(args, stdout = STDOUT, stderr = STDERR)
|
4
|
+
super
|
5
|
+
@hookname = args.shift
|
6
|
+
end
|
7
|
+
|
8
|
+
def run
|
9
|
+
options = {:installed => true}
|
10
|
+
options[:install_kind] = options[:kind] if options[:kind]
|
11
|
+
hook = Gitty::Hook.find(@hookname, options)
|
12
|
+
return no_hook_found unless hook
|
13
|
+
hook.uninstall
|
14
|
+
|
15
|
+
stdout.puts "#{hook.install_kind} hook #{hook.name} has been successfully uninstalled."
|
16
|
+
if hook.install_kind == :shared
|
17
|
+
stdout.puts "To propagate this change other developers, run 'git hook publish -m \"removed #{hook.name}\""
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
protected
|
22
|
+
|
23
|
+
def no_hook_found
|
24
|
+
stderr.puts("there is no installed hook named '#{@hookname}'")
|
25
|
+
exit 1
|
26
|
+
end
|
27
|
+
|
28
|
+
def options
|
29
|
+
@options ||= super.update(:kind => :local)
|
30
|
+
end
|
31
|
+
|
32
|
+
def option_parser
|
33
|
+
@option_parser ||= super.tap do |opts|
|
34
|
+
opts.banner = "Usage: git hook uninstall [opts] hook-name"
|
35
|
+
opts.on("-l", "--local", "Local hook (default)") { |l| options[:kind] = :local }
|
36
|
+
opts.on("-s", "--shared", "Remote hook") { |l| options[:kind] = :shared }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/gitty/helpers.rb
CHANGED
data/lib/gitty/hook.rb
CHANGED
@@ -1,42 +1,142 @@
|
|
1
|
-
class Gitty::Hook
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
end
|
13
|
-
|
14
|
-
def initialize(args, stdout = STDOUT, stderr = STDERR)
|
15
|
-
@args, @stdout, @stderr = args, stdout, stderr
|
16
|
-
if COMMANDS.include?(args.first)
|
17
|
-
@target = Gitty::Hook.const_get(args.shift.classify).new(args, stdout, stderr)
|
1
|
+
class Gitty::Hook
|
2
|
+
include Gitty::Helpers
|
3
|
+
include FileUtils
|
4
|
+
attr_accessor :path
|
5
|
+
|
6
|
+
def initialize(options = {})
|
7
|
+
options.each do |k,v|
|
8
|
+
send("#{k}=", v)
|
9
|
+
end
|
10
|
+
if installed?
|
11
|
+
extend Gitty::Hook::InstalledHookStrategy
|
18
12
|
else
|
19
|
-
|
13
|
+
extend Gitty::Hook::AvailableHookStrategy
|
20
14
|
end
|
21
15
|
end
|
22
|
-
|
23
|
-
def
|
24
|
-
|
25
|
-
|
16
|
+
|
17
|
+
def self.available_hooks_search_paths
|
18
|
+
Gitty.asset_paths.map { |ap| File.join(ap, "hooks") }
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.installed_hooks_search_paths
|
22
|
+
[installed_hooks_path(:local), installed_hooks_path(:shared)]
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.installed_path(which = :local)
|
26
|
+
Pathname.new(".git/hooks/#{which}")
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.installed_hooks_path(which = :local)
|
30
|
+
installed_path(which) + "hooks"
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.installed_helpers_path(which = :local)
|
34
|
+
installed_path(which) + "helpers"
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.find_all(filters = {})
|
38
|
+
paths = installed_hooks_search_paths + available_hooks_search_paths
|
39
|
+
candidates = find_all_in_paths(paths)
|
40
|
+
filter_candidates(candidates, filters)
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.filter_candidates(candidates, filters = {})
|
44
|
+
filters.each do |field, value|
|
45
|
+
candidates = candidates.select { |c| c.send(field) == value }
|
46
|
+
end
|
47
|
+
candidates
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.find(name, options)
|
51
|
+
find_all(options.merge(:name => name)).first
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.find_all_in_paths(paths)
|
55
|
+
paths.map { |hook_path| Dir.glob(File.join(hook_path, "*")) }.flatten.map do |path|
|
56
|
+
Gitty::Hook.new(:path => path)
|
26
57
|
end
|
27
58
|
end
|
28
59
|
|
29
|
-
def
|
30
|
-
|
31
|
-
|
32
|
-
|
60
|
+
def self.extract_meta_data(string_or_io)
|
61
|
+
io = string_or_io.respond_to?(:readline) ? string_or_io : StringIO.new(string_or_io)
|
62
|
+
meta_yaml = ""
|
63
|
+
begin
|
64
|
+
while line = io.readline
|
65
|
+
next unless line.match(/^# (description.+)/)
|
66
|
+
meta_yaml = "#{$1}\n"
|
67
|
+
break
|
68
|
+
end
|
69
|
+
|
70
|
+
while line = io.readline
|
71
|
+
break unless line.match(/^#()$/) || line.match(/^# (.*?)$/)
|
72
|
+
meta_yaml << "#{$1}\n"
|
73
|
+
end
|
74
|
+
rescue EOFError
|
33
75
|
end
|
34
|
-
|
76
|
+
meta_yaml.empty? ? nil : YAML.load(meta_yaml)
|
35
77
|
end
|
36
78
|
|
37
|
-
def
|
38
|
-
|
39
|
-
opt_p.parse!(args)
|
40
|
-
puts opt_p
|
79
|
+
def installed?
|
80
|
+
install_kind ? true : false
|
41
81
|
end
|
42
|
-
|
82
|
+
alias installed installed?
|
83
|
+
|
84
|
+
def install_kind
|
85
|
+
case
|
86
|
+
when path.include?(self.class.installed_hooks_path(:local).to_s) then :local
|
87
|
+
when path.include?(self.class.installed_hooks_path(:shared).to_s) then :shared
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def name
|
92
|
+
File.basename(path)
|
93
|
+
end
|
94
|
+
|
95
|
+
def <=>(other)
|
96
|
+
path <=> other.path
|
97
|
+
end
|
98
|
+
|
99
|
+
def meta_data
|
100
|
+
@meta_data ||= self.class.extract_meta_data(File.read(path))
|
101
|
+
end
|
102
|
+
|
103
|
+
module AvailableHookStrategy
|
104
|
+
def install(which = :local)
|
105
|
+
target_hook_path = existing_directory!(self.class.installed_hooks_path(which))
|
106
|
+
target_helper_path = existing_directory!(self.class.installed_helpers_path(which))
|
107
|
+
base_directory = self.class.installed_path(which)
|
108
|
+
cp(path, target_hook_path + name)
|
109
|
+
chmod(0755, target_hook_path + name)
|
110
|
+
meta_data["targets"].each do |target|
|
111
|
+
ln_s(
|
112
|
+
"../hooks/#{name}",
|
113
|
+
file_with_existing_directory!(base_directory + "#{target}.d" + name)
|
114
|
+
)
|
115
|
+
end
|
116
|
+
(meta_data["helpers"] || []).each do |helper|
|
117
|
+
cp(Gitty.find_asset("helpers/#{helper}"), target_helper_path + helper)
|
118
|
+
chmod(0755, target_helper_path + helper)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def uninstall
|
123
|
+
# do nothing
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
module InstalledHookStrategy
|
128
|
+
def install(which = :local)
|
129
|
+
# do nothing
|
130
|
+
end
|
131
|
+
|
132
|
+
def uninstall
|
133
|
+
target_hook_path = path
|
134
|
+
base_directory = self.class.installed_path(install_kind)
|
135
|
+
meta_data["targets"].each { |target| rm_f(base_directory + "#{target}.d" + name) }
|
136
|
+
rm(target_hook_path)
|
137
|
+
# TODO - clean up helpers
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
private :path=
|
142
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
class Gitty::HookCommand < Gitty::Runner
|
2
|
+
COMMANDS = %w[
|
3
|
+
init
|
4
|
+
list
|
5
|
+
install
|
6
|
+
uninstall
|
7
|
+
publish
|
8
|
+
shell
|
9
|
+
]
|
10
|
+
COMMANDS.each do |cmd|
|
11
|
+
autoload cmd.classify.to_sym, (GITTY_PATH + "commands/#{cmd}.rb").to_s
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(args, stdout = STDOUT, stderr = STDERR)
|
15
|
+
@args, @stdout, @stderr = args, stdout, stderr
|
16
|
+
if COMMANDS.include?(args.first)
|
17
|
+
@target = Gitty::HookCommand.const_get(args.shift.classify).new(args, stdout, stderr)
|
18
|
+
else
|
19
|
+
parse_args!
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def option_parser
|
24
|
+
@option_parser ||= super.tap do |opts|
|
25
|
+
opts.banner = "Usage: git hook [command]\nCommands are: #{COMMANDS.join(', ')}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def run
|
30
|
+
unless File.directory?(".git")
|
31
|
+
stderr.puts "You must run git hook from the root of a git repository"
|
32
|
+
exit 1
|
33
|
+
end
|
34
|
+
@target && @target.run
|
35
|
+
end
|
36
|
+
|
37
|
+
def parse_args!
|
38
|
+
opt_p = option_parser
|
39
|
+
opt_p.parse!(args)
|
40
|
+
puts opt_p
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
require File.expand_path('../../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
describe Gitty::Hook do
|
4
|
+
def installed_hook(name, which = :local)
|
5
|
+
hook = Gitty::Hook.find(name, :installed => false)
|
6
|
+
hook.install(which)
|
7
|
+
Gitty::Hook.find(name, :installed => true)
|
8
|
+
end
|
9
|
+
|
10
|
+
before(:each) do
|
11
|
+
Gitty::Hook.stub!(:available_hooks_search_paths).and_return([SandboxWorld::GITTY_ASSETS + "hooks"])
|
12
|
+
create_file(SandboxWorld::GITTY_ASSETS + "hooks/submodule_updater", <<-EOF)
|
13
|
+
#!/bin/bash
|
14
|
+
# description: managers submodule updating for you
|
15
|
+
# targets: ["post-checkout", "post-merge"]
|
16
|
+
...
|
17
|
+
EOF
|
18
|
+
create_file(SandboxWorld::GITTY_ASSETS + "hooks/no_messy_whitespace", <<-EOF)
|
19
|
+
#!/bin/bash
|
20
|
+
# description: prevents you from committing messy whitespace
|
21
|
+
# targets: ["pre-commit"]
|
22
|
+
...
|
23
|
+
EOF
|
24
|
+
end
|
25
|
+
|
26
|
+
describe ".extract_meta_data" do
|
27
|
+
it "extracts meta data from a stream" do
|
28
|
+
stream = <<-EOF
|
29
|
+
#!/usr/bash
|
30
|
+
|
31
|
+
# description: |-
|
32
|
+
# hi
|
33
|
+
#
|
34
|
+
# bye
|
35
|
+
# targets: ["post-merge", "post-checkout"]
|
36
|
+
#
|
37
|
+
|
38
|
+
here's my hook
|
39
|
+
EOF
|
40
|
+
Gitty::Hook.extract_meta_data(stream).should == {
|
41
|
+
"description" => "hi\n\nbye",
|
42
|
+
"targets" => ["post-merge", "post-checkout"]
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
it "returns nil when no data found" do
|
47
|
+
stream = <<-EOF
|
48
|
+
#!/usr/bash
|
49
|
+
#
|
50
|
+
#
|
51
|
+
EOF
|
52
|
+
Gitty::Hook.extract_meta_data(stream).should == nil
|
53
|
+
end
|
54
|
+
|
55
|
+
it "returns the data when there's no actual content" do
|
56
|
+
stream = <<-EOF
|
57
|
+
#!/usr/bash
|
58
|
+
#
|
59
|
+
# description: hi
|
60
|
+
EOF
|
61
|
+
Gitty::Hook.extract_meta_data(stream).should == {"description" => "hi"}
|
62
|
+
end
|
63
|
+
end
|
64
|
+
describe ".find_all" do
|
65
|
+
it "returns all available hooks" do
|
66
|
+
Gitty::Hook.find_all(:installed => false).map(&:name).should == %w[no_messy_whitespace submodule_updater]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe ".find" do
|
71
|
+
it "returns an available hook by name" do
|
72
|
+
Gitty::Hook.find("submodule_updater", :installed => false).name.should == "submodule_updater"
|
73
|
+
Gitty::Hook.find("no_messy_whitespace", :installed => false).name.should == "no_messy_whitespace"
|
74
|
+
end
|
75
|
+
|
76
|
+
it "finds installed hooks" do
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe "#installed?" do
|
81
|
+
it "returns false if the hook is not installed" do
|
82
|
+
Gitty::Hook.find("submodule_updater", :installed => false).installed?.should be_false
|
83
|
+
end
|
84
|
+
|
85
|
+
it "returns true if the hook is installed" do
|
86
|
+
Gitty::Hook.find("submodule_updater", :installed => false).install(:local)
|
87
|
+
Gitty::Hook.find("submodule_updater", :installed => true).installed?.should == true
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe "#install_kind" do
|
92
|
+
it "returns :local for local hooks" do
|
93
|
+
installed_hook("submodule_updater", :local).install_kind.should == :local
|
94
|
+
end
|
95
|
+
|
96
|
+
it "returns :shared for shared hooks" do
|
97
|
+
installed_hook("submodule_updater", :shared).install_kind.should == :shared
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe "#meta_data" do
|
102
|
+
it "reads the meta_data of a given file" do
|
103
|
+
Gitty::Hook.find("submodule_updater", :installed => false).meta_data
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe "#install" do
|
108
|
+
it "copies an available hook to the install path and links it into the targets" do
|
109
|
+
@hook = Gitty::Hook.find("submodule_updater", :installed => false)
|
110
|
+
@hook.install
|
111
|
+
File.exist?(".git/hooks/local/hooks/submodule_updater").should be_true
|
112
|
+
File.executable?(".git/hooks/local/hooks/submodule_updater").should be_true
|
113
|
+
File.exist?(".git/hooks/local/post-checkout.d/submodule_updater").should be_true
|
114
|
+
File.exist?(".git/hooks/local/post-merge.d/submodule_updater").should be_true
|
115
|
+
end
|
116
|
+
|
117
|
+
it "installs a hook into shared" do
|
118
|
+
@hook = Gitty::Hook.find("submodule_updater", :installed => false)
|
119
|
+
@hook.install(:shared)
|
120
|
+
File.exist?(".git/hooks/shared/hooks/submodule_updater").should be_true
|
121
|
+
File.executable?(".git/hooks/shared/hooks/submodule_updater").should be_true
|
122
|
+
File.exist?(".git/hooks/shared/post-checkout.d/submodule_updater").should be_true
|
123
|
+
File.exist?(".git/hooks/shared/post-merge.d/submodule_updater").should be_true
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
describe "#uninstall" do
|
128
|
+
it "removes a hook from installed path" do
|
129
|
+
hook = installed_hook("submodule_updater")
|
130
|
+
File.exist?(".git/hooks/local/hooks/submodule_updater").should be_true
|
131
|
+
File.symlink?(".git/hooks/local/post-checkout.d/submodule_updater").should be_true
|
132
|
+
File.symlink?(".git/hooks/local/post-merge.d/submodule_updater").should be_true
|
133
|
+
hook.uninstall
|
134
|
+
File.exist?(".git/hooks/local/hooks/submodule_updater").should be_false
|
135
|
+
File.symlink?(".git/hooks/local/post-checkout.d/submodule_updater").should be_false
|
136
|
+
File.symlink?(".git/hooks/local/post-merge.d/submodule_updater").should be_false
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
data/spec/gitty_spec.rb
CHANGED
@@ -21,39 +21,4 @@ describe Gitty do
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
-
describe ".extract_meta_data" do
|
25
|
-
it "extracts meta data from a stream" do
|
26
|
-
stream = <<-EOF
|
27
|
-
#!/usr/bash
|
28
|
-
|
29
|
-
# description: hi
|
30
|
-
# targets: ["post-merge", "post-checkout"]
|
31
|
-
#
|
32
|
-
|
33
|
-
here's my hook
|
34
|
-
EOF
|
35
|
-
Gitty.extract_meta_data(stream).should == {
|
36
|
-
"description" => "hi",
|
37
|
-
"targets" => ["post-merge", "post-checkout"]
|
38
|
-
}
|
39
|
-
end
|
40
|
-
|
41
|
-
it "returns nil when no data found" do
|
42
|
-
stream = <<-EOF
|
43
|
-
#!/usr/bash
|
44
|
-
#
|
45
|
-
#
|
46
|
-
EOF
|
47
|
-
Gitty.extract_meta_data(stream).should == nil
|
48
|
-
end
|
49
|
-
|
50
|
-
it "returns the data when there's no actual content" do
|
51
|
-
stream = <<-EOF
|
52
|
-
#!/usr/bash
|
53
|
-
#
|
54
|
-
# description: hi
|
55
|
-
EOF
|
56
|
-
Gitty.extract_meta_data(stream).should == {"description" => "hi"}
|
57
|
-
end
|
58
|
-
end
|
59
24
|
end
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
CHANGED
@@ -1,6 +1,29 @@
|
|
1
1
|
require File.dirname(__FILE__) + "/../lib/gitty"
|
2
|
-
SPEC_PATH = GITTY_ROOT_PATH + "spec"
|
3
2
|
require 'rubygems'
|
4
|
-
require
|
3
|
+
require "spec"
|
4
|
+
SPEC_PATH = Pathname.new(File.dirname(__FILE__))
|
5
|
+
require SPEC_PATH + "../features/support/sandbox_world.rb"
|
5
6
|
require SPEC_PATH + "support/constants.rb"
|
6
|
-
|
7
|
+
|
8
|
+
|
9
|
+
require 'forwardable'
|
10
|
+
Spec::Runner.configure do |config|
|
11
|
+
extend Forwardable
|
12
|
+
def sandbox
|
13
|
+
@sandbox ||= SandboxWorld.new
|
14
|
+
end
|
15
|
+
|
16
|
+
[:run, :in_dir, :current_dir, :create_file, :last_exit_status, :last_stderr, :last_stdout, :reset_sandbox!].each do |m|
|
17
|
+
eval "def #{m}(*args) sandbox.send(:#{m}, *args) end"
|
18
|
+
end
|
19
|
+
|
20
|
+
config.before(:each) do
|
21
|
+
reset_sandbox!
|
22
|
+
@_original_dir = Dir.pwd
|
23
|
+
Dir.chdir(current_dir)
|
24
|
+
end
|
25
|
+
|
26
|
+
config.after(:each) do
|
27
|
+
Dir.chdir(@_original_dir)
|
28
|
+
end
|
29
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gitty
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tim Harper
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-02-
|
12
|
+
date: 2010-02-24 00:00:00 -08:00
|
13
13
|
default_executable: git-hook
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -32,27 +32,28 @@ files:
|
|
32
32
|
- assets/helpers/git-trash
|
33
33
|
- assets/helpers/git-when-introduced
|
34
34
|
- assets/helpers/hookd_wrapper
|
35
|
+
- assets/hooks/auto-submodules
|
35
36
|
- assets/hooks/clean-patches
|
36
|
-
- assets/hooks/git-post-checkout-submodules
|
37
37
|
- assets/hooks/git-prevent-messy-rebase
|
38
|
-
- assets/hooks/
|
38
|
+
- assets/hooks/nocommit
|
39
39
|
- bin/git-hook
|
40
40
|
- cucumber.yml
|
41
41
|
- lib/ext.rb
|
42
42
|
- lib/gitty.rb
|
43
|
-
- lib/gitty/commands/add.rb
|
44
43
|
- lib/gitty/commands/init.rb
|
44
|
+
- lib/gitty/commands/install.rb
|
45
45
|
- lib/gitty/commands/list.rb
|
46
|
-
- lib/gitty/commands/manager.rb
|
47
46
|
- lib/gitty/commands/publish.rb
|
48
|
-
- lib/gitty/commands/remove.rb
|
49
47
|
- lib/gitty/commands/shell.rb
|
48
|
+
- lib/gitty/commands/uninstall.rb
|
50
49
|
- lib/gitty/helpers.rb
|
51
50
|
- lib/gitty/hook.rb
|
51
|
+
- lib/gitty/hook_command.rb
|
52
52
|
- lib/gitty/runner.rb
|
53
53
|
- lib/string.rb
|
54
|
-
- spec/gitty/
|
54
|
+
- spec/gitty/hook_spec.rb
|
55
55
|
- spec/gitty_spec.rb
|
56
|
+
- spec/spec.opts
|
56
57
|
- spec/spec_helper.rb
|
57
58
|
- spec/support/constants.rb
|
58
59
|
has_rdoc: true
|
@@ -84,7 +85,7 @@ signing_key:
|
|
84
85
|
specification_version: 3
|
85
86
|
summary: Unobtrusively extend git
|
86
87
|
test_files:
|
87
|
-
- spec/gitty/
|
88
|
+
- spec/gitty/hook_spec.rb
|
88
89
|
- spec/gitty_spec.rb
|
89
90
|
- spec/spec_helper.rb
|
90
91
|
- spec/support/constants.rb
|
data/lib/gitty/commands/add.rb
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
require GITTY_PATH + "commands/manager"
|
2
|
-
|
3
|
-
class Gitty::Hook::Add < Gitty::Hook::Manager
|
4
|
-
include FileUtils
|
5
|
-
|
6
|
-
def run
|
7
|
-
cp(src_hook_file, master_hook_file)
|
8
|
-
chmod(0755, master_hook_file)
|
9
|
-
meta_data["targets"].each do |target|
|
10
|
-
ln_s(
|
11
|
-
"../hooks/#{@hookname}",
|
12
|
-
file_with_existing_directory!(base_directory + "#{target}.d" + @hookname)
|
13
|
-
)
|
14
|
-
end
|
15
|
-
(meta_data["helpers"] || []).each do |helper|
|
16
|
-
cp(Gitty.find_asset("helpers/#{helper}"), helpers_directory + helper)
|
17
|
-
chmod(0755, helpers_directory + helper)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
def option_parser
|
22
|
-
@option_parser ||= super.tap do |opts|
|
23
|
-
opts.banner = "Usage: git hook add [opts] hook-name"
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
@@ -1,50 +0,0 @@
|
|
1
|
-
class Gitty::Hook::Manager < Gitty::Runner
|
2
|
-
include ::Gitty::Helpers
|
3
|
-
def initialize(args, stdout = STDOUT, stderr = STDERR)
|
4
|
-
super
|
5
|
-
@hookname = args.shift
|
6
|
-
end
|
7
|
-
|
8
|
-
def options
|
9
|
-
@options ||= super.update(:kind => :local)
|
10
|
-
end
|
11
|
-
|
12
|
-
def src_hook_file
|
13
|
-
Gitty.find_asset("hooks/#{@hookname}")
|
14
|
-
end
|
15
|
-
|
16
|
-
def master_hook_file
|
17
|
-
@master_hook_file ||= hooks_directory + @hookname
|
18
|
-
end
|
19
|
-
|
20
|
-
def meta_data
|
21
|
-
@meta_data ||= Gitty.extract_meta_data(File.read(src_hook_file))
|
22
|
-
end
|
23
|
-
|
24
|
-
def run
|
25
|
-
raise NotImplementedError
|
26
|
-
end
|
27
|
-
|
28
|
-
def target_file(hook)
|
29
|
-
@target_file ||= file_with_existing_directory!(base_directory + "#{hook}.d/#{@hookname}")
|
30
|
-
end
|
31
|
-
|
32
|
-
def base_directory
|
33
|
-
@base_directory ||= existing_directory!(".git/hooks/#{options[:kind]}")
|
34
|
-
end
|
35
|
-
|
36
|
-
def helpers_directory
|
37
|
-
@helpers_directory ||= existing_directory!(".git/hooks/#{options[:kind]}/helpers")
|
38
|
-
end
|
39
|
-
|
40
|
-
def hooks_directory
|
41
|
-
existing_directory!(base_directory + "hooks")
|
42
|
-
end
|
43
|
-
|
44
|
-
def option_parser
|
45
|
-
@option_parser ||= super.tap do |opts|
|
46
|
-
opts.on("-l", "--local", "Local hook (default)") { |l| options[:kind] = :local }
|
47
|
-
opts.on("-s", "--shared", "Remote hook") { |l| options[:kind] = :shared }
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
require GITTY_PATH + "commands/manager"
|
2
|
-
class Gitty::Hook::Remove < Gitty::Hook::Manager
|
3
|
-
include FileUtils
|
4
|
-
def run
|
5
|
-
rm(master_hook_file)
|
6
|
-
meta_data["targets"].each do |target|
|
7
|
-
rm(target_file(target))
|
8
|
-
end
|
9
|
-
# TODO - cleanup helpers
|
10
|
-
end
|
11
|
-
|
12
|
-
def option_parser
|
13
|
-
@option_parser ||= super.tap do |opts|
|
14
|
-
opts.banner = "Usage: git hook remove [opts] hook-name"
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|