pre-commit 0.12.0 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +39 -16
  3. data/bin/pre-commit +1 -12
  4. data/lib/plugins/pluginator/extensions/find_check.rb +26 -0
  5. data/lib/plugins/pre_commit/checks/before_all.rb +23 -7
  6. data/lib/plugins/pre_commit/checks/ci.rb +10 -3
  7. data/lib/plugins/pre_commit/checks/closure.rb +12 -4
  8. data/lib/plugins/pre_commit/checks/coffeelint.rb +9 -4
  9. data/lib/plugins/pre_commit/checks/common.rb +17 -0
  10. data/lib/plugins/pre_commit/checks/console_log.rb +23 -7
  11. data/lib/plugins/pre_commit/checks/csslint.rb +32 -0
  12. data/lib/plugins/pre_commit/checks/debugger.rb +14 -10
  13. data/lib/plugins/pre_commit/checks/gemfile_path.rb +18 -7
  14. data/lib/plugins/pre_commit/checks/jshint.rb +10 -4
  15. data/lib/plugins/pre_commit/checks/jslint.rb +11 -5
  16. data/lib/plugins/pre_commit/checks/local.rb +10 -2
  17. data/lib/plugins/pre_commit/checks/merge_conflict.rb +15 -6
  18. data/lib/plugins/pre_commit/checks/migration.rb +32 -26
  19. data/lib/plugins/pre_commit/checks/nb_space.rb +10 -2
  20. data/lib/plugins/pre_commit/checks/php.rb +10 -4
  21. data/lib/plugins/pre_commit/checks/pry.rb +15 -6
  22. data/lib/plugins/pre_commit/checks/rails.rb +17 -0
  23. data/lib/plugins/pre_commit/checks/rspec_focus.rb +19 -7
  24. data/lib/plugins/pre_commit/checks/rubocop.rb +20 -8
  25. data/lib/plugins/pre_commit/checks/ruby.rb +17 -0
  26. data/lib/plugins/pre_commit/checks/ruby_symbol_hashrockets.rb +17 -8
  27. data/lib/plugins/pre_commit/checks/tabs.rb +15 -8
  28. data/lib/plugins/pre_commit/checks/whitespace.rb +28 -5
  29. data/lib/plugins/pre_commit/configuration/providers/README.md +10 -0
  30. data/lib/plugins/pre_commit/configuration/providers/default.rb +34 -0
  31. data/lib/plugins/pre_commit/configuration/providers/git.rb +26 -0
  32. data/lib/plugins/pre_commit/configuration/providers/git_old.rb +28 -0
  33. data/lib/plugins/pre_commit/configuration/providers/yaml.rb +67 -0
  34. data/lib/pre-commit.rb +28 -1
  35. data/lib/pre-commit/checks.rb +1 -98
  36. data/lib/pre-commit/checks/grep.rb +57 -0
  37. data/lib/{plugins/pre_commit → pre-commit}/checks/js.rb +15 -7
  38. data/lib/pre-commit/checks/plugin.rb +13 -0
  39. data/lib/pre-commit/cli.rb +46 -19
  40. data/lib/pre-commit/configuration.rb +54 -0
  41. data/lib/pre-commit/configuration/providers.rb +53 -0
  42. data/lib/pre-commit/installer.rb +54 -0
  43. data/lib/pre-commit/list_evaluator.rb +85 -0
  44. data/lib/pre-commit/plugins_list.rb +87 -0
  45. data/lib/pre-commit/runner.rb +54 -9
  46. data/lib/pre-commit/support/csslint/csslint.js +9259 -0
  47. data/lib/pre-commit/utils/git_conversions.rb +56 -0
  48. data/lib/pre-commit/utils/staged_files.rb +21 -0
  49. metadata +47 -30
  50. data/lib/pre-commit/support/templates/automatic_hook +0 -35
  51. data/lib/pre-commit/support/templates/default_hook +0 -35
  52. data/lib/pre-commit/support/templates/manual_hook +0 -14
  53. data/lib/pre-commit/utils.rb +0 -27
@@ -0,0 +1,13 @@
1
+ module PreCommit
2
+ module Checks
3
+ class Plugin
4
+ attr_accessor :pluginator, :config
5
+
6
+ def initialize(pluginator, config, list)
7
+ @pluginator = pluginator
8
+ @config = config
9
+ @list = list
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,4 +1,7 @@
1
1
  require 'fileutils'
