gitty 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README.textile +21 -0
- data/Rakefile +29 -0
- data/assets/helpers/git-cleanup-branches +151 -0
- data/assets/helpers/git-strip-new-whitespace +30 -0
- data/assets/helpers/git-submodule-helper +262 -0
- data/assets/helpers/git-trash +26 -0
- data/assets/helpers/git-when-introduced +16 -0
- data/assets/helpers/hookd_wrapper +22 -0
- data/assets/hooks/clean-patches +43 -0
- data/assets/hooks/git-post-checkout-submodules +74 -0
- data/assets/hooks/git-prevent-messy-rebase +17 -0
- data/assets/hooks/prevent-nocommit-tags +11 -0
- data/bin/git-hook +4 -0
- data/cucumber.yml +1 -0
- data/lib/ext.rb +16 -0
- data/lib/gitty.rb +55 -0
- data/lib/gitty/commands/add.rb +26 -0
- data/lib/gitty/commands/init.rb +55 -0
- data/lib/gitty/commands/list.rb +67 -0
- data/lib/gitty/commands/manager.rb +50 -0
- data/lib/gitty/commands/publish.rb +34 -0
- data/lib/gitty/commands/remove.rb +17 -0
- data/lib/gitty/commands/shell.rb +32 -0
- data/lib/gitty/helpers.rb +21 -0
- data/lib/gitty/hook.rb +42 -0
- data/lib/gitty/runner.rb +44 -0
- data/lib/string.rb +13 -0
- data/spec/gitty/commands/add_spec.rb +5 -0
- data/spec/gitty_spec.rb +59 -0
- data/spec/spec_helper.rb +6 -0
- data/spec/support/constants.rb +1 -0
- metadata +90 -0
@@ -0,0 +1,50 @@
|
|
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
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class Gitty::Hook::Publish < Gitty::Runner
|
2
|
+
include ::Gitty::Helpers
|
3
|
+
|
4
|
+
def run
|
5
|
+
rev = nil
|
6
|
+
puts "Publishing with message #{options[:message].inspect}"
|
7
|
+
with_env_var("GIT_OBJECT_DIRECTORY", File.join(Dir.pwd, ".git/objects")) do
|
8
|
+
Dir.chdir(".git/hooks/shared") do
|
9
|
+
cmd(*%w[git add . -A])
|
10
|
+
cmd(*%w[git commit -m].push(options[:message]))
|
11
|
+
rev = %x{git rev-parse HEAD}.chomp
|
12
|
+
end
|
13
|
+
end
|
14
|
+
# back on the mother repo...
|
15
|
+
cmd(*%w[git push origin -f].push("#{rev}:refs/heads/--hooks--"))
|
16
|
+
end
|
17
|
+
|
18
|
+
protected
|
19
|
+
def option_parser
|
20
|
+
@option_parser ||= super.tap do |opts|
|
21
|
+
opts.banner = "Usage: git hook publish [options]"
|
22
|
+
opts.on("-m [message]", "--message [message]", "Message for commit (required)") do |m|
|
23
|
+
options[:message] = m
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def parse_args!
|
29
|
+
super
|
30
|
+
if options[:message].nil?
|
31
|
+
puts option_parser
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,17 @@
|
|
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
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
class Gitty::Hook::Shell < Gitty::Runner
|
3
|
+
include ::Gitty::Helpers
|
4
|
+
|
5
|
+
def run
|
6
|
+
exec "bash --init-file #{create_init_file}"
|
7
|
+
end
|
8
|
+
|
9
|
+
def create_init_file
|
10
|
+
"/tmp/gitty-shell-init".tap do |filename|
|
11
|
+
File.open(filename, "wb") do |f|
|
12
|
+
f.puts(<<-EOF)
|
13
|
+
pushd $HOME > /dev/null
|
14
|
+
[ -f $HOME/.bashrc ] && . $HOME/.bashrc
|
15
|
+
[ -f $HOME/.bash_profile ] && . $HOME/.bash_profile
|
16
|
+
popd > /dev/null
|
17
|
+
export GIT_OBJECT_DIRECTORY="$(pwd)/.git/objects"
|
18
|
+
|
19
|
+
export PS1="Shared Hooks [$(basename $(pwd))]$ "
|
20
|
+
cd .git/hooks/shared
|
21
|
+
rm "#{filename}"
|
22
|
+
EOF
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def option_parser
|
28
|
+
super.tap do |opts|
|
29
|
+
opts.banner = "Usage: git hook shell"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Gitty::Helpers
|
2
|
+
def existing_directory!(dir)
|
3
|
+
FileUtils.mkdir_p(dir)
|
4
|
+
Pathname.new(dir)
|
5
|
+
end
|
6
|
+
|
7
|
+
def file_with_existing_directory!(path)
|
8
|
+
FileUtils.mkdir_p(File.dirname(path))
|
9
|
+
Pathname.new(path)
|
10
|
+
end
|
11
|
+
|
12
|
+
def with_env_var(name, value, &block)
|
13
|
+
previous_value, ENV[name] = ENV[name], value
|
14
|
+
yield
|
15
|
+
ENV[name] = previous_value
|
16
|
+
end
|
17
|
+
|
18
|
+
def cmd(*args)
|
19
|
+
system(*args.flatten)
|
20
|
+
end
|
21
|
+
end
|
data/lib/gitty/hook.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
class Gitty::Hook < Gitty::Runner
|
2
|
+
COMMANDS = %w[
|
3
|
+
init
|
4
|
+
list
|
5
|
+
add
|
6
|
+
remove
|
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::Hook.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
|
data/lib/gitty/runner.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require "optparse"
|
2
|
+
class Gitty::Runner
|
3
|
+
attr_reader :stdout, :stderr, :args
|
4
|
+
|
5
|
+
def initialize(args, stdout = STDOUT, stderr = STDERR)
|
6
|
+
@args, @stdout, @stderr = args, stdout, stderr
|
7
|
+
parse_args!
|
8
|
+
end
|
9
|
+
|
10
|
+
def options
|
11
|
+
@options ||= {}
|
12
|
+
end
|
13
|
+
|
14
|
+
def run
|
15
|
+
raise NotImplementedError
|
16
|
+
end
|
17
|
+
|
18
|
+
def option_parser
|
19
|
+
@option_parser ||= OptionParser.new do |opts|
|
20
|
+
opts.banner = "Usage: #{$0}"
|
21
|
+
opts.separator "Options:"
|
22
|
+
opts.on('--help', "Show help") do |h|
|
23
|
+
@show_help = opts
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def handle_show_help
|
29
|
+
if @show_help
|
30
|
+
puts @show_help
|
31
|
+
exit(1)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.run(args, stdout = STDOUT, stderr = STDERR)
|
36
|
+
new(args, stdout, stderr).run
|
37
|
+
end
|
38
|
+
|
39
|
+
protected
|
40
|
+
def parse_args!
|
41
|
+
option_parser.parse!(args)
|
42
|
+
handle_show_help
|
43
|
+
end
|
44
|
+
end
|
data/lib/string.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
class String
|
2
|
+
def constantize
|
3
|
+
Object.module_eval("::" + self)
|
4
|
+
end
|
5
|
+
|
6
|
+
def underscore
|
7
|
+
gsub(/(^|\b)[A-Z]/) { |l| l.downcase}.gsub(/[A-Z]/) { |l| "_#{l.downcase}" }.gsub("::", "/")
|
8
|
+
end
|
9
|
+
|
10
|
+
def classify
|
11
|
+
gsub(/^[a-z]/) { |l| l.upcase}.gsub(/_[a-z]/) { |l| l[1..1].upcase}.gsub(/\b[a-z]/) {|l| l.upcase}.gsub("/", "::")
|
12
|
+
end
|
13
|
+
end
|
data/spec/gitty_spec.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Gitty do
|
4
|
+
describe ".asset_file" do
|
5
|
+
it "searches first in the specified $GITTY_ASSETS environment variable" do
|
6
|
+
ENV.stub!(:[]).with("GITTY_ASSETS").and_return("/tmp/assets")
|
7
|
+
File.stub!(:exist?).with("/tmp/assets/helpers/helpful").and_return(true)
|
8
|
+
File.stub!(:exist?).with(ASSETS_PATH + "helpers/helpful").and_return(true)
|
9
|
+
|
10
|
+
Gitty.find_asset("helpers/helpful").should == "/tmp/assets/helpers/helpful"
|
11
|
+
end
|
12
|
+
|
13
|
+
it "searches the core ASSETS_PATH if GITTY_ASSETS is not defined" do
|
14
|
+
ENV.stub!(:[]).with("GITTY_ASSETS").and_return(nil)
|
15
|
+
File.stub!(:exist?).with((ASSETS_PATH + "helpers/helpful").to_s).and_return(true)
|
16
|
+
Gitty.find_asset("helpers/helpful").should == (ASSETS_PATH + "helpers/helpful").to_s
|
17
|
+
end
|
18
|
+
|
19
|
+
it "returns nil if none the file is not found" do
|
20
|
+
Gitty.find_asset("willy/wonka").should be_nil
|
21
|
+
end
|
22
|
+
end
|
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
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
BIN_PATH = GITTY_LIB_PATH + "../bin"
|
metadata
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: gitty
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tim Harper
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-02-21 00:00:00 -07:00
|
13
|
+
default_executable: git-hook
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Unobtrusively extend git
|
17
|
+
email: timcharper@gmail.com
|
18
|
+
executables:
|
19
|
+
- git-hook
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- LICENSE
|
24
|
+
- README.textile
|
25
|
+
files:
|
26
|
+
- LICENSE
|
27
|
+
- README.textile
|
28
|
+
- Rakefile
|
29
|
+
- assets/helpers/git-cleanup-branches
|
30
|
+
- assets/helpers/git-strip-new-whitespace
|
31
|
+
- assets/helpers/git-submodule-helper
|
32
|
+
- assets/helpers/git-trash
|
33
|
+
- assets/helpers/git-when-introduced
|
34
|
+
- assets/helpers/hookd_wrapper
|
35
|
+
- assets/hooks/clean-patches
|
36
|
+
- assets/hooks/git-post-checkout-submodules
|
37
|
+
- assets/hooks/git-prevent-messy-rebase
|
38
|
+
- assets/hooks/prevent-nocommit-tags
|
39
|
+
- bin/git-hook
|
40
|
+
- cucumber.yml
|
41
|
+
- lib/ext.rb
|
42
|
+
- lib/gitty.rb
|
43
|
+
- lib/gitty/commands/add.rb
|
44
|
+
- lib/gitty/commands/init.rb
|
45
|
+
- lib/gitty/commands/list.rb
|
46
|
+
- lib/gitty/commands/manager.rb
|
47
|
+
- lib/gitty/commands/publish.rb
|
48
|
+
- lib/gitty/commands/remove.rb
|
49
|
+
- lib/gitty/commands/shell.rb
|
50
|
+
- lib/gitty/helpers.rb
|
51
|
+
- lib/gitty/hook.rb
|
52
|
+
- lib/gitty/runner.rb
|
53
|
+
- lib/string.rb
|
54
|
+
- spec/gitty/commands/add_spec.rb
|
55
|
+
- spec/gitty_spec.rb
|
56
|
+
- spec/spec_helper.rb
|
57
|
+
- spec/support/constants.rb
|
58
|
+
has_rdoc: true
|
59
|
+
homepage: http://github.com/timcharper/gitty
|
60
|
+
licenses: []
|
61
|
+
|
62
|
+
post_install_message:
|
63
|
+
rdoc_options:
|
64
|
+
- --charset=UTF-8
|
65
|
+
require_paths:
|
66
|
+
- lib
|
67
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: "0"
|
72
|
+
version:
|
73
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: "0"
|
78
|
+
version:
|
79
|
+
requirements: []
|
80
|
+
|
81
|
+
rubyforge_project:
|
82
|
+
rubygems_version: 1.3.5
|
83
|
+
signing_key:
|
84
|
+
specification_version: 3
|
85
|
+
summary: Unobtrusively extend git
|
86
|
+
test_files:
|
87
|
+
- spec/gitty/commands/add_spec.rb
|
88
|
+
- spec/gitty_spec.rb
|
89
|
+
- spec/spec_helper.rb
|
90
|
+
- spec/support/constants.rb
|