rabbitt-githooks 1.2.7 → 1.3.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.
@@ -1,7 +1,9 @@
1
- class Process::Status
2
- def failed?
3
- !success?
1
+ module Process
2
+ class Status
3
+ def failed?
4
+ !success?
5
+ end
6
+ alias_method :fail?, :failed?
7
+ alias_method :failure?, :failed?
4
8
  end
5
- alias_method :fail?, :failed?
6
- alias_method :failure?, :failed?
7
9
  end
data/lib/githooks/hook.rb CHANGED
@@ -63,19 +63,24 @@ module GitHooks
63
63
  end
64
64
 
65
65
  attr_reader :sections, :phase, :repository, :repository_path
66
- attr_accessor :args, :unstaged, :untracked
66
+ attr_accessor :args, :staged, :untracked, :tracked
67
67
 
68
68
  def initialize(phase)
69
69
  @phase = phase
70
- @sections = []
70
+ @sections = {}
71
71
  @commands = []
72
72
  @args = []
73
- @unstaged = false
73
+ @staged = true
74
+ @tracked = false
74
75
  @untracked = false
75
76
 
76
77
  repository_path = Dir.getwd # rubocop:disable UselessAssignment
77
78
  end
78
79
 
80
+ def [](name)
81
+ @sections[name]
82
+ end
83
+
79
84
  def repository_path=(path)
80
85
  @repository = Repository.new(path)
81
86
  end
@@ -86,7 +91,7 @@ module GitHooks
86
91
 
87
92
  def run
88
93
  # only run sections that have actions matching files in the manifest
89
- runable_sections = @sections.select { |section| !section.actions.empty? }
94
+ runable_sections = sections.select { |section| !section.actions.empty? }
90
95
  runable_sections.collect { |section| section.run }.all?
91
96
  end
92
97
 
@@ -111,6 +116,10 @@ module GitHooks
111
116
  @commands.select { |command| command.aliases.include? name.to_s }.first
112
117
  end
113
118
 
119
+ def sections
120
+ @sections.values
121
+ end
122
+
114
123
  # DSL methods
115
124
 
116
125
  def command(name, options = {})
@@ -123,7 +132,14 @@ module GitHooks
123
132
  end
124
133
 
125
134
  def section(name, &block)
126
- @sections << Section.new(name, self, &block)
135
+ key_name = Section.key_from_name(name)
136
+ return @sections[key_name] unless block_given?
137
+
138
+ if @sections.include? key_name
139
+ @sections[key_name].instance_eval(&block)
140
+ else
141
+ @sections[key_name] ||= Section.new(name, self, &block)
142
+ end
127
143
  self
128
144
  end
129
145
 
@@ -141,8 +157,9 @@ module GitHooks
141
157
 
142
158
  def manifest
143
159
  @files ||= repo.manifest(
144
- untracked: hook.untracked,
145
- unstaged: hook.unstaged
160
+ staged: hook.staged,
161
+ tracked: hook.tracked,
162
+ untracked: hook.untracked
146
163
  )
147
164
  end
148
165
 
@@ -22,7 +22,7 @@ require 'singleton'
22
22
  require 'open3'
23
23
 
24
24
  module GitHooks
25
- class Repository
25
+ class Repository # rubocop:disable ClassLength
26
26
  autoload :Config, 'githooks/repository/config'
27
27
  autoload :File, 'githooks/repository/file'
28
28
  autoload :Limiter, 'githooks/repository/limiter'
@@ -34,12 +34,12 @@ module GitHooks
34
34
  renamed: 'R', retyped: 'T',
35
35
  unknown: 'U', unmerged: 'X',
36
36
  broken: 'B', untracked: '?',
37
- any: '*'
37
+ any: '*', tracked: '^'
38
38
  }.freeze unless defined? CHANGE_TYPE_SYMBOLS
39
39
 
40
40
  CHANGE_TYPES = CHANGE_TYPE_SYMBOLS.invert.freeze unless defined? CHANGE_TYPES
