gitty 0.3.7 → 0.4.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/README.textile CHANGED
@@ -13,9 +13,49 @@ Missing features:
13
13
 
14
14
  * Only receive hooks from trusted publishers. (currently when gitty is activated on a repository, any hook published to origin is automatically installed)
15
15
  * It's very young and might break
16
+ * Remote repository must be named origin for shared hooks to work. This is currently not configurable.
16
17
 
17
18
  h2. Documentation
18
19
 
20
+ h3. Initialization
21
+
22
+ To use gitty with a git repository, you need to install the basic gitty hooks.
23
+
24
+ <pre>
25
+ git hook init
26
+ </pre>
27
+
28
+ * Any existing hooks will be preserved. They are moved to .git/hooks/local/<hook-name>.d/original
29
+
30
+ h3. Enabling sharing
31
+
32
+ By default, it's turned off (security reasons). To enable it:
33
+
34
+ <pre>
35
+ git hook init --enable-sharing
36
+ </pre>
37
+
38
+ h3. Adding hooks
39
+
40
+ To see available hooks:
41
+
42
+ <pre>
43
+ git hook list
44
+ </pre>
45
+
46
+ To install one:
47
+
48
+ <pre>
49
+ git hook install <hook-name>
50
+ </pre>
51
+
52
+ To share one:
53
+
54
+ <pre>
55
+ git hook share <hook-name>
56
+ git hook publish -m "added <hook-name>"
57
+ </pre>
58
+
19
59
  Read the cucumber features for an idea of how it works and what it does
20
60
 
21
61
  h2. Issues
@@ -2,17 +2,7 @@
2
2
  dirname=$(dirname $0)
3
3
  hooktype=$(basename $0)
4
4
 
5
- # Check for updates. Since there is no post-fetch hook, we check before we're about to run a hook.
6
- remote_branch=$(git show-ref origin/--hooks--)
7
- [ -n "$remote_branch" ] && (
8
- cd ${dirname}/shared > /dev/null
9
- local_rev=$(GIT_OBJECT_DIRECTORY="../../objects" git rev-parse HEAD)
10
- [ "${remote_branch%% *}" != "$local_rev" ] && (
11
- echo "Hook updates were applied:" 1>&2
12
- GIT_OBJECT_DIRECTORY=../../objects git branch origin/--hooks-- ${remote_branch%% *} -f 1>&2
13
- GIT_OBJECT_DIRECTORY=../../objects git merge ${remote_branch%% *} 1>&2
14
- )
15
- )
5
+ [ -x "$dirname/gitty/update-shared-hooks" ] && . "$dirname/gitty/update-shared-hooks"
16
6
 
17
7
  for base_dir in "${dirname}"/{shared,local}; do
18
8
  [ -d "${base_dir}/${hooktype}.d" ] || continue
@@ -0,0 +1,22 @@
1
+ #!/bin/bash
2
+ # Check for updates. Since there is no post-fetch hook, we check before we're about to run a hook.
3
+ remote_branch=$(git show-ref origin/--hooks--)
4
+ [ -n "$remote_branch" ] && (
5
+ cd ${dirname}/shared > /dev/null
6
+ local_rev=$(GIT_OBJECT_DIRECTORY="../../objects" git rev-parse HEAD)
7
+ [ "${remote_branch%% *}" != "$local_rev" ] && (
8
+ echo "Hook updates were applied:" 1>&2
9
+ GIT_OBJECT_DIRECTORY=../../objects git branch origin/--hooks-- ${remote_branch%% *} -f 1>&2
10
+ # This is a bit of a hack. If we're in the middle of commit, we need to borrow the index. But don't worry, we'll put it back!
11
+ if [ -f ../../index.lock ]; then
12
+ mv ../../index.lock ../../index.lock_ 1>&2
13
+ mv ../../index ../../index_ 1>&2
14
+ fi
15
+ GIT_OBJECT_DIRECTORY=../../objects git reset HEAD 1>&2
16
+ GIT_OBJECT_DIRECTORY=../../objects git reset --hard origin/--hooks-- 1>&2
17
+ if [ -f ../../index.lock_ ]; then
18
+ mv ../../index.lock_ ../../index.lock 1>&2
19
+ mv ../../index_ ../../index 1>&2
20
+ fi
21
+ )
22
+ )
@@ -8,7 +8,7 @@
8
8
  # - If a submodule has been removed from the branch you move to, it alerts you
9
9
  # - If a submodule has been added on the branch you move to, it alerts you
10
10
  # - Otherwise, it checks out the revision for you
11
- # version: 0.2
11
+ # version: 0.3
12
12
  # targets: ["pre-rebase", "post-applypatch", "post-checkout", "post-merge"]
13
13
 
14
14
  # this is a bit of a hack: when a rebase is ran, we don't want to have the initial checkout update submodules
@@ -23,6 +23,7 @@ if File.exist?(".git/queue-rebase-run")
23
23
  exit 0
24
24
  end
25
25
 
26
+ # Not pretty... but well tested!! Refactor me.
26
27
  module GitMethods
