git-hooks 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3e9ac25d07132d4f6863fd59f76a6701a50f722e
4
- data.tar.gz: 49d1ca7b2397c04777d52e2b4640a5adab33ba63
3
+ metadata.gz: 1eb1b43db79e2fee7f1e80b606a5f179d9ef6e01
4
+ data.tar.gz: 4c406f7fa4c304979c38479a7b7e3aee4e3775d1
5
5
  SHA512:
6
- metadata.gz: 7a098c47f8872d7e8ecc6ac350d791d07f760e5e316e00a956b6dd9bd238b8582687b6218e55289d3b5de9fa7b0b4ad73875cf4c3ed5de25a054e5c79793ace1
7
- data.tar.gz: 2927c77962ac840deac371dc161de5cf7502e76082df7ee183bfb626dc383ada485c353fbc94ed526ab758787da93e8908b4c1b882b58a76cfa506b63a838952
6
+ metadata.gz: 8e738a492bf589e366da29a5355a85c54c5d7990e369b0479f2cd3a325b7c78b619bd1d0df26fb25932fdcc19ca30ae600699ffd9b9689f58b26d57f897a4eb8
7
+ data.tar.gz: ce5edbedf28705755913ef38b183ad64d8e60fe58dec7837be37350ff0779aad3c49213932ced1c7d755f476bc9e355b1142150702ee9904c05374c902dcebbe
@@ -0,0 +1,8 @@
1
+ ---
2
+ pre_commits:
3
+ GitHooks::PreCommit::TrailingWhitespace:
4
+ GitHooks::PreCommit::PreventDebugger:
5
+ GitHooks::PreCommit::PreventMaster:
6
+ GitHooks::PreCommit::Rubocop:
7
+ use_stash: true
8
+ GitHooks::PreCommit::Rspec:
@@ -2,4 +2,6 @@ language: ruby
2
2
  rvm:
3
3
  - '2.0.0'
4
4
  - '2.1.0'
5
+ - '2.1.5'
6
+ - '2.2.0'
5
7
  script: bundle exec rspec
data/README.md CHANGED
@@ -6,8 +6,8 @@
6
6
 
7
7
  # GitHooks
8
8
 
9
- Some usefull git hooks, it's written on ruby but can be used for other
10
- languages.
9
+ This gem provides an interface to write useful git hooks in Ruby. Those hooks
10
+ can be used when working in projects in any programming language.
11
11
 
12
12
  ## Installation
13
13
 
@@ -48,17 +48,21 @@ By now you will find the following built-in hooks:
48
48
  - Prevent commits with debugger.
49
49
  - Prevent commits with trailing white space.
50
50
 
51
+ ### Warning about `Rubocop` pre-commit `use_stash` option:
52
+
53
+ This feature is yet experimental. Be aware that in some odd circumstances you
54
+ may encounter merge conflicts when applying the stash.
55
+
51
56
  ### Ensure hooks existence
52
57
 
53
- To ensure that hooks exists on `.git/hooks`, include this line
58
+ To ensure that hooks exists on `.git/hooks`, include the following line on your
59
+ application's start-up code (e.g. `config/environments/development.rb` or
60
+ `config/environments/test.rb` for a rails app).
54
61
 
55
62
  ```ruby
56
63
  GitHooks.validate_hooks!
57
64
  ```
58
65
 
59
- on your application's start up (e.g. `config/environments/development.rb` or
60
- `config/environments/test.rb` for a rails app).
61
-
62
66
  This will force `git_hooks` installation before your application's start.
63
67
 
64
68
  ## Contributing
@@ -0,0 +1,4 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
@@ -1,7 +1,8 @@
1
1
  ---
2
2
  pre_commits:
