overcommit 0.15.0 → 0.16.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 043d9e4f69b46108c0de597ecf9640f31149c98e
4
- data.tar.gz: 9b61ce0b7846dae6580ec4d8934b4f2ec6484eab
3
+ metadata.gz: 9e7a230157adc2af8bc8cf4b209e6b50d99d67a7
4
+ data.tar.gz: 190432fe93e3a69293a69b93bbd75460923f72b1
5
5
  SHA512:
6
- metadata.gz: c4f4dc8af420e79565d242caf90eb37148fe7cbc4f1cd015627a4f8863a16f8237da519ed738c7620dff9c35b0a6f86614e5fae0923f0a4f1cb2c3f9f1fc2876
7
- data.tar.gz: e1fd1a72991e8e708503cf870c68f333c4321eab536e010bc80eb2cff2b1f116c10f8710a540697d3d4ecd202e3e16e4a326ab8f37ede4762d800323c5d8af71
6
+ metadata.gz: 4e98e7cbe0771bb681380819fc688d27c06b6106ebb884d8bbd71ef132a77916eacf8d4fe42b997e6d70edc868436c47a7a437215258d091e337fe2474b9d001
7
+ data.tar.gz: 8481d1109df9d34d2d6306fbfb56db74e20a002444d91775aba9d5553a3e149cb37b9a0dbfacd33868f7a328fcb1a55f5371fc3f22075e15da679329e7b1b37c
data/config/default.yml CHANGED
@@ -21,12 +21,6 @@ PostCheckout:
21
21
  ALL:
22
22
  required: false
23
23
  quiet: false
24
- BundleCheck:
25
- description: 'Checking Gemfile dependencies'
26
- include:
27
- - 'Gemfile'
28
- - 'Gemfile.lock'
29
- - '*.gemspec'
30
24
  IndexTags:
31
25
  description: 'Generating tags file from source'
32
26
  enabled: false
@@ -8,6 +8,9 @@ module Overcommit::Exceptions
8
8
  # Raised when a {HookContext} is unable to setup the environment before a run.
9
9
  class HookSetupFailed < StandardError; end
10
10
 
11
+ # Raised when a {HookContext} is unable to clean the environment after a run.
12
+ class HookCleanupFailed < StandardError; end
13
+
11
14
  # Raised when a hook run was cancelled by the user.
12
15
  class HookCancelled < StandardError; end
13
16
 
@@ -42,11 +42,11 @@ module Overcommit::HookContext
42
42
  # as if nothing ever changed.
43
43
  def cleanup_environment
44
44
  unless initial_commit? || (@stash_attempted && !@changes_stashed)
45
- `git reset --hard &> /dev/null` # Ensure working tree is clean before popping stash
45
+ clear_working_tree # Ensure working tree is clean before restoring it
46
46
  end
47
47
 
48
48
  if @changes_stashed
49
- `git stash pop --index --quiet`
49
+ restore_working_tree
50
50
  end
51
51
 
52
52
  Overcommit::GitRepo.restore_merge_state
@@ -69,6 +69,26 @@ module Overcommit::HookContext
69
69
 
70
70
  private
71
71
 
72
+ # Clears the working tree so that the stash can be applied.
73
+ def clear_working_tree
74
+ result = Overcommit::Utils.execute(%w[git reset --hard])
75
+ unless result.success?
76
+ raise Overcommit::Exceptions::HookCleanupFailed,
77
+ "Unable to cleanup working tree after #{hook_script_name} hooks run:" \
78
+ "\n#{result.stderr}"
79
+ end
80
+ end
81
+
82
+ # Applies the stash to the working tree to restore the user's state.
83
+ def restore_working_tree
84
+ result = Overcommit::Utils.execute(%w[git stash pop --index --quiet])
85
+ unless result.success?
86
+ raise Overcommit::Exceptions::HookCleanupFailed,
87
+ "Unable to restore working tree after #{hook_script_name} hooks run:" \
88
+ "\n#{result.stderr}"
89
+ end
90
+ end
91
+
72
92
  # Returns whether there are any changes to the working tree, staged or
73
93
  # otherwise.
74
94
  def any_changes?
@@ -17,13 +17,18 @@ module Overcommit
17
17
 
18
18
  # Loads and runs the hooks registered for this {HookRunner}.