2
+ require 'pre-commit/configuration'
3
+ require 'pre-commit/installer'
4
+ require 'pre-commit/list_evaluator'
2
5
 
3
6
  module PreCommit
4
7
 
@@ -6,36 +9,60 @@ module PreCommit
6
9
 
7
10
  class Cli
8
11
 
9
- PRE_COMMIT_HOOK_PATH = '.git/hooks/pre-commit'
10
- TEMPLATE_DIR = File.expand_path("../support/templates/", __FILE__)
12
+ def initialize(*args)
13
+ @args = args
14
+ end
11
15
 
12
- attr_reader :templates
16
+ def execute()
17
+ action_name = @args.shift or 'help'
18
+ action = "execute_#{action_name}".to_sym
19
+ if respond_to?(action)
20
+ then send(action, *@args)
21
+ else execute_help(action_name, *@args)
22
+ end
23
+ end
13
24
 
14
- def initialize
15
- @templates = load_templates
25
+ def execute_help(*args)
26
+ warn "Unknown parameters: #{args * " "}" unless args.empty?
27
+ warn "Usage: pre-commit install"
28
+ warn "Usage: pre-commit list"
29
+ warn "Usage: pre-commit plugins"
30
+ warn "Usage: pre-commit <enable|disbale> <git|yaml> <checks|warnings> check1 [check2...]"
31
+ args.empty? # return status, it's ok if user requested help
16
32
  end
17
33
 
18
- def install(key = nil)
19
- key ||= "default"
20
- hook = templates[key.sub(/^--/, "")]
34
+ def execute_install(key = nil, *args)
35
+ PreCommit::Installer.new(key).install
36
+ end
21
37
 
22
- raise TemplateNotFound.new("Could not find template #{key}") unless hook
38
+ def execute_list(*args)
39
+ puts list_evaluator.list
40
+ true
41
+ end
23
42
 
24
- FileUtils.cp(hook, PRE_COMMIT_HOOK_PATH)
25
- FileUtils.chmod(0755, PRE_COMMIT_HOOK_PATH)
43
+ def execute_plugins(*args)
44
+ puts list_evaluator.plugins
45
+ true
26
46
  end
27
47
 
28
- private
48
+ def execute_enable(*args)
49
+ config.enable(*args)
50
+ rescue ArgumentError
51
+ execute_help('enable', *args)
52
+ end
29
53
 
30
- def load_templates
31
- pattern = File.join(TEMPLATE_DIR, "*_hook")
54
+ def execute_disable(*args)
55
+ config.disable(*args)
56
+ rescue ArgumentError
57
+ execute_help('disable', *args)
58
+ end
32
59
 
33
- Dir.glob(pattern).inject({}) do |hash, file|
34
- key = file.match(/\/([^\/]+?)_hook$/)[1]
35
- hash[key] = file
60
+ def config
61
+ @config ||= PreCommit::Configuration.new(PreCommit.pluginator)
62
+ end
36
63
 
37
- hash
38
- end
64
+ def list_evaluator
65
+ @list_evaluator ||= PreCommit::ListEvaluator.new(config)
39
66
  end
40
67
 
41
68
  end