27
28
  def chdir_parent
28
29
  Dir.chdir('..') until File.directory?('.git') || Dir.pwd == '/'
@@ -97,12 +98,12 @@ previous_submodules = list_submodules('HEAD@{1}')
97
98
  end
98
99
  end
99
100
  if ref.match(/^refs\/heads/)
100
- system("git checkout -q '#{File.basename(ref)}'")
101
+ output = %x(git checkout '#{File.basename(ref)}' 2>&1)
101
102
  if $? == 0
102
- STDERR.puts "Checked out #{File.basename(ref)}"
103
+ STDERR.puts "Switched to branch #{File.basename(ref)}"
103
104
  exit 0
104
105
  else
105
- STDERR.puts "Couldn't update submodule."
106
+ STDERR.puts "Couldn't update submodule: #{output}"
106
107
  exit $?
107
108
  end
108
109
  end
@@ -114,7 +115,11 @@ previous_submodules = list_submodules('HEAD@{1}')
114
115
  divergent_commits=%x{git rev-list #{ref}..#{local_ref}}.strip
115
116
  if divergent_commits.empty?
116
117
  STDERR.puts "fastforwarding #{local_ref} to #{ref}"
117
- system("git branch -f #{local_ref} #{ref}")
118
+ if File.read(".git/HEAD").include?("ref: refs/heads/#{local_ref}")
119
+ system("git merge #{ref}")
120
+ else
121
+ system("git branch -f #{local_ref} #{ref}")
122
+ end
118
123
  exec("git checkout #{local_ref}")
119
124
  end
120
125
  end
@@ -1,6 +1,7 @@
1
1
  require 'fileutils'
2
2
  class Gitty::HookCommand::Init < Gitty::Runner
3
3
  include ::Gitty::Helpers
4
+ include FileUtils
4
5
 
5
6
  CLIENT_HOOKS = %w[
6
7
  applypatch-msg
@@ -17,12 +18,23 @@ class Gitty::HookCommand::Init < Gitty::Runner
17
18
  ]
18
19
  def run
19
20
  puts "Initializing with gitty"
20
- FileUtils.mkdir_p(".git/hooks/shared")
21
- FileUtils.mkdir_p(".git/hooks/local")
21
+ # MESSY!
22
+ mkdir_p(".git/hooks/gitty")
23
+ mkdir_p(".git/hooks/shared")
24
+ mkdir_p(".git/hooks/local")
25
+ cp((ASSETS_PATH + "helpers/hookd_wrapper").to_s, ".git/hooks/gitty/hookd_wrapper")
26
+ chmod(0755, ".git/hooks/gitty/hookd_wrapper")
27
+ if options[:sharing]
28
+ cp((ASSETS_PATH + "helpers/update-shared-hooks").to_s, ".git/hooks/gitty/update-shared-hooks")
29
+ chmod(0755, ".git/hooks/gitty/update-shared-hooks")
30
+ end
22
31
 
23
32
  CLIENT_HOOKS.each do |hook|
24
- FileUtils.cp((ASSETS_PATH + "helpers/hookd_wrapper").to_s, ".git/hooks/#{hook}")
25
- FileUtils.chmod(0755, ".git/hooks/#{hook}")
33
+ if File.exist?(".git/hooks/#{hook}")
34
+ mkdir_p(".git/hooks/local/#{hook}.d")
35
+ mv(".git/hooks/#{hook}", ".git/hooks/local/#{hook}.d/original")
36
+ end
37
+ ln_sf("gitty/hookd_wrapper", ".git/hooks/#{hook}")
26
38
  end
27
39
 
28
40
  hooks_rev = remote_hooks_rev
@@ -43,6 +55,9 @@ class Gitty::HookCommand::Init < Gitty::Runner
43
55
  def option_parser
44
56
  super.tap do |opts|
45
57
  opts.banner = "Usage: git hook init"
58
+ opts.on("-s", "--enable-sharing", "Enable sharing") do
59
+ options[:sharing] = true
60
+ end
46
61
  end
47
62
  end
48
63
 
@@ -11,22 +11,13 @@ class Gitty::HookCommand::Install < Gitty::Runner
11
11
  stderr.puts "no hook named '#{@hookname}' found."
12
12
  exit 1
13
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)
14
+ hook.install(:local)
15
+ stdout.puts "#hook #{hook.name} has been installed."
23
16
  end
24
17
 
25
18
  def option_parser
26
19
  @option_parser ||= super.tap do |opts|
27
20
  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
21
  end
31
22
  end
32
23
  end