3
- - GitHooks::PreCommit::TrailingWhitespace
4
- - GitHooks::PreCommit::PreventDebugger
5
- - GitHooks::PreCommit::PreventMaster
6
- - GitHooks::PreCommit::Rubocop
7
- - GitHooks::PreCommit::Rspec
3
+ GitHooks::PreCommit::TrailingWhitespace:
4
+ GitHooks::PreCommit::PreventDebugger:
5
+ GitHooks::PreCommit::PreventMaster:
6
+ GitHooks::PreCommit::Rubocop:
7
+ use_stash: false
8
+ GitHooks::PreCommit::Rspec:
@@ -1,4 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
  require 'git-hooks'
3
3
 
4
+ puts 'Running pre-commit hooks...'
5
+
4
6
  GitHooks.execute_pre_commits
@@ -24,9 +24,10 @@ module GitHooks
24
24
  attr_writer :configurations
25
25
 
26
26
  def execute_pre_commits
27
- configurations.pre_commits.each do |pre_commit|
27
+ configurations.pre_commits.each do |pre_commit, options|
28
28
  puts "Executing #{pre_commit}"
29
- GitHooks::PreCommit.const_get(pre_commit).validate
29
+ pre_commit_checker = GitHooks::PreCommit.const_get(pre_commit)
30
+ pre_commit_checker.validate(options)
30
31
  end
31
32
  end
32
33
 
@@ -54,3 +55,19 @@ module GitHooks
54
55
  end
55
56
  end
56
57
  end
58
+
59
+ # TODO: Fix this in the ruby-git gem.
60
+
61
+ # Since the `Git` gem does not provide us with an api that allows you to use the
62
+ # '--keep-index' option when stashing, we are stuck with this monkey patch.
63
+ module Git
64
+ class Lib
65
+ def stash_pop(_ = nil)
66
+ command('stash pop')
67
+ end
68
+
69
+ def stash_save(message)
70
+ command('stash save', ['--keep-index', message])
71
+ end
72
+ end
73
+ end
@@ -3,7 +3,7 @@ module GitHooks
3
3
  class PreventDebugger
4
4
  attr_reader :git_repository
5
5
 
6
- def self.validate
6
+ def self.validate(*)
7
7
  new(GitHooks.configurations.git_repository).validate
8
8
  end
9
9
 
@@ -3,7 +3,7 @@ module GitHooks
3
3
  class PreventMaster
4
4
  attr_reader :git_repository
5
5
 
6
- def self.validate
6
+ def self.validate(*)
7
7
  new(GitHooks.configurations.git_repository).validate
8
8
  end
9
9
 
@@ -1,16 +1,16 @@
1
1
  module GitHooks
2
2
  module PreCommit
3
3
  class Rspec
4
- attr_reader :git_repository, :rspec_executor
5
-
6
- def self.validate
4
+ def self.validate(*)
7
5
  new(
8
- GitHooks.configurations.git_repository, RspecExecutor.new
6
+ GitHooks.configurations.git_repository,
7
+ RspecExecutor.new
9
8
  ).validate
10
9
  end
11
10
 
12
11
  def initialize(git_repository, rspec_executor)
13
- @git_repository, @rspec_executor = git_repository, rspec_executor
12
+ @git_repository = git_repository
13
+ @rspec_executor = rspec_executor
14
14
  end
15
15
 
16
16
  def validate
@@ -18,6 +18,10 @@ module GitHooks
18
18
 
19
19
  abort 'Prevented broken commit' if rspec_executor.errors?
20
20
  end
21
+
22
+ protected
23
+
24
+ attr_reader :git_repository, :rspec_executor
21
25
  end
22
26
  end
23
27
  end
@@ -1,32 +1,73 @@
1
1
  module GitHooks
2
2
  module PreCommit
3
3
  class Rubocop
4
- attr_reader :git_repository, :rubocop_validator
4
+ RUBOCOP_STASH_NAME = 'rubocop-stash'
5
5
 
6
- def self.validate
6
+ def self.validate(options = {})
7
7
  new(
8
- GitHooks.configurations.git_repository, RubocopValidator.new
8
+ GitHooks.configurations.git_repository,
9
+ RubocopValidator.new,
10
+ options
9
11
  ).validate