19
19
  def run
20
+ # ASSUMPTION: we assume the setup and cleanup calls will never need to be
21
+ # interrupted, i.e. they will finish quickly. Should further evidence
22
+ # suggest this assumption does not hold, we will have to separately wrap
23
+ # these calls to allow some sort of "are you sure?" double-interrupt
24
+ # functionality, but until that's deemed necessary let's keep it simple.
20
25
  InterruptHandler.isolate_from_interrupts do
21
26
  @context.setup_environment
22
27
  load_hooks
23
- run_hooks
28
+ result = run_hooks
29
+ @context.cleanup_environment
30
+ result
24
31
  end
25
- ensure
26
- @context.cleanup_environment
27
32
  end
28
33
 
29
34
  private
@@ -63,20 +68,23 @@ module Overcommit
63
68
 
64
69
  @printer.start_hook(hook)
65
70
 
71
+ status, output = nil, nil
72
+
66
73
  begin
67
74
  # Disable the interrupt handler during individual hook run so that
68
75
  # Ctrl-C actually stops the current hook from being run, but doesn't
69
76
  # halt the entire process.
70
- InterruptHandler.disable!
71
- status, output = hook.run_and_transform
77
+ InterruptHandler.disable_until_finished_or_interrupted do
78
+ status, output = hook.run_and_transform
79
+ end
72
80
  rescue => ex
73
81
  status = :fail
74
82
  output = "Hook raised unexpected error\n#{ex.message}"
75
83
  rescue Interrupt
84
+ # At this point, interrupt has been handled and protection is back in
85
+ # effect thanks to the InterruptHandler.
76
86
  status = :interrupt
77
87
  output = 'Hook was interrupted by Ctrl-C; restoring repo state...'
78
- ensure
79
- InterruptHandler.enable!
80
88
  end
81
89
 
82
90
  @printer.end_hook(hook, status, output)
@@ -5,22 +5,65 @@ require 'singleton'
5
5
  class InterruptHandler
6
6
  include Singleton
7
7
 
8
- attr_accessor :isolate_signals, :signal_received
8
+ attr_accessor :isolate_signals, :signal_received, :reenable_on_interrupt
9
9
 
10
10
  def initialize
11
11
  self.isolate_signals = false
12
12
  self.signal_received = false
13
+ self.reenable_on_interrupt = false
13
14
 
14
15
  Signal.trap('INT') do
15
16
  if isolate_signals
16
17
  self.signal_received = true
17
18
  else
18
- raise Interrupt
19
+ if reenable_on_interrupt
20
+ self.reenable_on_interrupt = false
21
+ self.isolate_signals = true
22
+ end
23
+
24
+ raise Interrupt # Allow interrupt to propagate to code
19
25
  end
20
26
  end
21
27
  end
22
28
 
23
29
  class << self
30
+ # Provide a way to allow a single Ctrl-C interrupt to happen and atomically
31
+ # re-enable interrupt protections once that interrupt is propagated.
32
+ #
33
+ # This prevents a race condition where code like the following:
34
+ #
35
+ # begin
36
+ # InterruptHandler.disable!
37
+ # ... do stuff ...
38
+ # rescue Interrupt
39
+ # ... handle it ...
40
+ # ensure
41
+ # InterruptHandler.enable!
42
+ # end
43
+ #
44
+ # ...could have the `enable!` call to the interrupt handler not called in
45
+ # the event another interrupt was received in between the interrupt being
46
+ # handled and the `ensure` block being entered.
47
+ #
48
+ # Thus you should always write:
49
+ #
50
+ # begin
51
+ # InterruptHandler.disable_until_finished_or_interrupted do
52
+ # ... do stuff ...
53
+ # end
54
+ # rescue Interrupt
55
+ # ... handle it ...
56
+ # rescue
57
+ # ... handle any other exceptions ...
58
+ # end
59
+ def disable_until_finished_or_interrupted
60
+ instance.reenable_on_interrupt = true
61
+ instance.isolate_signals = false
62
+ yield
63
+ ensure
64
+ instance.isolate_signals = true
65
+ end
66
+
24
67
  def disable!
25
68
  instance.isolate_signals = false
26
69
  end
@@ -1,4 +1,4 @@
1
1
  # Defines the gem version.