@@ -0,0 +1,54 @@
1
+ require 'pluginator'
2
+ require 'pre-commit/configuration/providers'
3
+ require 'pre-commit/plugins_list'
4
+
5
+ module PreCommit
6
+ class Configuration
7
+ attr_reader :pluginator, :providers
8
+
9
+ def initialize(pluginator, providers = nil)
10
+ @pluginator = (pluginator or PreCommit.pluginator)
11
+ @providers = (providers or Providers.new(@pluginator))
12
+ end
13
+
14
+ def get(name)
15
+ @providers[name.to_sym]
16
+ end
17
+
18
+ def get_arr(name)
19
+ value = get(name)
20
+ case value
21
+ when nil then []
22
+ when Array then value
23
+ else raise PreCommit::NotAnArray.new
24
+ end
25
+ end
26
+
27
+ def get_combined(name)
28
+ get_arr(name) + get_arr("#{name}_add")
29
+ end
30
+
31
+ def enable(plugin_name, type, check1, *checks)
32
+ checks.unshift(check1) # check1 is ArgumentError triger
33
+ checks.map!(&:to_sym)
34
+ @providers.update( plugin_name, "#{type}_remove", :-, checks )
35
+ @providers.update( plugin_name, "#{type}_add", :+, (checks or []) - (@providers.default(type) or []) )
36
+ true
37
+ rescue PreCommit::PluginNotFound => e
38
+ $stderr.puts e
39
+ false
40
+ end
41
+
42
+ def disable(plugin_name, type, check1, *checks)
43
+ checks.unshift(check1) # check1 is ArgumentError triger
44
+ checks.map!(&:to_sym)
45
+ @providers.update( plugin_name, "#{type}_add", :-, checks )
46
+ @providers.update( plugin_name, "#{type}_remove", :+, checks )
47
+ true
48
+ rescue PreCommit::PluginNotFound => e
49
+ warn e
50
+ false
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,53 @@
1
+ require 'plugins/pluginator/extensions/conversions'
2
+
3
+ module PreCommit
4
+ class NotAnArray < StandardError
5
+ end
6
+
7
+ class PluginNotFound < StandardError
8
+ end
9
+
10
+ class Configuration
11
+ class Providers
12
+ include Pluginator::Extensions::Conversions
13
+
14
+ def initialize(pluginator, plugins = nil)
15
+ @pluginator = pluginator
16
+ @plugins = plugins
17
+ end
18
+
19
+ def [](name)
20
+ plugins.map{|plugin| plugin[name] }.compact.last
21
+ end
22
+
23
+ def default(name)
24
+ plugins[0][name]
25
+ end
26
+
27
+ def update(plugin_name, name, operation, list)
28
+ plugin = find_update_plugin(plugin_name)
29
+ name = name.to_sym
30
+ value = plugin[name] || []
31
+ raise PreCommit::NotAnArray.new unless Array === value
32
+ value = value.send(operation, list)
33
+ plugin.update(name, value)
34
+ end
35
+
36
+ def list
37
+ plugins.map{|plugin| "#{class2string(class2name(plugin.class))}(#{plugin.class.priority})" }
38
+ end
39
+
40
+ private
41
+ def plugins
42
+ @plugins ||= @pluginator['configuration/providers'].sort_by(&:priority).map(&:new)
43
+ end
44
+
45
+ def find_update_plugin(plugin_name)
46
+ plugin = plugins.detect{|plugin| class2string(class2name(plugin.class)) == plugin_name.to_s}
47
+ raise PluginNotFound.new("Plugin not found for #{plugin_name}.") unless plugin
48
+ plugin
49
+ end
50
+
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,54 @@
1
+ require 'fileutils'
2
+ require 'pre-commit/configuration'
3
+
4
+ module PreCommit
5
+
6
+ class Installer
7
+
8
+ TARGET_HOOK_PATH = '.git/hooks/pre-commit'
9
+ TEMPLATE_DIR = File.expand_path("../../../templates/hooks/", __FILE__)
10
+
11
+ attr_reader :key
12
+
13
+ def initialize(key = nil)
14
+ @key = key || "default"
15
+ end
16
+
17
+ def hook
18
+ templates[key.sub(/^--/, "")]
19
+ end
20
+
21
+ def target
22
+ TARGET_HOOK_PATH
23
+ end
24
+
25
+ def install
26
+ if
27
+ hook
28
+ then
29
+ FileUtils.cp(hook, target)
30
+ FileUtils.chmod(0755, target)
31
+ puts "Installed #{hook} to #{target}"
32
+ true
33
+ else
34
+ warn "Could not find template #{key}"
35
+ false
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ def templates
42
+ return @templates if @templates
43
+ pattern = File.join(TEMPLATE_DIR, "*")
44
+
45
+ @templates =
46
+ Dir.glob(pattern).inject({}) do |hash, file|
47
+ key = file.match(/\/([^\/]+?)$/)[1]
48
+ hash[key] = file
49
+ hash
50
+ end
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,85 @@
1
+ require 'pluginator'
2
+ require 'pre-commit/configuration'
3
+ require 'plugins/pluginator/extensions/conversions'
4
+ require 'pre-commit/plugins_list'
5
+
6
+ module PreCommit
7
+ class ListEvaluator
8
+ include Pluginator::Extensions::Conversions
9
+
10
+ attr_reader :config
11
+
12
+ def initialize(config)
13
+ @config = config
14
+ end
15
+
16
+ def list
17
+ <<-DATA
18
+ Available providers: #{config.providers.list.join(" ")}
19
+ Available checks : #{plugin_names.join(" ")}
20
+ Default checks : #{config.get_arr(:checks).join(" ")}
21
+ Enabled checks : #{checks_config.join(" ")}
22
+ Evaluated checks : #{checks_evaluated.join(" ")}
23
+ Default warnings : #{config.get_arr(:warnings).join(" ")}
24
+ Enabled warnings : #{warnings_config.join(" ")}
25
+ Evaluated warnings : #{warnings_evaluated.join(" ")}
26
+ DATA
27
+ end
28
+
29
+ def plugins
30
+ list = config.pluginator['checks'].map{|plugin| [class2string(class2name(plugin)), plugin] }.sort
31
+ separator = list.map{|name, plugin| name.length }.max
32
+ list.map{ |name, plugin| format_plugin(name, separator, plugin) }.flatten
33
+ end
34
+
35
+ def checks_config
36
+ get_combined_checks - get_arr_checks_remove
37
+ end
38
+
39
+ def checks_evaluated(type = :evaluated_names)
40
+ PreCommit::PluginsList.new(get_combined_checks, get_arr_checks_remove) do |name|
41
+ config.pluginator.find_check(name)
42
+ end.send(type)
43
+ end
44
+
45
+ def warnings_config
46
+ get_combined_warnings - get_arr_warnings_remove
47
+ end
48
+
49
+ def warnings_evaluated(type = :evaluated_names)
50
+ PreCommit::PluginsList.new(get_combined_warnings, get_arr_warnings_remove) do |name|
51
+ config.pluginator.find_check(name)
52
+ end.send(type)
53
+ end
54
+
55
+ private
56
+
57
+ def plugin_names
58
+ config.pluginator['checks'].map{|plugin| class2string(class2name(plugin)) }.sort
59
+ end
60
+
61
+ def format_plugin(name, separator, plugin)
62
+ line = [sprintf("%#{separator}s : %s", name, plugin.description)]
63
+ line << sprintf("%#{separator}s - includes: %s", "", plugin.includes.join(" ")) if plugin.respond_to?(:includes)
64
+ line << sprintf("%#{separator}s - excludes: %s", "", plugin.excludes.join(" ")) if plugin.respond_to?(:excludes)
65
+ line
66
+ end
67
+
68
+ def get_combined_checks
69
+ @get_combined_checks ||= config.get_combined(:checks)
70
+ end
71
+
72
+ def get_arr_checks_remove
73
+ @get_arr_checks_remove ||= config.get_arr("checks_remove")
74
+ end
75
+
76
+ def get_combined_warnings
77
+ @get_combined_warnings ||= config.get_combined(:warnings)
78
+ end
79
+
80
+ def get_arr_warnings_remove
81
+ @get_arr_warnings_remove ||= config.get_arr("warnings_remove")
82
+ end
83
+
84
+ end
85
+ end
@@ -0,0 +1,87 @@
1
+ module PreCommit
2
+
3
+ def self.pluginator
4
+ Pluginator.find('pre_commit', :extends => [:find_check])
5
+ end
6
+
7
+ class PluginsList
8
+ attr_reader :configured_names, :configured_remove
9
+
10
+ def initialize(configured_names, configured_remove, &block)
11
+ @configured_names = configured_names
12
+ @configured_remove = configured_remove
13
+ @class_finder = block
14
+ end
15
+
16
+ def evaluated_names
17
+ evaluated_names_(evaluated_names_pairs).flatten.compact
18
+ end
19
+
20
+ def list_to_run
21
+ list_to_run_(evaluated_names_pairs).flatten.compact
22
+ end
23
+
24
+ private
25
+
26
+ def evaluated_names_(list)
27
+ list.map{|name, klass, includes| [name] + evaluated_names_(includes||[]) }
28
+ end
29
+
30
+ def list_to_run_(list)
31
+ list.map{|name, klass, includes| [klass] + list_to_run_(includes||[]) }
32
+ end
33
+
34
+ def evaluated_names_pairs
35
+ list = find_classes_and_includes(configured_names)
36
+ excludes = excludes(list).flatten.compact
37
+ list = filter_excludes(list, excludes)
38
+ list = filter_excludes(list, configured_remove_aliases)
39
+ list = filter_callable(list)
40
+ list
41
+ end
42
+
43
+ def find_classes_and_includes(list)
44
+ find_classes(list).map{ |name, klass| class_and_includes(name, klass) }
45
+ end
46
+
47
+ def find_class(name)
48
+ @class_finder.call(name)
49
+ end
50
+
51
+ def find_classes(list)
52
+ list.map{|name| [name, find_class(name)] }.reject{|name, klass| klass.nil? }
53
+ end
54
+
55
+ def class_and_includes(name, klass)
56
+ [ name, klass, klass.respond_to?(:includes) ? find_classes_and_includes(klass.includes) : [] ]
57
+ end
58
+
59
+ def excludes(list)
60
+ list.map{|name, klass, includes| class_excludes(klass) + excludes(includes) }
61
+ end
62
+
63
+ def class_excludes(klass)
64
+ klass.respond_to?(:excludes) ? klass.excludes : []
65
+ end
66
+
67
+ def filter_excludes(list, excludes)
68
+ list.map{|name, klass, includes| excludes.include?(name) ? nil : [name, klass, filter_excludes(includes, excludes)] }.compact
69
+ end
70
+
71
+ def filter_callable(list)
72
+ list.map{|name, klass, includes|
73
+ (klass.instance_methods.include?(:call) ? [name, klass] : [nil, nil]) << filter_callable(includes)
74
+ }.compact
75
+ end
76
+
77
+ def configured_remove_aliases
78
+ @configured_remove_aliases ||= configured_remove.map{|remove|
79
+ list = [remove]
80
+ klass = find_class(remove)
81
+ list += klass.aliases if klass.respond_to?(:aliases)
82
+ list
83
+ }.flatten.compact
84
+ end
85
+
86
+ end
87
+ end
@@ -1,20 +1,65 @@
1
+ require 'pluginator'
2
+ require 'pre-commit/utils/staged_files'
3
+ require 'pre-commit/configuration'
4
+ require 'pre-commit/list_evaluator'
5
+
1
6
  module PreCommit