41
41
 
42
- DEFAULT_DIFF_INDEX_OPTIONS = { staged: true, ref: 'HEAD' } unless defined? DEFAULT_DIFF_INDEX_OPTIONS
42
+ DEFAULT_DIFF_INDEX_OPTIONS = { staged: true } unless defined? DEFAULT_DIFF_INDEX_OPTIONS
43
43
 
44
44
  @__instance__ = {}
45
45
  @__mutex__ = Mutex.new
@@ -91,28 +91,39 @@ module GitHooks
91
91
  end
92
92
 
93
93
  def manifest(options = {})
94
- ref = options.delete(:ref) || 'HEAD'
95
- unstaged = options.delete(:unstaged)
96
- untracked = options.delete(:untracked)
94
+ ref = options.delete(:ref)
97
95
 
98
- return staged_manifest(ref: ref) unless unstaged || untracked
96
+ return staged_manifest(ref: ref) if options.delete(:staged)
99
97
 
100
- [].tap do |files|
101
- files.push(*unstaged_manifest(ref: ref)) if unstaged
102
- files.push(*untracked_manifest) if untracked
103
- end
98
+ files = unstaged_manifest(ref: ref)
99
+
100
+ tracked_manifest(ref: ref).each do |file|
101
+ files << file unless files.index { |f| f.path.to_s == file.path.to_s }
102
+ end if options.delete(:tracked)
103
+
104
+ untracked_manifest(ref: ref).each do |file|
105
+ files << file unless files.index { |f| f.path.to_s == file.path.to_s }
106
+ end if options.delete(:untracked)
107
+
108
+ files.sort_by! { |f| f.path.to_s }
109
+ files.uniq { |f| f.path.to_s }
104
110
  end
105
111
 
106
112
  def staged_manifest(options = {})
107
- diff_index(options.merge(unstaged: false))
113
+ diff_index(options.merge(staged: true))
108
114
  end
109
115
  alias_method :commit_manifest, :staged_manifest
110
116
 
111
117
  def unstaged_manifest(options = {})
112
- diff_index(options.merge(unstaged: true))
118
+ diff_index(options.merge(staged: false))
113
119
  end
114
120
 
115
- def untracked_manifest
121
+ def tracked_manifest(*)
122
+ files = git_command('ls-files', '--exclude-standard').output.strip.split(/\s*\n\s*/)
123
+ files.collect { |path| DiffIndexEntry.from_file_path(path, true).to_repo_file }
124
+ end
125
+
126
+ def untracked_manifest(*)
116
127
  files = git_command('ls-files', '--others', '--exclude-standard').output.strip.split(/\s*\n\s*/)
117
128
  files.collect { |path| DiffIndexEntry.from_file_path(path).to_repo_file }
118
129
  end
@@ -122,11 +133,17 @@ module GitHooks
122
133
  def diff_index(options = {})
123
134
  options = DEFAULT_DIFF_INDEX_OPTIONS.merge(options)
124
135
 
125
- cmd = %w(diff-index -C -M -B)
126
- cmd << '--cached' unless options[:unstaged]
127
- cmd << options.delete(:ref) || 'HEAD'
136
+ if $stdout.tty? && !options[:staged]
137
+ cmd = %w(diff-files -C -M -B)
138
+ else
139
+ cmd = %w(diff-index -C -M -B)
140
+ cmd << '--cached' if options[:staged]
141
+ cmd << (options.delete(:ref) || 'HEAD')
142
+ end
143
+
144
+ cmd.compact!
128
145
 
129
- raw_output = git_command(*cmd).output.strip
146
+ raw_output = git_command(*cmd.compact).output.strip
130
147
  raw_output.split(/\n/).collect { |data| DiffIndexEntry.new(data).to_repo_file }
131
148
  end
132
149
 
@@ -22,149 +22,156 @@ require 'singleton'
22
22
  require 'open3'