2
2
  module Overcommit
3
- VERSION = '0.15.0'
3
+ VERSION = '0.16.0'
4
4
  end
@@ -4,6 +4,14 @@
4
4
  # in all of your git hooks being symlinked to this file, allowing the framework
5
5
  # to manage your hooks for you.
6
6
 
7
+ # Prevent a Ruby stack trace from appearing when we interrupt the hook.
8
+ # Note that this will be overridden when Overcommit is loaded, since the
9
+ # InterruptHandler will redefine the trap at that time.
10
+ Signal.trap('INT') do
11
+ puts 'Hook run interrupted'
12
+ exit 130
13
+ end
14
+
7
15
  # Required for Ruby 1.8 compatibility (for older OSX versions)
8
16
  if RUBY_VERSION.split('.')[0..1] == %w[1 8]
9
17
  require 'rubygems'
@@ -78,12 +86,13 @@ rescue Overcommit::Exceptions::HookContextLoadError => error
78
86
  puts error
79
87
  puts 'Are you running an old version of Overcommit?'
80
88
  exit 69 # EX_UNAVAILABLE
81
- rescue Overcommit::Exceptions::HookSetupFailed => error
82
- puts error
89
+ rescue Overcommit::Exceptions::HookSetupFailed,
90
+ Overcommit::Exceptions::HookCleanupFailed => error
91
+ puts error.message
83
92
  exit 74 # EX_IOERR
84
93
  rescue Overcommit::Exceptions::HookCancelled
85
94
  puts 'You cancelled the hook run'
86
- exit 1
95
+ exit 130 # Ctrl-C cancel
87
96
  rescue Overcommit::Exceptions::InvalidGitRepo => error
88
97
  puts error
89
98
  exit 64 # EX_USAGE
@@ -4,6 +4,14 @@
4
4
  # in all of your git hooks being symlinked to this file, allowing the framework
5
5
  # to manage your hooks for you.
6
6
 
7
+ # Prevent a Ruby stack trace from appearing when we interrupt the hook.
8
+ # Note that this will be overridden when Overcommit is loaded, since the
9
+ # InterruptHandler will redefine the trap at that time.
10
+ Signal.trap('INT') do
11
+ puts 'Hook run interrupted'
12
+ exit 130
13
+ end
14
+
7
15
  # Required for Ruby 1.8 compatibility (for older OSX versions)
8
16
  if RUBY_VERSION.split('.')[0..1] == %w[1 8]
9
17
  require 'rubygems'
@@ -78,12 +86,13 @@ rescue Overcommit::Exceptions::HookContextLoadError => error
78
86
  puts error
79
87
  puts 'Are you running an old version of Overcommit?'
80
88
  exit 69 # EX_UNAVAILABLE
81
- rescue Overcommit::Exceptions::HookSetupFailed => error
82
- puts error
89
+ rescue Overcommit::Exceptions::HookSetupFailed,
90
+ Overcommit::Exceptions::HookCleanupFailed => error
91
+ puts error.message
83
92
  exit 74 # EX_IOERR
84
93
  rescue Overcommit::Exceptions::HookCancelled
85
94
  puts 'You cancelled the hook run'
86
- exit 1
95
+ exit 130 # Ctrl-C cancel
87
96
  rescue Overcommit::Exceptions::InvalidGitRepo => error
88
97
  puts error
89
98
  exit 64 # EX_USAGE
@@ -4,6 +4,14 @@
4
4
  # in all of your git hooks being symlinked to this file, allowing the framework
5
5
  # to manage your hooks for you.
6
6
 
7
+ # Prevent a Ruby stack trace from appearing when we interrupt the hook.
8
+ # Note that this will be overridden when Overcommit is loaded, since the
9
+ # InterruptHandler will redefine the trap at that time.
10
+ Signal.trap('INT') do
11
+ puts 'Hook run interrupted'
12
+ exit 130
13
+ end
14
+
7
15
  # Required for Ruby 1.8 compatibility (for older OSX versions)
8
16
  if RUBY_VERSION.split('.')[0..1] == %w[1 8]
9
17
  require 'rubygems'
@@ -78,12 +86,13 @@ rescue Overcommit::Exceptions::HookContextLoadError => error
78
86
  puts error