@@ -0,0 +1,34 @@
1
+ class Gitty::HookCommand::Share < 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, :install_kind => :local) || Gitty::Hook.find(@hookname, :installed => false)
10
+ if hook.nil?
11
+ stderr.puts "no hook named '#{@hookname}' is available"
12
+ exit 1
13
+ end
14
+ if hook.install_kind == :shared
15
+ stderr.puts "hook #{@hookname} is already installed"
16
+ exit 1
17
+ end
18
+ unless Gitty.sharing_enabled?
19
+ stderr.puts "WARNING: sharing is disabled on your repository. Run git hook init --enable-sharing to turn it on."
20
+ end
21
+ hook.share!
22
+ stdout.puts "To propagate this change other developers, run 'git hook publish -m \"added #{hook.name}...\""
23
+ end
24
+
25
+ def options
26
+ @options ||= super.update(:kind => :local)
27
+ end
28
+
29
+ def option_parser
30
+ @option_parser ||= super.tap do |opts|
31
+ opts.banner = "Usage: git hook install [opts] hook-name"
32
+ end
33
+ end
34
+ end
data/lib/gitty/hook.rb CHANGED
@@ -100,28 +100,49 @@ class Gitty::Hook
100
100
  @meta_data ||= self.class.extract_meta_data(File.read(path))
101
101
  end
102
102
 
103
+ protected
104
+ def copy_to(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_sf(
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 destroy
123
+ target_hook_path = path
124
+ base_directory = self.class.installed_path(install_kind)
125
+ meta_data["targets"].each do |target|
126
+ targetd_path = base_directory + "#{target}.d"
127
+ rm_f(targetd_path + name)
128
+ FileUtils.rmdir(targetd_path) if Dir.glob((targetd_path + "*").to_s).empty?
129
+ end
130
+ rm(target_hook_path)
131
+ # TODO - clean up helpers
132
+ end
133
+
103
134
  module AvailableHookStrategy
104
135
  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_sf(
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
136
+ copy_to(which)
120
137
  end
121
138
 
122
139
  def uninstall
123
140
  # do nothing
124
141
  end
142
+
143
+ def share!
144
+ copy_to(:shared)
145
+ end
125
146
  end
126
147
 
127
148
  module InstalledHookStrategy
@@ -130,15 +151,13 @@ class Gitty::Hook
130
151
  end
131
152
 
132
153
  def uninstall
133
- target_hook_path = path
134
- base_directory = self.class.installed_path(install_kind)
135
- meta_data["targets"].each do |target|
136
- targetd_path = base_directory + "#{target}.d"
137
- rm_f(targetd_path + name)
138
- FileUtils.rmdir(targetd_path) if Dir.glob((targetd_path + "*").to_s).empty?
139
- end
140
- rm(target_hook_path)
141
- # TODO - clean up helpers
154
+ destroy
155
+ end
156
+
157
+ def share!
158
+ return nil if install_kind == :shared
159
+ copy_to(:shared)
160
+ destroy
142
161
  end
143
162
  end
144
163
 
@@ -2,6 +2,7 @@ class Gitty::HookCommand < Gitty::Runner
2
2
  COMMANDS = %w[
3
3
  init
4
4
  list
5
+ share
5
6
  show
6
7
  install
7
8
  uninstall
data/lib/gitty.rb CHANGED
@@ -26,6 +26,10 @@ module Gitty
26
26
  end
27
27
  nil
28
28
  end
29
+
30
+ def self.sharing_enabled?
31
+ File.exist?(".git/hooks/gitty/update-shared-hooks")
32
+ end
29
33
  end
30
34
 
31
35
  require "gitty/runner.rb"
@@ -138,4 +138,19 @@ EOF
138
138
  File.directory?(".git/hooks/local/post-merge.d").should be_false
139
139
  end
140
140
  end
141
+
142
+ describe "#share" do
143
+ it "copies the hook straight to shared when uninstalled" do
144
+ hook = Gitty::Hook.find("submodule_updater")
145
+ hook.share!
146
+ Gitty::Hook.find("submodule_updater", :install_kind => :shared).should_not be_nil
147
+ end
148
+
149
+ it "copies the hook to shared and uninstalls the :local copy" do
150
+ hook = installed_hook("submodule_updater")
151
+ hook.share!
152
+ Gitty::Hook.find("submodule_updater", :install_kind => :local).should be_nil
153
+ Gitty::Hook.find("submodule_updater", :install_kind => :shared).should_not be_nil
154
+ end
155
+ end
141
156
  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.3.7
4
+ version: 0.4.2
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-03-10 00:00:00 -07:00
12
+ date: 2010-03-12 00:00:00 -07:00
13
13
  default_executable: git-hook
14
14
  dependencies: []
15
15
 
@@ -32,6 +32,7 @@ files:
32
32
  - assets/helpers/git-trash
33
33
  - assets/helpers/git-when-introduced
34
34
  - assets/helpers/hookd_wrapper
35
+ - assets/helpers/update-shared-hooks
35
36
  - assets/hooks/auto-submodules
36
37
  - assets/hooks/clean-patches
37
38
  - assets/hooks/git-prevent-messy-rebase
@@ -44,6 +45,7 @@ files:
44
45
  - lib/gitty/commands/install.rb
45
46
  - lib/gitty/commands/list.rb
46
47
  - lib/gitty/commands/publish.rb
48
+ - lib/gitty/commands/share.rb
47
49
  - lib/gitty/commands/shell.rb
48
50
  - lib/gitty/commands/show.rb
49
51
  - lib/gitty/commands/uninstall.rb