23
23
 
24
24
  module GitHooks
25
- class Repository::Config # rubocop:disable ClassLength
26
- OPTIONS = {
27
- 'path' => { type: :path, multiple: false },
28
- 'script' => { type: :path, multiple: false },
29
- 'pre-run-execute' => { type: :path, multiple: true },
30
- 'post-run-execute' => { type: :path, multiple: true }
31
- }
32
-
33
- def initialize(path = Dir.getwd)
34
- @repository = Repository.instance(path)
35
- end
36
-
37
- OPTIONS.keys.each do |name|
38
- method_name = name.gsub(/-/, '_')
39
- class_eval(<<-EOS, __FILE__, __LINE__ + 1)
40
- def #{method_name}(options = {})
41
- result = get('#{name}', options)
42
- OPTIONS['#{name}'][:multiple] ? [result].flatten.compact : result
43
- end
44
- EOS
45
- end
25
+ class Repository
26
+ class Config # rubocop:disable ClassLength
27
+ OPTIONS = {
28
+ 'path' => { type: :path, multiple: false },
29
+ 'script' => { type: :path, multiple: false },
30
+ 'pre-run-execute' => { type: :path, multiple: true },
31
+ 'post-run-execute' => { type: :path, multiple: true }
32
+ }
33
+
34
+ def initialize(path = Dir.getwd)
35
+ @repository = Repository.instance(path)
36
+ end
46
37
 
47
- def [](option)
48
- send(option.gsub('-', '_'))
49
- end
38
+ OPTIONS.keys.each do |name|
39
+ method_name = name.gsub(/-/, '_')
40
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
41
+ def #{method_name}(options = {})
42
+ result = get('#{name}', options)
43
+ OPTIONS['#{name}'][:multiple] ? [result].flatten.compact : result
44
+ end
45
+ EOS
46
+ end
50
47
 
51
- def set(option, value, options = {}) # rubocop:disable CyclomaticComplexity, MethodLength
52
- unless OPTIONS.keys.include? option
53
- fail ArgumentError, "Unexpected option '#{option}': expected one of: #{OPTIONS.keys.join(', ')}"
48
+ def [](option)
49
+ send(option.gsub('-', '_'))
54
50
  end
55
51
 
56
- repo = options.delete(:repo_path) || repo_path
57
- global = (opt = options.delete(:global)).nil? ? false : opt
58
- var_type = "--#{OPTIONS[option][:type]}"
59
- add_type = OPTIONS[option][:multiple] ? '--add' : '--replace-all'
60
- overwrite = !!options.delete(:overwrite)
61
-
62
- if option == 'path'
63
- new_path = Pathname.new(value)
64
- errors = []
65
- errors << 'path must be a real location' unless new_path.exist?
66
- errors << 'path must be a directory' unless new_path.directory?
67
- errors << 'path must have a hooks directory in it' unless (new_path + 'hooks').exist?
68
-
69
- if errors.size > 0
70
- puts "Unable to change githooks path for [#{repo}]:"
71
- errors.each { |error| puts " #{error}" }
72
- fail ArgumentError
52
+ def set(option, value, options = {}) # rubocop:disable CyclomaticComplexity, MethodLength
53
+ unless OPTIONS.keys.include? option
54
+ fail ArgumentError, "Unexpected option '#{option}': expected one of: #{OPTIONS.keys.join(', ')}"
55
+ end
56
+
57
+ repo = options.delete(:repo_path) || repo_path
58
+ global = (opt = options.delete(:global)).nil? ? false : opt
59
+ var_type = "--#{OPTIONS[option][:type]}"
60
+ add_type = OPTIONS[option][:multiple] ? '--add' : '--replace-all'
61
+ overwrite = !!options.delete(:overwrite)
62
+
63
+ if option == 'path'
64
+ new_path = Pathname.new(value)
65
+ errors = []
66
+ errors << 'path must be a real location' unless new_path.exist?
67
+ errors << 'path must be a directory' unless new_path.directory?
68
+ unless (new_path + 'hooks').exist? || (new_path + '.hooks').exist?
69
+ errors << 'path must have a hooks or .hooks directory in it'
70
+ end
71
+
72
+ if errors.size > 0
73
+ puts "Unable to change githooks path for [#{repo}]:"
74
+ errors.each { |error| puts " #{error}" }
75
+ fail ArgumentError
76
+ end
77
+ else
78
+ fail ArgumentError unless Pathname.new(value).executable?
73
79
  end