79
87
  puts 'Are you running an old version of Overcommit?'
80
88
  exit 69 # EX_UNAVAILABLE
81
- rescue Overcommit::Exceptions::HookSetupFailed => error
82
- puts error
89
+ rescue Overcommit::Exceptions::HookSetupFailed,
90
+ Overcommit::Exceptions::HookCleanupFailed => error
91
+ puts error.message
83
92
  exit 74 # EX_IOERR
84
93
  rescue Overcommit::Exceptions::HookCancelled
85
94
  puts 'You cancelled the hook run'
86
- exit 1
95
+ exit 130 # Ctrl-C cancel
87
96
  rescue Overcommit::Exceptions::InvalidGitRepo => error
88
97
  puts error
89
98
  exit 64 # EX_USAGE
@@ -4,6 +4,14 @@
4
4
  # in all of your git hooks being symlinked to this file, allowing the framework
5
5
  # to manage your hooks for you.
6
6
 
7
+ # Prevent a Ruby stack trace from appearing when we interrupt the hook.
8
+ # Note that this will be overridden when Overcommit is loaded, since the
9
+ # InterruptHandler will redefine the trap at that time.
10
+ Signal.trap('INT') do
11
+ puts 'Hook run interrupted'
12
+ exit 130
13
+ end
14
+
7
15
  # Required for Ruby 1.8 compatibility (for older OSX versions)
8
16
  if RUBY_VERSION.split('.')[0..1] == %w[1 8]
9
17
  require 'rubygems'
@@ -78,12 +86,13 @@ rescue Overcommit::Exceptions::HookContextLoadError => error
78
86
  puts error
79
87
  puts 'Are you running an old version of Overcommit?'
80
88
  exit 69 # EX_UNAVAILABLE
81
- rescue Overcommit::Exceptions::HookSetupFailed => error
82
- puts error
89
+ rescue Overcommit::Exceptions::HookSetupFailed,
90
+ Overcommit::Exceptions::HookCleanupFailed => error
91
+ puts error.message
83
92
  exit 74 # EX_IOERR
84
93
  rescue Overcommit::Exceptions::HookCancelled
85
94
  puts 'You cancelled the hook run'
86
- exit 1
95
+ exit 130 # Ctrl-C cancel
87
96
  rescue Overcommit::Exceptions::InvalidGitRepo => error
88
97
  puts error
89
98
  exit 64 # EX_USAGE
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: overcommit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.15.0
4
+ version: 0.16.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Causes Engineering
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-07-28 00:00:00.000000000 Z
12
+ date: 2014-08-01 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: childprocess
@@ -94,7 +94,6 @@ files:
94
94
  - lib/overcommit/hook/commit_msg/hard_tabs.rb
95
95
  - lib/overcommit/hook/commit_msg/text_width.rb
96
96
  - lib/overcommit/hook/commit_msg/base.rb
97
- - lib/overcommit/hook/post_checkout/bundle_check.rb
98
97
  - lib/overcommit/hook/post_checkout/index_tags.rb
99
98
  - lib/overcommit/hook/post_checkout/base.rb
100
99
  - lib/overcommit/hook/base.rb
@@ -1,33 +0,0 @@
1
- module Overcommit::Hook::PostCheckout
2
- # If Gemfile dependencies were modified since HEAD was changed, check if
3
- # currently installed gems satisfy the dependencies.
4
- class BundleCheck < Base
5
- def run
6
- unless in_path?('bundle')
7
- return :warn, 'bundler not installed -- run `gem install bundler`'
8
- end
9
-
10
- if dependencies_changed? && !dependencies_satisfied?
11
- return :warn, "#{LOCK_FILE} is not up-to-date -- run `bundle check`"
12
- end
13
-
14
- :pass
15
- end
16
-
17
- private
18
-
19
- LOCK_FILE = 'Gemfile.lock'
20
-
21
- def dependencies_changed?
22
- result = execute(%w[git diff --exit-code --name-only] + [new_head, previous_head])
23
-
24
- result.stdout.split("\n").any? do |file|
25
- Array(config['include']).any? { |glob| Dir[glob].include?(file) }
26
- end
27
- end
28
-
29
- def dependencies_satisfied?
30
- execute(%w[bundle check]).success?
31
- end
32
- end
33
- end