2
7
  class Runner
8
+ include PreCommit::Utils::StagedFiles
3
9
 
4
- def run
5
- checks_to_run = PreCommit.checks_to_run
10
+ attr_reader :pluginator, :config
6
11
 
7
- all_passed = checks_to_run.inject(true) do |current_status, check|
8
- passed = check.call
12
+ def initialize(stderr = nil, staged_files = nil, config = nil, pluginator = nil)
13
+ @stderr = (stderr or $stderr)
14
+ @pluginator = (pluginator or PreCommit.pluginator)
15
+ @config = (config or PreCommit::Configuration.new(@pluginator))
16
+ @staged_files = staged_files
17
+ end
9
18
 
10
- if !passed && check.respond_to?(:error_message)
11
- puts check.error_message
12
- end
19
+ def run
20
+ run_single(:warnings)
21
+ run_single(:checks ) or return false
22
+ true
23
+ end
13
24
 
14
- check && current_status
25
+ def run_single(name)
26
+ show_output(name, execute(list_to_run(name)))
27
+ end
28
+
29
+ def show_output(name, list)
30
+ if list.any?
31
+ @stderr.puts send(name, list)
32
+ return false
15
33
  end
34
+ true
35
+ end
36
+
37
+ def execute(list)
38
+ list.map{|cmd| cmd.new(pluginator, config, list).call(staged_files.dup) }.compact
39
+ end
40
+
41
+ def list_to_run(name)
42
+ list_evaluator.send(:"#{name}_evaluated", :list_to_run)
43
+ end
44
+
45
+ def list_evaluator
46
+ @list_evaluator ||= PreCommit::ListEvaluator.new(config)
47
+ end
48
+
49
+ def warnings(list)
50
+ <<-WARNINGS
51
+ pre-commit: Some warnings were raised. These will not stop commit:
52
+ #{list.join("\n")}
53
+ WARNINGS
54
+ end
55
+
56
+ def checks(list)
57
+ <<-ERRORS
58
+ pre-commit: Stopping commit because of errors.
59
+ #{list.join("\n")}
60
+ pre-commit: You can bypass this check using `git commit -n`
16
61
 
17
- exit(all_passed ? 0 : 1)
62
+ ERRORS
18
63
  end
19
64
 
20
65
  end