74
- else
75
- fail ArgumentError unless Pathname.new(value).executable?
76
- end
77
80
 
78
- value = Pathname.new(value).realpath.to_s
81
+ value = Pathname.new(value).realpath.to_s
79
82
 
80
- if overwrite && !self[option].nil? && !self[option].empty?
81
- puts "Overwrite requested for option '#{option}'" if GitHooks.verbose
82
- unset(option, repo_path: repo, global: global)
83
- end
83
+ if overwrite && !self[option].nil? && !self[option].empty?
84
+ puts "Overwrite requested for option '#{option}'" if GitHooks.verbose
85
+ unset(option, repo_path: repo, global: global)
86
+ end
84
87
 
85
- option = "githooks.#{repo}.#{option}"
86
- git_command(global ? '--global' : '--local', var_type, add_type, option, value, path: repo).tap do |result|
87
- puts "Added option #{option} with value #{value}" if result.status.success?
88
+ option = "githooks.#{repo}.#{option}"
89
+ git_command(global ? '--global' : '--local', var_type, add_type, option, value, path: repo).tap do |result|
90
+ puts "Added option #{option} with value #{value}" if result.status.success?
91
+ end
88
92
  end
89
- end
90
93
 
91
- def remove_section(options = {})
92
- repo = options.delete(:repo_path) || repo_path
93
- global = (opt = options.delete(:global)).nil? ? false : opt
94
- option = "githooks.#{repo}"
95
- git_command(global ? '--global' : '--local', '--remove-section', option, path: repo)
96
- end
97
-
98
- def unset(option, *args)
99
- unless OPTIONS.keys.include? option
100
- fail ArgumentError, "Unexpected option '#{option}': expected one of: #{OPTIONS.keys.join(', ')}"
94
+ def remove_section(options = {})
95
+ repo = options.delete(:repo_path) || repo_path
96
+ global = (opt = options.delete(:global)).nil? ? false : opt
97
+ option = "githooks.#{repo}"
98
+ git_command(global ? '--global' : '--local', '--remove-section', option, path: repo)
101
99
  end
102
100
 
103
- options = args.extract_options
104
- repo = options.delete(:repo_path) || repo_path
105
- global = (opt = options.delete(:global)).nil? ? false : opt
106
- option = "githooks.#{repo}.#{option}"
101
+ def unset(option, *args) # rubocop:disable Style/CyclomaticComplexity
102
+ unless OPTIONS.keys.include? option
103
+ fail ArgumentError, "Unexpected option '#{option}': expected one of: #{OPTIONS.keys.join(', ')}"
104
+ end
107
105
 
108
- value_regex = args.first
106
+ options = args.extract_options
107
+ repo = options.delete(:repo_path) || repo_path
108
+ global = (opt = options.delete(:global)).nil? ? false : opt
109
+ option = "githooks.#{repo}.#{option}"
109
110
 
110
- if options.delete(:all) || value_regex.nil?
111
- git_command(global ? '--global' : '--local', '--unset-all', option, path: repo)
112
- else
113
- git_command(global ? '--global' : '--local', '--unset', option, value_regex, path: repo)
114
- end.tap do |result|
115
- puts "Unset option #{option.git_option_path_split.last}" if result.status.success?
116
- end
117
- end
111
+ value_regex = args.first
118
112
 