10
12
  end
11
13
 
12
- def initialize(git_repository, rubocop_validator)
13
- @git_repository, @rubocop_validator = git_repository, rubocop_validator
14
+ def initialize(git, rubocop_validator, options = {})
15
+ @git = git
16
+ @rubocop_validator = rubocop_validator
17
+ @options = options
14
18
  end
15
19
 
16
20
  def validate
17
21
  abort 'Check rubocop offences' if offences?
18
22
  end
19
23
 
24
+ protected
25
+
26
+ attr_reader :git, :rubocop_validator, :options
27
+
20
28
  private
21
29
 
22
30
  def changed_files
23
- git_repository
31
+ git
24
32
  .added_or_modified
25
- .select { |file| File.extname(file) == '.rb' }
33
+ .select(&ruby_files)
26
34
  end
27
35
 
28
36
  def offences?
29
- rubocop_validator.errors?(changed_files)
37
+ stash_me_maybe { rubocop_validator.errors?(changed_files) }
38
+ end
39
+
40
+ def ruby_files
41
+ -> (file) { File.extname(file) == '.rb' }
42
+ end
43
+
44
+ def stash_me_maybe(&blk)
45
+ return yield unless stash_around?
46
+
47
+ stash_around(&blk)
48
+ end
49
+
50
+ def stash_around
51
+ git.repository.lib.stash_save(RUBOCOP_STASH_NAME)
52
+ yield
53
+ ensure
54
+ git.repository.lib.stash_pop(rubocop_stash_id) if rubocop_stash?
55
+ end
56
+
57
+ def stash_around?
58
+ options['use_stash']
59
+ end
60
+
61
+ def rubocop_stash?
62
+ rubocop_stash_id
63
+ end
64
+
65
+ def rubocop_stash_id
66
+ Array(
67
+ git.repository.lib
68
+ .stashes_all
69
+ .rassoc(RUBOCOP_STASH_NAME)
70
+ ).first
30
71
  end
31
72
  end
32
73
  end
@@ -3,7 +3,7 @@ module GitHooks
3
3
  class TrailingWhitespace
4
4
  attr_reader :git_repository, :trailing_whitespace_validator
5
5
 