119
- def get(option, options = {})
120
- unless OPTIONS.keys.include? option
121
- fail ArgumentError, "Unexpected option '#{option}': expected one of: #{OPTIONS.keys.join(', ')}"
113
+ if options.delete(:all) || value_regex.nil?
114
+ git_command(global ? '--global' : '--local', '--unset-all', option, path: repo)
115
+ else
116
+ git_command(global ? '--global' : '--local', '--unset', option, value_regex, path: repo)
117
+ end.tap do |result|
118
+ puts "Unset option #{option.git_option_path_split.last}" if result.status.success?
119
+ end
122
120
  end
123
121
 
124
- repo = options[:repo_path] || repo_path
125
- githooks = list(options)['githooks']
122
+ def get(option, options = {})
123
+ unless OPTIONS.keys.include? option
124
+ fail ArgumentError, "Unexpected option '#{option}': expected one of: #{OPTIONS.keys.join(', ')}"
125
+ end
126
126
 
127
- githooks[repo][option] if githooks && githooks[repo] && githooks[repo][option]
128
- end
127
+ repo = options[:repo_path] || repo_path
128
+ githooks = list(options)['githooks']
129
129
 
130
- def list(options = {}) # rubocop:disable MethodLength, CyclomaticComplexity
131
- repo = options.delete(:repo_path) || repo_path
132
- global = (opt = options.delete(:global)).nil? ? false : opt
130
+ githooks[repo][option] if githooks && githooks[repo] && githooks[repo][option]
131
+ end
133
132
 
134
- config_list = git_command('--list', global ? '--global' : '--local', path: repo).output.split(/\n/)
135
- config_list.inject({}) do |hash, line|
136
- key, value = line.split(/\s*=\s*/)
137
- key_parts = key.git_option_path_split
133
+ def list(options = {})
134
+ config(options.delete(:repo_path) || repo_path)
135
+ end
138
136
 
139
- ptr = hash[key_parts.shift] ||= {} # rubocop:disable IndentationWidth
140
- while key_parts.size > 1 && (part = key_parts.shift)
141
- ptr = ptr[part] ||= {} # rubocop:disable IndentationWidth
142
- end
137
+ private
143
138
 
144
- key = key_parts.shift
145
- case ptr[key]
146
- when nil then ptr[key] = value
147
- when Array then ptr[key] << value
148
- else ptr[key] = [ptr[key], value].flatten
149
- end
139
+ def repo_path
140
+ @repository.root_path
141
+ end
150
142
 
151
- hash
143
+ def git_command(*args)
144
+ args = ['config', *args].flatten
145
+ @repository.git_command(*args)
152
146
  end
153
- end
154
147
 
155
- private
148
+ def config(path = nil) # rubocop:disable MethodLength, CyclomaticComplexity
149
+ path ||= repo_path
156
150
 
157
- def repo_path
158
- @repository.root_path
159
- end
151
+ raw_config = git_command('--list', path: path).output.split("\n")
152
+ raw_config.sort.uniq.inject({}) do |hash, line|
153
+ key, value = line.split(/\s*=\s*/)
154
+ key_parts = key.git_option_path_split
160
155
 
161
- def git_command(*args)
162
- args = ['config', *args].flatten
163
- @repository.git_command(*args)
164
- end
156
+ ptr = hash[key_parts.shift] ||= {} # rubocop:disable IndentationWidth
157
+ while key_parts.size > 1 && (part = key_parts.shift)
158
+ ptr = ptr[part] ||= {} # rubocop:disable IndentationWidth
159
+ end
160
+
161
+ key = key_parts.shift
162
+ case ptr[key]
163
+ when nil then ptr[key] = value
164
+ when Array then ptr[key] << value
165
+ else ptr[key] = [ptr[key], value].flatten
166
+ end
165
167
 
166
- def git
167
- @repository.git
168
+ hash
169
+ end
170
+ end
171
+
172
+ def git
173
+ @repository.git
174
+ end
168
175
  end
169
176
  end
170
177
  end