6
- def self.validate
6
+ def self.validate(*)
7
7
  new(
8
8
  GitHooks.configurations.git_repository,
9
9
  TrailingWhitespaceValidator.new
@@ -1,3 +1,3 @@
1
1
  module GitHooks
2
- VERSION = '0.4.0'
2
+ VERSION = '0.5.0'
3
3
  end
@@ -1,4 +1,5 @@
1
1
  ---
2
2
  pre_commits:
3
- - foo
4
- - bar
3
+ Rubocop:
4
+ use_stash: true
5
+ Rspec:
@@ -0,0 +1,121 @@
1
+ describe GitHooks do
2
+ subject(:git_hooks) { described_class }
3
+
4
+ let(:configs) do
5
+ GitHooks::Configurations.new(config_file: config_file)
6
+ end
7
+
8
+ let(:config_file) do
9
+ GitHooks::ConfigFile.new(fixture_path('git_hooks.yml'))
10
+ end
11
+
12
+ before do
13
+ GitHooks.configurations = configs
14
+ allow($stdout).to receive(:write)
15
+ end
16
+
17
+ describe '#validate_hooks!' do
18
+ subject { -> { git_hooks.validate_hooks! } }
19
+
20
+ let(:installed?) { true }
21
+ let(:installer) { instance_double(GitHooks::Installer) }
22
+
23
+ before do
24
+ allow(GitHooks::Installer)
25
+ .to receive(:new)
26
+ .with(GitHooks::PRE_COMMIT)
27
+ .and_return(installer)
28
+ end
29
+
30
+ before do
31
+ allow(installer).to receive(:installed?).and_return(installed?)
32
+ end
33
+
34
+ it { is_expected.to_not raise_error }
35
+
36
+ context 'but without pre-commit installed' do
37
+ let(:installed?) { false }
38
+
39
+ let(:message) do
40
+ "Please install pre-commit hook with `git_hooks install pre-commit'"
41
+ end
42
+
43
+ it do
44
+ is_expected.to raise_error(GitHooks::Exceptions::MissingHook, message)
45
+ end
46
+ end
47
+ end
48
+
49
+ describe '.base_path' do
50
+ subject { described_class.base_path }
51
+
52
+ it "has gem's root path" do
53
+ is_expected.to eq(
54
+ File.absolute_path(
55
+ File.join(File.expand_path(__FILE__), '..', '..')
56
+ )
57
+ )
58
+ end
59
+ end
60
+
61
+ describe '.configurations' do
62
+ subject(:configurations) { described_class.configurations }
63
+
64
+ before { GitHooks.configurations = nil }
65
+
66
+ let(:configs) { double(:probe) }
67
+
68
+ it 'creates with default params' do
69
+ expect(GitHooks::Configurations)
70
+ .to receive(:new)
71
+ .with(no_args)
72
+ .and_return(configs)
73
+
74
+ is_expected.to eq(configs)
75
+ end
76
+ end
77
+
78
+ describe 'configurations=' do
79
+ subject { -> { GitHooks.configurations = configs } }
80
+
81
+ let!(:configs) { double(:probe) }
82
+
83
+ before { GitHooks.configurations = nil }
84
+ after { GitHooks.configurations = nil }
85
+
86
+ it 'updates configurations' do
87
+ is_expected.to change { GitHooks.configurations }.to(configs)
88
+ end
89
+ end
90
+
91
+ describe '#execute_pre_commits' do
92
+ subject(:execute_pre_commits) { GitHooks.execute_pre_commits }
93
+
94
+ let(:rubocop_options) do
95
+ { 'use_stash' => true }
96
+ end
97
+
98
+ before do
99
+ allow(GitHooks::PreCommit::Rspec).to receive(:validate)
100
+ allow(GitHooks::PreCommit::Rubocop).to receive(:validate)
101
+ end
102
+
103
+ it 'instantiates each pre commit' do
104
+ expect(GitHooks::PreCommit).to receive(:const_get)
105
+ .with('Rubocop').and_call_original
106
+ expect(GitHooks::PreCommit).to receive(:const_get)
107
+ .with('Rspec').and_call_original
108
+
109
+ execute_pre_commits
110
+ end
111
+
112
+ it 'validates the hook, passing its options when available' do
113
+ expect(GitHooks::PreCommit::Rubocop).to receive(:validate)
114
+ .with(rubocop_options)
115
+ expect(GitHooks::PreCommit::Rspec).to receive(:validate)
116
+ .with(nil)
117
+
118
+ execute_pre_commits
119
+ end
120
+ end
121
+ end
@@ -4,7 +4,12 @@ module GitHooks
4
4
 
5
5
  let(:path) { 'some-not-existent-file' }
6
6
  let(:content) { { 'pre_commits' => pre_commits } }
7
- let(:pre_commits) { %w(foo bar) }
7
+ let(:pre_commits) do
8
+ {
9
+ 'Rubocop' => { 'use_stash' => true },
10
+ 'Rspec' => nil
11
+ }
12
+ end
8
13
 
9
14
  describe '#pre_commits' do
10
15
  subject { config.pre_commits }
@@ -12,11 +17,11 @@ module GitHooks
12
17
  let(:path) { fixture_path('git_hooks.yml') }
13
18
 
14
19
  it 'has the pre commits specified on hook file' do
15
- is_expected.to eq(%w(foo bar))
20
+ is_expected.to eq(pre_commits)
16
21
  end
17
22
 
18
23
  context 'when the given file does not exist' do
19
- let(:path) { 'some-not-existent-file' }
24
+ let(:path) { 'some-non-existing-file' }
20
25
 
21
26
  it { is_expected.to eq([]) }
22
27
  end
@@ -1,7 +1,7 @@
1
1
  module GitHooks
2
2
  module PreCommit
3
3
  describe Rspec do
4
- subject(:rspec) { described_class.new git_repository, rspec_executor }
4
+ subject(:rspec) { described_class.new(git_repository, rspec_executor) }
5
5
 
6
6
  let(:git_repository) do
7
7
  instance_double(GitHooks::Git, clean?: clean?)
@@ -44,6 +44,44 @@ module GitHooks
44
44
 
45
45
  it { expect(-> { validate }).to_not raise_error }
46
46
  end
47
+
48
+ context 'with stash option' do
49
+ let(:rubocop) do
50
+ described_class.new(
51
+ git_repository, rubocop_validator, 'use_stash' => true
52
+ )
53
+ end
54
+
55
+ let(:repository) { instance_double(::Git::Base) }
56
+ let(:lib) { instance_double(::Git::Lib) }
57
+
58
+ before do
59
+ allow(repository).to receive(:lib).and_return(lib)
60
+ allow(git_repository).to receive(:repository).and_return(repository)
61
+ allow(lib).to receive(:stash_save).and_return(true)
62
+ allow(lib).to receive(:stash_pop).and_return(true)
63
+ allow(lib).to receive(:stashes_all).and_return([[0, 'rubocop-stash']])
64
+ end
65
+
66
+ it 'stashes working directory changes and reapplies them' do
67
+ expect(lib).to receive(:stash_save).with('rubocop-stash')
68
+ expect(lib).to receive(:stash_pop)
69
+
70
+ expect(-> { validate }).not_to raise_error
71
+ end
72
+
73
+ context 'with validation error' do
74
+ let(:errors?) { true }
75
+
76
+ it 'stashes working directory changes and reapplies them' do
77
+ expect(lib).to receive(:stash_save).with('rubocop-stash')
78
+ expect(lib).to receive(:stash_pop)
79
+
80
+ expect(-> { validate }).to raise_error(SystemExit)
81
+ .and output("Check rubocop offences\n").to_stderr
82
+ end
83
+ end
84
+ end
47
85
  end
48
86
 
49
87
  describe '.validate' do
@@ -62,7 +100,7 @@ module GitHooks
62
100
  end
63
101
 
64
102
  it 'creates object with git_repository and rubocop_validator' do
65
- expect(Rubocop).to receive(:new).with(git, rubocop_validator)
103
+ expect(Rubocop).to receive(:new).with(git, rubocop_validator, {})
66
104
 
67
105
  validate
68
106
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: git-hooks
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rafael da Silva Almeida
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-09 00:00:00.000000000 Z
11
+ date: 2015-03-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubocop
@@ -130,6 +130,7 @@ executables:
130
130
  extensions: []
131
131
  extra_rdoc_files: []
132
132
  files:
133
+ - ".git_hooks.yml"
133
134
  - ".gitignore"
134
135
  - ".rspec"
135
136
  - ".rubocop.yml"
@@ -138,6 +139,7 @@ files:
138
139
  - CHANGELOG
139
140
  - Gemfile
140
141
  - README.md
142
+ - Rakefile
141
143
  - bin/git_hooks
142
144
  - git-hooks.gemspec
143
145
  - git_hooks.yml.example
@@ -162,6 +164,7 @@ files:
162
164
  - lib/git_hooks/trailing_whitespace_validator.rb
163
165
  - lib/git_hooks/version.rb
164
166
  - spec/fixtures/git_hooks.yml
167
+ - spec/git-hooks_spec.rb
165
168
  - spec/git_hooks/config_file_spec.rb
166
169
  - spec/git_hooks/configurations_spec.rb
167
170
  - spec/git_hooks/git_spec.rb
@@ -174,7 +177,6 @@ files:
174
177
  - spec/git_hooks/rspec_executor_spec.rb
175
178
  - spec/git_hooks/rubocop_validator_spec.rb
176
179
  - spec/git_hooks/trailing_space_validator.rb
177
- - spec/git_hooks_spec.rb
178
180
  - spec/spec_helper.rb
179
181
  homepage: http://github.com/stupied4ever/ruby-git-hooks
180
182
  licenses:
@@ -202,6 +204,7 @@ specification_version: 4
202
204
  summary: Help to keep git hooks organized.
203
205
  test_files:
204
206
  - spec/fixtures/git_hooks.yml
207
+ - spec/git-hooks_spec.rb
205
208
  - spec/git_hooks/config_file_spec.rb
206
209
  - spec/git_hooks/configurations_spec.rb
207
210
  - spec/git_hooks/git_spec.rb
@@ -214,6 +217,5 @@ test_files:
214
217
  - spec/git_hooks/rspec_executor_spec.rb
215
218
  - spec/git_hooks/rubocop_validator_spec.rb
216
219
  - spec/git_hooks/trailing_space_validator.rb
217
- - spec/git_hooks_spec.rb
218
220
  - spec/spec_helper.rb
219
221
  has_rdoc:
@@ -1,89 +0,0 @@
1
- describe GitHooks do
2
- describe '#validate_hooks!' do
3
- subject { -> { described_class.validate_hooks! } }
4
-
5
- before do
6
- allow(GitHooks::Installer)
7
- .to receive(:new)
8
- .with(GitHooks::PRE_COMMIT)
9
- .and_return(installer)
10
-
11
- GitHooks.configurations = configs
12
- end
13
-
14
- let(:configs) do
15
- GitHooks::Configurations.new(config_file: config_file)
16
- end
17
-
18
- let(:config_file) do
19
- GitHooks::ConfigFile.new(fixture_path('git_hooks.yml'))
20
- end
21
-
22
- let(:installed?) { true }
23
- let(:installer) { instance_double(GitHooks::Installer) }
24
-
25
- before do
26
- allow(installer).to receive(:installed?).and_return(installed?)
27
- end
28
-
29
- it { is_expected.to_not raise_error }
30
-
31
- context 'but without pre-commit installed' do
32
- let(:installed?) { false }
33
-
34
- let(:message) do
35
- "Please install pre-commit hook with `git_hooks install pre-commit'"
36
- end
37
-
38
- it do
39
- is_expected.to raise_error(GitHooks::Exceptions::MissingHook, message)
40
- end
41
- end
42
- end
43
-
44
- describe '.base_path' do
45
- subject { described_class.base_path }
46
-
47
- it "has gem's root path" do
48
- is_expected.to eq(
49
- File.absolute_path(
50
- File.join(File.expand_path(__FILE__), '..', '..')
51
- )
52
- )
53
- end
54
- end
55
-
56
- describe '.configurations' do
57
- subject(:configurations) { described_class.configurations }
58
-
59
- before { GitHooks.configurations = nil }
60
-
61
- let(:configs) { instance_double(GitHooks::Configurations) }
62
-
63
- it 'creates with default params' do
64
- expect(GitHooks::Configurations)
65
- .to receive(:new)
66
- .with(no_args)
67
- .and_return(configs)
68
-
69
- is_expected.to eq(configs)
70
- end
71
- end
72
-
73
- describe 'configurations=' do
74
- subject(:set_configurations) { GitHooks.configurations = configs }
75
-
76
- let(:configs) { instance_double(GitHooks::Configurations) }
77
-
78
- before do
79
- GitHooks.configurations = nil
80
- allow(GitHooks::Configurations).to receive(:new).and_return(nil)
81
- end
82
-
83
- it 'updates configurations' do
84
- expect { set_configurations }.to change {
85
- GitHooks.configurations
86
- }.to(configs)
87
- end
88
- end
89
- end