overcommit-jeygeethanmedia 0.53.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (226) hide show
  1. checksums.yaml +7 -0
  2. data/bin/overcommit +50 -0
  3. data/config/default.yml +1356 -0
  4. data/config/starter.yml +33 -0
  5. data/lib/overcommit.rb +26 -0
  6. data/lib/overcommit/cli.rb +223 -0
  7. data/lib/overcommit/command_splitter.rb +146 -0
  8. data/lib/overcommit/configuration.rb +350 -0
  9. data/lib/overcommit/configuration_loader.rb +96 -0
  10. data/lib/overcommit/configuration_validator.rb +186 -0
  11. data/lib/overcommit/constants.rb +12 -0
  12. data/lib/overcommit/exceptions.rb +52 -0
  13. data/lib/overcommit/git_config.rb +22 -0
  14. data/lib/overcommit/git_repo.rb +286 -0
  15. data/lib/overcommit/git_version.rb +17 -0
  16. data/lib/overcommit/hook/base.rb +294 -0
  17. data/lib/overcommit/hook/commit_msg/base.rb +14 -0
  18. data/lib/overcommit/hook/commit_msg/capitalized_subject.rb +25 -0
  19. data/lib/overcommit/hook/commit_msg/empty_message.rb +12 -0
  20. data/lib/overcommit/hook/commit_msg/gerrit_change_id.rb +22 -0
  21. data/lib/overcommit/hook/commit_msg/hard_tabs.rb +17 -0
  22. data/lib/overcommit/hook/commit_msg/message_format.rb +31 -0
  23. data/lib/overcommit/hook/commit_msg/russian_novel.rb +16 -0
  24. data/lib/overcommit/hook/commit_msg/single_line_subject.rb +16 -0
  25. data/lib/overcommit/hook/commit_msg/spell_check.rb +45 -0
  26. data/lib/overcommit/hook/commit_msg/text_width.rb +56 -0
  27. data/lib/overcommit/hook/commit_msg/trailing_period.rb +16 -0
  28. data/lib/overcommit/hook/post_checkout/base.rb +22 -0
  29. data/lib/overcommit/hook/post_checkout/bower_install.rb +13 -0
  30. data/lib/overcommit/hook/post_checkout/bundle_install.rb +13 -0
  31. data/lib/overcommit/hook/post_checkout/composer_install.rb +13 -0
  32. data/lib/overcommit/hook/post_checkout/index_tags.rb +12 -0
  33. data/lib/overcommit/hook/post_checkout/npm_install.rb +13 -0
  34. data/lib/overcommit/hook/post_checkout/submodule_status.rb +12 -0
  35. data/lib/overcommit/hook/post_checkout/yarn_install.rb +13 -0
  36. data/lib/overcommit/hook/post_commit/base.rb +12 -0
  37. data/lib/overcommit/hook/post_commit/bower_install.rb +13 -0
  38. data/lib/overcommit/hook/post_commit/bundle_install.rb +13 -0
  39. data/lib/overcommit/hook/post_commit/commitplease.rb +16 -0
  40. data/lib/overcommit/hook/post_commit/composer_install.rb +13 -0
  41. data/lib/overcommit/hook/post_commit/git_guilt.rb +43 -0
  42. data/lib/overcommit/hook/post_commit/index_tags.rb +12 -0
  43. data/lib/overcommit/hook/post_commit/npm_install.rb +13 -0
  44. data/lib/overcommit/hook/post_commit/submodule_status.rb +12 -0
  45. data/lib/overcommit/hook/post_commit/yarn_install.rb +13 -0
  46. data/lib/overcommit/hook/post_merge/base.rb +12 -0
  47. data/lib/overcommit/hook/post_merge/bower_install.rb +13 -0
  48. data/lib/overcommit/hook/post_merge/bundle_install.rb +13 -0
  49. data/lib/overcommit/hook/post_merge/composer_install.rb +13 -0
  50. data/lib/overcommit/hook/post_merge/index_tags.rb +12 -0
  51. data/lib/overcommit/hook/post_merge/npm_install.rb +13 -0
  52. data/lib/overcommit/hook/post_merge/submodule_status.rb +12 -0
  53. data/lib/overcommit/hook/post_merge/yarn_install.rb +13 -0
  54. data/lib/overcommit/hook/post_rewrite/base.rb +12 -0
  55. data/lib/overcommit/hook/post_rewrite/bower_install.rb +13 -0
  56. data/lib/overcommit/hook/post_rewrite/bundle_install.rb +13 -0
  57. data/lib/overcommit/hook/post_rewrite/composer_install.rb +13 -0
  58. data/lib/overcommit/hook/post_rewrite/index_tags.rb +19 -0
  59. data/lib/overcommit/hook/post_rewrite/npm_install.rb +13 -0
  60. data/lib/overcommit/hook/post_rewrite/submodule_status.rb +12 -0
  61. data/lib/overcommit/hook/post_rewrite/yarn_install.rb +13 -0
  62. data/lib/overcommit/hook/pre_commit/author_email.rb +26 -0
  63. data/lib/overcommit/hook/pre_commit/author_name.rb +25 -0
  64. data/lib/overcommit/hook/pre_commit/base.rb +19 -0
  65. data/lib/overcommit/hook/pre_commit/berksfile_check.rb +24 -0
  66. data/lib/overcommit/hook/pre_commit/broken_symlinks.rb +17 -0
  67. data/lib/overcommit/hook/pre_commit/bundle_audit.rb +24 -0
  68. data/lib/overcommit/hook/pre_commit/bundle_check.rb +32 -0
  69. data/lib/overcommit/hook/pre_commit/bundle_outdated.rb +25 -0
  70. data/lib/overcommit/hook/pre_commit/case_conflicts.rb +27 -0
  71. data/lib/overcommit/hook/pre_commit/chamber_compare.rb +43 -0
  72. data/lib/overcommit/hook/pre_commit/chamber_security.rb +15 -0
  73. data/lib/overcommit/hook/pre_commit/chamber_verification.rb +36 -0
  74. data/lib/overcommit/hook/pre_commit/code_spell_check.rb +36 -0
  75. data/lib/overcommit/hook/pre_commit/coffee_lint.rb +35 -0
  76. data/lib/overcommit/hook/pre_commit/cook_style.rb +35 -0
  77. data/lib/overcommit/hook/pre_commit/credo.rb +27 -0
  78. data/lib/overcommit/hook/pre_commit/css_lint.rb +26 -0
  79. data/lib/overcommit/hook/pre_commit/dogma.rb +33 -0
  80. data/lib/overcommit/hook/pre_commit/es_lint.rb +38 -0
  81. data/lib/overcommit/hook/pre_commit/execute_permissions.rb +76 -0
  82. data/lib/overcommit/hook/pre_commit/fasterer.rb +25 -0
  83. data/lib/overcommit/hook/pre_commit/file_size.rb +47 -0
  84. data/lib/overcommit/hook/pre_commit/fix_me.rb +17 -0
  85. data/lib/overcommit/hook/pre_commit/flay.rb +38 -0
  86. data/lib/overcommit/hook/pre_commit/foodcritic.rb +149 -0
  87. data/lib/overcommit/hook/pre_commit/forbidden_branches.rb +26 -0
  88. data/lib/overcommit/hook/pre_commit/ginkgo_focus.rb +23 -0
  89. data/lib/overcommit/hook/pre_commit/go_fmt.rb +17 -0
  90. data/lib/overcommit/hook/pre_commit/go_lint.rb +29 -0
  91. data/lib/overcommit/hook/pre_commit/go_vet.rb +24 -0
  92. data/lib/overcommit/hook/pre_commit/golangci_lint.rb +21 -0
  93. data/lib/overcommit/hook/pre_commit/hadolint.rb +27 -0
  94. data/lib/overcommit/hook/pre_commit/haml_lint.rb +23 -0
  95. data/lib/overcommit/hook/pre_commit/hard_tabs.rb +15 -0
  96. data/lib/overcommit/hook/pre_commit/hlint.rb +34 -0
  97. data/lib/overcommit/hook/pre_commit/html_hint.rb +23 -0
  98. data/lib/overcommit/hook/pre_commit/html_tidy.rb +30 -0
  99. data/lib/overcommit/hook/pre_commit/image_optim.rb +28 -0
  100. data/lib/overcommit/hook/pre_commit/java_checkstyle.rb +27 -0
  101. data/lib/overcommit/hook/pre_commit/js_hint.rb +23 -0
  102. data/lib/overcommit/hook/pre_commit/js_lint.rb +22 -0
  103. data/lib/overcommit/hook/pre_commit/jscs.rb +27 -0
  104. data/lib/overcommit/hook/pre_commit/jsl.rb +28 -0
  105. data/lib/overcommit/hook/pre_commit/json_syntax.rb +21 -0
  106. data/lib/overcommit/hook/pre_commit/kt_lint.rb +19 -0
  107. data/lib/overcommit/hook/pre_commit/license_finder.rb +14 -0
  108. data/lib/overcommit/hook/pre_commit/license_header.rb +48 -0
  109. data/lib/overcommit/hook/pre_commit/line_endings.rb +77 -0
  110. data/lib/overcommit/hook/pre_commit/local_paths_in_gemfile.rb +16 -0
  111. data/lib/overcommit/hook/pre_commit/mdl.rb +29 -0
  112. data/lib/overcommit/hook/pre_commit/merge_conflicts.rb +16 -0
  113. data/lib/overcommit/hook/pre_commit/nginx_test.rb +26 -0
  114. data/lib/overcommit/hook/pre_commit/pep257.rb +23 -0
  115. data/lib/overcommit/hook/pre_commit/pep8.rb +23 -0
  116. data/lib/overcommit/hook/pre_commit/php_cs.rb +43 -0
  117. data/lib/overcommit/hook/pre_commit/php_cs_fixer.rb +57 -0
  118. data/lib/overcommit/hook/pre_commit/php_lint.rb +44 -0
  119. data/lib/overcommit/hook/pre_commit/php_stan.rb +30 -0
  120. data/lib/overcommit/hook/pre_commit/pronto.rb +12 -0
  121. data/lib/overcommit/hook/pre_commit/puppet_lint.rb +26 -0
  122. data/lib/overcommit/hook/pre_commit/puppet_metadata_json_lint.rb +29 -0
  123. data/lib/overcommit/hook/pre_commit/pycodestyle.rb +23 -0
  124. data/lib/overcommit/hook/pre_commit/pydocstyle.rb +23 -0
  125. data/lib/overcommit/hook/pre_commit/pyflakes.rb +32 -0
  126. data/lib/overcommit/hook/pre_commit/pylint.rb +32 -0
  127. data/lib/overcommit/hook/pre_commit/python_flake8.rb +32 -0
  128. data/lib/overcommit/hook/pre_commit/rails_best_practices.rb +34 -0
  129. data/lib/overcommit/hook/pre_commit/rails_schema_up_to_date.rb +58 -0
  130. data/lib/overcommit/hook/pre_commit/rake_target.rb +12 -0
  131. data/lib/overcommit/hook/pre_commit/reek.rb +26 -0
  132. data/lib/overcommit/hook/pre_commit/rst_lint.rb +27 -0
  133. data/lib/overcommit/hook/pre_commit/rubo_cop.rb +35 -0
  134. data/lib/overcommit/hook/pre_commit/ruby_lint.rb +23 -0
  135. data/lib/overcommit/hook/pre_commit/ruby_syntax.rb +27 -0
  136. data/lib/overcommit/hook/pre_commit/scalariform.rb +22 -0
  137. data/lib/overcommit/hook/pre_commit/scalastyle.rb +31 -0
  138. data/lib/overcommit/hook/pre_commit/scss_lint.rb +43 -0
  139. data/lib/overcommit/hook/pre_commit/semi_standard.rb +23 -0
  140. data/lib/overcommit/hook/pre_commit/shell_check.rb +23 -0
  141. data/lib/overcommit/hook/pre_commit/slim_lint.rb +23 -0
  142. data/lib/overcommit/hook/pre_commit/sqlint.rb +26 -0
  143. data/lib/overcommit/hook/pre_commit/standard.rb +23 -0
  144. data/lib/overcommit/hook/pre_commit/stylelint.rb +23 -0
  145. data/lib/overcommit/hook/pre_commit/swift_lint.rb +19 -0
  146. data/lib/overcommit/hook/pre_commit/terraform_format.rb +19 -0
  147. data/lib/overcommit/hook/pre_commit/trailing_whitespace.rb +15 -0
  148. data/lib/overcommit/hook/pre_commit/travis_lint.rb +15 -0
  149. data/lib/overcommit/hook/pre_commit/ts_lint.rb +28 -0
  150. data/lib/overcommit/hook/pre_commit/vint.rb +22 -0
  151. data/lib/overcommit/hook/pre_commit/w3c_css.rb +67 -0
  152. data/lib/overcommit/hook/pre_commit/w3c_html.rb +64 -0
  153. data/lib/overcommit/hook/pre_commit/xml_lint.rb +24 -0
  154. data/lib/overcommit/hook/pre_commit/xml_syntax.rb +21 -0
  155. data/lib/overcommit/hook/pre_commit/yaml_lint.rb +18 -0
  156. data/lib/overcommit/hook/pre_commit/yaml_syntax.rb +20 -0
  157. data/lib/overcommit/hook/pre_commit/yard_coverage.rb +90 -0
  158. data/lib/overcommit/hook/pre_commit/yarn_check.rb +37 -0
  159. data/lib/overcommit/hook/pre_push/base.rb +33 -0
  160. data/lib/overcommit/hook/pre_push/brakeman.rb +15 -0
  161. data/lib/overcommit/hook/pre_push/cargo_test.rb +12 -0
  162. data/lib/overcommit/hook/pre_push/go_test.rb +14 -0
  163. data/lib/overcommit/hook/pre_push/golangci_lint.rb +16 -0
  164. data/lib/overcommit/hook/pre_push/minitest.rb +20 -0
  165. data/lib/overcommit/hook/pre_push/php_unit.rb +16 -0
  166. data/lib/overcommit/hook/pre_push/pronto.rb +12 -0
  167. data/lib/overcommit/hook/pre_push/protected_branches.rb +74 -0
  168. data/lib/overcommit/hook/pre_push/pytest.rb +16 -0
  169. data/lib/overcommit/hook/pre_push/python_nose.rb +16 -0
  170. data/lib/overcommit/hook/pre_push/r_spec.rb +16 -0
  171. data/lib/overcommit/hook/pre_push/rake_target.rb +12 -0
  172. data/lib/overcommit/hook/pre_push/test_unit.rb +16 -0
  173. data/lib/overcommit/hook/pre_rebase/base.rb +14 -0
  174. data/lib/overcommit/hook/pre_rebase/merged_commits.rb +31 -0
  175. data/lib/overcommit/hook/prepare_commit_msg/base.rb +25 -0
  176. data/lib/overcommit/hook/prepare_commit_msg/replace_branch.rb +57 -0
  177. data/lib/overcommit/hook/shared/bower_install.rb +15 -0
  178. data/lib/overcommit/hook/shared/bundle_install.rb +15 -0
  179. data/lib/overcommit/hook/shared/composer_install.rb +15 -0
  180. data/lib/overcommit/hook/shared/index_tags.rb +14 -0
  181. data/lib/overcommit/hook/shared/npm_install.rb +15 -0
  182. data/lib/overcommit/hook/shared/pronto.rb +21 -0
  183. data/lib/overcommit/hook/shared/rake_target.rb +26 -0
  184. data/lib/overcommit/hook/shared/submodule_status.rb +32 -0
  185. data/lib/overcommit/hook/shared/yarn_install.rb +15 -0
  186. data/lib/overcommit/hook_context.rb +19 -0
  187. data/lib/overcommit/hook_context/base.rb +139 -0
  188. data/lib/overcommit/hook_context/commit_msg.rb +48 -0
  189. data/lib/overcommit/hook_context/post_checkout.rb +36 -0
  190. data/lib/overcommit/hook_context/post_commit.rb +33 -0
  191. data/lib/overcommit/hook_context/post_merge.rb +37 -0
  192. data/lib/overcommit/hook_context/post_rewrite.rb +49 -0
  193. data/lib/overcommit/hook_context/pre_commit.rb +212 -0
  194. data/lib/overcommit/hook_context/pre_push.rb +89 -0
  195. data/lib/overcommit/hook_context/pre_rebase.rb +38 -0
  196. data/lib/overcommit/hook_context/prepare_commit_msg.rb +34 -0
  197. data/lib/overcommit/hook_context/run_all.rb +48 -0
  198. data/lib/overcommit/hook_loader/base.rb +48 -0
  199. data/lib/overcommit/hook_loader/built_in_hook_loader.rb +14 -0
  200. data/lib/overcommit/hook_loader/plugin_hook_loader.rb +102 -0
  201. data/lib/overcommit/hook_runner.rb +219 -0
  202. data/lib/overcommit/hook_signer.rb +123 -0
  203. data/lib/overcommit/installer.rb +193 -0
  204. data/lib/overcommit/interrupt_handler.rb +91 -0
  205. data/lib/overcommit/logger.rb +92 -0
  206. data/lib/overcommit/message_processor.rb +148 -0
  207. data/lib/overcommit/os.rb +38 -0
  208. data/lib/overcommit/printer.rb +145 -0
  209. data/lib/overcommit/subprocess.rb +98 -0
  210. data/lib/overcommit/utils.rb +309 -0
  211. data/lib/overcommit/utils/file_utils.rb +71 -0
  212. data/lib/overcommit/utils/messages_utils.rb +77 -0
  213. data/lib/overcommit/version.rb +6 -0
  214. data/libexec/gerrit-change-id +174 -0
  215. data/libexec/index-tags +17 -0
  216. data/template-dir/hooks/commit-msg +116 -0
  217. data/template-dir/hooks/overcommit-hook +116 -0
  218. data/template-dir/hooks/post-checkout +116 -0
  219. data/template-dir/hooks/post-commit +116 -0
  220. data/template-dir/hooks/post-merge +116 -0
  221. data/template-dir/hooks/post-rewrite +116 -0
  222. data/template-dir/hooks/pre-commit +116 -0
  223. data/template-dir/hooks/pre-push +116 -0
  224. data/template-dir/hooks/pre-rebase +116 -0
  225. data/template-dir/hooks/prepare-commit-msg +116 -0
  226. metadata +303 -0
@@ -0,0 +1,33 @@
1
+ # Use this file to configure the Overcommit hooks you wish to use. This will
2
+ # extend the default configuration defined in:
3
+ # https://github.com/sds/overcommit/blob/master/config/default.yml
4
+ #
5
+ # At the topmost level of this YAML file is a key representing type of hook
6
+ # being run (e.g. pre-commit, commit-msg, etc.). Within each type you can
7
+ # customize each hook, such as whether to only run it on certain files (via
8
+ # `include`), whether to only display output if it fails (via `quiet`), etc.
9
+ #
10
+ # For a complete list of hooks, see:
11
+ # https://github.com/sds/overcommit/tree/master/lib/overcommit/hook
12
+ #
13
+ # For a complete list of options that you can use to customize hooks, see:
14
+ # https://github.com/sds/overcommit#configuration
15
+ #
16
+ # Uncomment the following lines to make the configuration take effect.
17
+
18
+ #PreCommit:
19
+ # RuboCop:
20
+ # enabled: true
21
+ # on_warn: fail # Treat all warnings as failures
22
+ #
23
+ # TrailingWhitespace:
24
+ # enabled: true
25
+ # exclude:
26
+ # - '**/db/structure.sql' # Ignore trailing whitespace in generated files
27
+ #
28
+ #PostCheckout:
29
+ # ALL: # Special hook name that customizes all hooks of this type
30
+ # quiet: true # Change all post-checkout hooks to only display output on failure
31
+ #
32
+ # IndexTags:
33
+ # enabled: true # Generate a tags file with `ctags` each time HEAD changes
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'overcommit/os'
4
+ require 'overcommit/constants'
5
+ require 'overcommit/exceptions'
6
+ require 'overcommit/utils/file_utils'
7
+ require 'overcommit/utils'
8
+ require 'overcommit/git_version'
9
+ require 'overcommit/configuration_validator'
10
+ require 'overcommit/configuration'
11
+ require 'overcommit/configuration_loader'
12
+ require 'overcommit/hook/base'
13
+ require 'overcommit/hook_context/base'
14
+ require 'overcommit/hook_context'
15
+ require 'overcommit/git_config'
16
+ require 'overcommit/git_repo'
17
+ require 'overcommit/hook_signer'
18
+ require 'overcommit/hook_loader/base'
19
+ require 'overcommit/hook_loader/built_in_hook_loader'
20
+ require 'overcommit/hook_loader/plugin_hook_loader'
21
+ require 'overcommit/interrupt_handler'
22
+ require 'overcommit/printer'
23
+ require 'overcommit/hook_runner'
24
+ require 'overcommit/installer'
25
+ require 'overcommit/logger'
26
+ require 'overcommit/version'
@@ -0,0 +1,223 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'overcommit'
4
+ require 'optparse'
5
+
6
+ module Overcommit
7
+ # Responsible for parsing command-line options and executing appropriate
8
+ # application logic based on those options.
9
+ class CLI # rubocop:disable ClassLength
10
+ def initialize(arguments, input, logger)
11
+ @arguments = arguments
12
+ @input = input
13
+ @log = logger
14
+ @options = {}
15
+
16
+ Overcommit::Utils.log = logger
17
+ end
18
+
19
+ def run
20
+ parse_arguments
21
+
22
+ case @options[:action]
23
+ when :install, :uninstall
24
+ install_or_uninstall
25
+ when :template_dir
26
+ print_template_directory_path
27
+ when :sign
28
+ sign
29
+ when :run_all
30
+ run_all
31
+ end
32
+ rescue Overcommit::Exceptions::ConfigurationSignatureChanged => ex
33
+ puts ex
34
+ exit 78 # EX_CONFIG
35
+ rescue Overcommit::Exceptions::HookContextLoadError => ex
36
+ puts ex
37
+ exit 64 # EX_USAGE
38
+ end
39
+
40
+ private
41
+
42
+ attr_reader :log
43
+
44
+ def parse_arguments
45
+ @parser = create_option_parser
46
+
47
+ begin
48
+ @parser.parse!(@arguments)
49
+
50
+ # Default action is to install
51
+ @options[:action] ||= :install
52
+
53
+ # Unconsumed arguments are our targets
54
+ @options[:targets] = @arguments
55
+ rescue OptionParser::InvalidOption => ex
56
+ print_help @parser.help, ex
57
+ end
58
+ end
59
+
60
+ def create_option_parser
61
+ OptionParser.new do |opts|
62
+ opts.banner = "Usage: #{opts.program_name} [options] [target-repo]"
63
+
64
+ add_information_options(opts)
65
+ add_installation_options(opts)
66
+ add_other_options(opts)
67
+ end
68
+ end
69
+
70
+ def add_information_options(opts)
71
+ opts.on_tail('-h', '--help', 'Show this message') do
72
+ print_help opts.help
73
+ end
74
+
75
+ opts.on_tail('-v', '--version', 'Show version') do
76
+ print_version(opts.program_name)
77
+ end
78
+
79
+ opts.on_tail('-l', '--list-hooks', 'List installed hooks') do
80
+ print_installed_hooks
81
+ end
82
+ end
83
+
84
+ def add_installation_options(opts)
85
+ opts.on('-u', '--uninstall', 'Remove Overcommit hooks from a repository') do
86
+ @options[:action] = :uninstall
87
+ end
88
+
89
+ opts.on('-i', '--install', 'Install Overcommit hooks in a repository') do
90
+ @options[:action] = :install
91
+ end
92
+
93
+ opts.on('-f', '--force', 'Overwrite any previously installed hooks') do
94
+ @options[:force] = true
95
+ end
96
+
97
+ opts.on('-r', '--run', 'Run pre-commit hook against all git tracked files') do
98
+ @options[:action] = :run_all
99
+ end
100
+ end
101
+
102
+ def add_other_options(opts)
103
+ opts.on('-s', '--sign [hook]', 'Update hook signatures', String) do |hook_to_sign|
104
+ @options[:hook_to_sign] = hook_to_sign if hook_to_sign.is_a?(String)
105
+ @options[:action] = :sign
106
+ end
107
+
108
+ opts.on('-t', '--template-dir', 'Print location of template directory') do
109
+ @options[:action] = :template_dir
110
+ end
111
+ end
112
+
113
+ def install_or_uninstall
114
+ if Array(@options[:targets]).empty?
115
+ @options[:targets] = [Overcommit::Utils.repo_root].compact
116
+ end
117
+
118
+ if @options[:targets].empty?
119
+ log.warning 'You are not in a git repository.'
120
+ log.log 'You must either specify the path to a repository or ' \
121
+ 'change your current directory to a repository.'
122
+ halt 64 # EX_USAGE
123
+ end
124
+
125
+ @options[:targets].each do |target|
126
+ begin
127
+ Installer.new(log).run(target, @options)
128
+ rescue Overcommit::Exceptions::InvalidGitRepo => error
129
+ log.warning "Invalid repo #{target}: #{error}"
130
+ halt 69 # EX_UNAVAILABLE
131
+ rescue Overcommit::Exceptions::PreExistingHooks => error
132
+ log.warning "Unable to install into #{target}: #{error}"
133
+ halt 73 # EX_CANTCREAT
134
+ end
135
+ end
136
+ end
137
+
138
+ def print_template_directory_path
139
+ puts File.join(Overcommit::HOME, 'template-dir')
140
+ halt
141
+ end
142
+
143
+ def print_help(message, error = nil)
144
+ log.error "#{error}\n" if error
145
+ log.log message
146
+ halt(error ? 64 : 0) # 64 = EX_USAGE
147
+ end
148
+
149
+ def print_version(program_name)
150
+ log.log "#{program_name} #{Overcommit::VERSION}"
151
+ halt
152
+ end
153
+
154
+ # Prints the hooks available in the current repo and whether they're
155
+ # enabled/disabled.
156
+ def print_installed_hooks
157
+ config.all_hook_configs.each do |hook_type, hook_configs|
158
+ print_hooks_for_hook_type(config, hook_configs, hook_type)
159
+ end
160
+
161
+ halt
162
+ end
163
+
164
+ def print_hooks_for_hook_type(repo_config, hook_configs, hook_type)
165
+ log.log "#{hook_type}:"
166
+ hook_configs.each do |hook_name, config|
167
+ log.partial " #{hook_name}: "
168
+
169
+ if config['enabled']
170
+ log.success('enabled', true)
171
+ else
172
+ log.error('disabled', true)
173
+ end
174
+
175
+ if repo_config.plugin_hook?(hook_type, hook_name)
176
+ log.warning(' (plugin)')
177
+ else
178
+ log.newline
179
+ end
180
+ end
181
+ end
182
+
183
+ def sign
184
+ if @options[:hook_to_sign]
185
+ context = Overcommit::HookContext.create(@options[:hook_to_sign],
186
+ config,
187
+ @arguments,
188
+ @input)
189
+ Overcommit::HookLoader::PluginHookLoader.new(config,
190
+ context,
191
+ log).update_signatures
192
+ else
193
+ log.log 'Updating signature for configuration file...'
194
+ config(verify: false).update_signature!
195
+ end
196
+
197
+ halt
198
+ end
199
+
200
+ def run_all
201
+ empty_stdin = File.open(File::NULL) # pre-commit hooks don't take input
202
+ context = Overcommit::HookContext.create('run-all', config, @arguments, empty_stdin)
203
+ config.apply_environment!(context, ENV)
204
+
205
+ printer = Overcommit::Printer.new(config, log, context)
206
+ runner = Overcommit::HookRunner.new(config, log, context, printer)
207
+
208
+ status = runner.run
209
+
210
+ halt(status ? 0 : 65)
211
+ end
212
+
213
+ # Used for ease of stubbing in tests
214
+ def halt(status = 0)
215
+ exit status
216
+ end
217
+
218
+ # Returns the configuration for this repository.
219
+ def config(options = {})
220
+ @config ||= Overcommit::ConfigurationLoader.new(log, options).load_repo_config
221
+ end
222
+ end
223
+ end
@@ -0,0 +1,146 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Overcommit
4
+ # Distributes a list of arguments over multiple invocations of a command.
5
+ #
6
+ # This accomplishes the same functionality provided by `xargs` but in a
7
+ # cross-platform way that does not require any pre-existing tools.
8
+ #
9
+ # One of the tradeoffs with this approach is that we no longer deal with a
10
+ # single exit status from a command, but multiple (one for each invocation).
11
+ #
12
+ # This will return a struct similar to `Subprocess::Result` but with
13
+ # additional `statuses`, `stdouts`, and `stderrs` fields so hook authors can
14
+ # actually see the results of each invocation. If they don't care, the
15
+ # standard `status`, `stdout`, and `stderr` will still work but be a
16
+ # aggregation/concatenation of all statuses/outputs.
17
+ class CommandSplitter
18
+ # Encapsulates the result of a split argument run.
19
+ #
20
+ # @attr_reader statuses [Array<Integer>] status codes for invocations
21
+ # @attr_reader stdouts [Array<String>] standard outputs from invocations
22
+ # @attr_reader stderrs [Array<String>] standard error outputs from invocations
23
+ Result = Struct.new(:statuses, :stdouts, :stderrs) do
24
+ # Returns whether all invocations were successful.
25
+ #
26
+ # @return [true,false]
27
+ def success?
28
+ status == 0
29
+ end
30
+
31
+ # Returns `0` if all invocations returned `0`; `1` otherwise.
32
+ #
33
+ # @return [true,false]
34
+ def status
35
+ statuses.all? { |code| code == 0 } ? 0 : 1
36
+ end
37
+
38
+ # Returns concatenated standard output streams of all invocations in the
39
+ # order they were executed.
40
+ #
41
+ # @return [String]
42
+ def stdout
43
+ stdouts.join
44
+ end
45
+
46
+ # Returns concatenated standard error streams of all invocations in the
47
+ # order they were executed.
48
+ #
49
+ # @return [String]
50
+ def stderr
51
+ stderrs.join
52
+ end
53
+ end
54
+
55
+ class << self
56
+ def execute(initial_args, options)
57
+ options = options.dup
58
+
59
+ if (splittable_args = (options.delete(:args) { [] })).empty?
60
+ raise Overcommit::Exceptions::InvalidCommandArgs,
61
+ 'Must specify list of arguments to split on'
62
+ end
63
+
64
+ # Execute each chunk of arguments in serial. We don't parallelize (yet)
65
+ # since in theory we want to support parallelization at the hook level
66
+ # and not within individual hooks.
67
+ results = extract_argument_lists(initial_args, splittable_args).map do |arg_list|
68
+ Overcommit::Subprocess.spawn(arg_list, options)
69
+ end
70
+
71
+ Result.new(results.map(&:status), results.map(&:stdout), results.map(&:stderr))
72
+ end
73
+
74
+ private
75
+
76
+ # Given a list of prefix arguments and suffix arguments that can be split,
77
+ # returns a list of argument lists that are executable on the current OS
78
+ # without exceeding command line limitations.
79
+ def extract_argument_lists(args, splittable_args)
80
+ # Total number of bytes needed to contain the prefix command
81
+ # (including byte separators between each argument)
82
+ prefix_bytes = (args.size - 1) + args.reduce(0) { |sum, arg| sum + arg.bytesize }
83
+
84
+ if prefix_bytes >= max_command_length
85
+ raise Overcommit::Exceptions::InvalidCommandArgs,
86
+ "Command `#{args.take(5).join(' ')} ...` is longer than the " \
87
+ 'maximum number of bytes allowed by the operating system ' \
88
+ "(#{max_command_length})"
89
+ end
90
+
91
+ arg_lists = []
92
+ index = 0
93
+ while index <= splittable_args.length - 1
94
+ arg_list, index = arguments_under_limit(splittable_args,
95
+ index,
96
+ max_command_length - prefix_bytes)
97
+ arg_lists << args + arg_list
98
+ end
99
+
100
+ arg_lists
101
+ end
102
+
103
+ # @return [Array<Array<String>, Integer>] tuple of arguments and new index
104
+ def arguments_under_limit(splittable_args, start_index, byte_limit)
105
+ index = start_index
106
+ total_bytes = 0
107
+
108
+ loop do
109
+ break if index > splittable_args.length - 1
110
+ total_bytes += splittable_args[index].bytesize
111
+ break if total_bytes > byte_limit # Not enough room
112
+ index += 1
113
+ end
114
+
115
+ if index == start_index
116
+ # No argument was consumed; perhaps a really long argument?
117
+ raise Overcommit::Exceptions::InvalidCommandArgs,
118
+ "Argument `#{splittable_args[index][0..5]}...` exceeds the " \
119
+ 'maximum command length when appended to command prefix and ' \
120
+ "can't be split further"
121
+ end
122
+
123
+ [splittable_args[start_index...index], index]
124
+ end
125
+
126
+ # Returns the maximum number of arguments allowed in a single command on
127
+ # this system.
128
+ #
129
+ # @return [Integer]
130
+ def max_command_length
131
+ @max_command_length ||=
132
+ if Gem.win_platform?
133
+ # Windows is limited to 2048 since that is a worst-case scenario.
134
+ # http://blogs.msdn.com/b/oldnewthing/archive/2003/12/10/56028.aspx
135
+ 2048
136
+ else
137
+ # We fudge factor this by halving the buffer size since *nix systems
138
+ # usually have pretty large limits, and the actual limit changes
139
+ # depending on how much of your stack is environment variables.
140
+ # Definitely erring on the side of overly cautious.
141
+ `getconf ARG_MAX`.to_i / 2
142
+ end
143
+ end
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,350 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'digest'
4
+ require 'json'
5
+
6
+ module Overcommit
7
+ # Stores configuration for Overcommit and the hooks it runs.
8
+ class Configuration # rubocop:disable ClassLength
9
+ # Creates a configuration from the given hash.
10
+ #
11
+ # @param hash [Hash] loaded YAML config file as a hash
12
+ # @param options [Hash]
13
+ # @option default [Boolean] whether this is the default built-in configuration
14
+ # @option logger [Overcommit::Logger]
15
+ def initialize(hash, options = {})
16
+ @options = options.dup
17
+ @options[:logger] ||= Overcommit::Logger.silent
18
+ @hash = hash # Assign so validator can read original values
19
+ unless options[:validate] == false
20
+ @hash = Overcommit::ConfigurationValidator.new.validate(self, hash, options)
21
+ end
22
+ end
23
+
24
+ def ==(other)
25
+ super || @hash == other.hash
26
+ end
27
+
28
+ # Access the configuration as if it were a hash.
29
+ #
30
+ # @param key [String]
31
+ # @return [Array,Hash,Number,String]
32
+ def [](key)
33
+ @hash[key]
34
+ end
35
+
36
+ # Returns absolute path to the directory that external hook plugins should
37
+ # be loaded from.
38
+ def plugin_directory
39
+ File.join(Overcommit::Utils.repo_root, @hash['plugin_directory'] || '.git-hooks')
40
+ end
41
+
42
+ def concurrency
43
+ @concurrency ||=
44
+ begin
45
+ cores = Overcommit::Utils.processor_count
46
+ content = @hash.fetch('concurrency') { '%<processors>d' }
47
+ if content.is_a?(String)
48
+ concurrency_expr = content % { processors: cores }
49
+
50
+ a, op, b = concurrency_expr.scan(%r{(\d+)\s*([+\-*\/])\s*(\d+)})[0]
51
+ if a
52
+ a.to_i.send(op, b.to_i)
53
+ else
54
+ concurrency_expr.to_i
55
+ end
56
+ else
57
+ content.to_i
58
+ end
59
+ end
60
+ end
61
+
62
+ # Returns configuration for all hooks in each hook type.
63
+ #
64
+ # @return [Hash]
65
+ def all_hook_configs
66
+ smart_merge(all_builtin_hook_configs, all_plugin_hook_configs)
67
+ end
68
+
69
+ # Returns configuration for all built-in hooks in each hook type.
70
+ #
71
+ # @return [Hash]
72
+ def all_builtin_hook_configs
73
+ hook_configs = {}
74
+
75
+ Overcommit::Utils.supported_hook_type_classes.each do |hook_type|
76
+ hook_names = @hash[hook_type].keys.reject { |name| name == 'ALL' }
77
+
78
+ hook_configs[hook_type] = Hash[
79
+ hook_names.map do |hook_name|
80
+ [hook_name, for_hook(hook_name, hook_type)]
81
+ end
82
+ ]
83
+ end
84
+
85
+ hook_configs
86
+ end
87
+
88
+ # Returns configuration for all plugin hooks in each hook type.
89
+ #
90
+ # @return [Hash]
91
+ def all_plugin_hook_configs
92
+ hook_configs = {}
93
+
94
+ Overcommit::Utils.supported_hook_types.each do |hook_type|
95
+ hook_type_class_name = Overcommit::Utils.camel_case(hook_type)
96
+
97
+ directory = File.join(plugin_directory, hook_type.tr('-', '_'))
98
+ plugin_paths = Dir[File.join(directory, '*.rb')].sort
99
+
100
+ hook_names = plugin_paths.map do |path|
101
+ Overcommit::Utils.camel_case(File.basename(path, '.rb'))
102
+ end
103
+
104
+ hook_configs[hook_type_class_name] = Hash[
105
+ hook_names.map do |hook_name|
106
+ [hook_name, for_hook(hook_name, Overcommit::Utils.camel_case(hook_type))]
107
+ end
108
+ ]
109
+ end
110
+
111
+ hook_configs
112
+ end
113
+
114
+ # Returns the built-in hooks that have been enabled for a hook type.
115
+ def enabled_builtin_hooks(hook_context)
116
+ @hash[hook_context.hook_class_name].keys.
117
+ reject { |hook_name| hook_name == 'ALL' }.
118
+ select { |hook_name| built_in_hook?(hook_context, hook_name) }.
119
+ select { |hook_name| hook_enabled?(hook_context, hook_name) }
120
+ end
121
+
122
+ # Returns the ad hoc hooks that have been enabled for a hook type.
123
+ def enabled_ad_hoc_hooks(hook_context)
124
+ @hash[hook_context.hook_class_name].keys.
125
+ reject { |hook_name| hook_name == 'ALL' }.
126
+ select { |hook_name| ad_hoc_hook?(hook_context, hook_name) }.
127
+ select { |hook_name| hook_enabled?(hook_context, hook_name) }
128
+ end
129
+
130
+ # Returns a non-modifiable configuration for a hook.
131
+ def for_hook(hook, hook_type = nil)
132
+ unless hook_type
133
+ components = hook.class.name.split('::')
134
+ hook = components.last
135
+ hook_type = components[-2]
136
+ end
137
+
138
+ # Merge hook configuration with special 'ALL' config
139
+ hook_config = smart_merge(@hash[hook_type]['ALL'], @hash[hook_type][hook] || {})
140
+
141
+ # Need to specially handle `enabled` option since not setting it does not
142
+ # necessarily mean the hook is disabled
143
+ hook_config['enabled'] = hook_enabled?(hook_type, hook)
144
+
145
+ hook_config.freeze
146
+ end
147
+
148
+ # Merges the given configuration with this one, returning a new
149
+ # {Configuration}. The provided configuration will either add to or replace
150
+ # any options defined in this configuration.
151
+ def merge(config)
152
+ self.class.new(smart_merge(@hash, config.hash))
153
+ end
154
+
155
+ # Applies additional configuration settings based on the provided
156
+ # environment variables.
157
+ def apply_environment!(hook_context, env)
158
+ skipped_hooks = "#{env['SKIP']} #{env['SKIP_CHECKS']} #{env['SKIP_HOOKS']}".split(/[:, ]/)
159
+ only_hooks = env.fetch('ONLY') { '' }.split(/[:, ]/)
160
+ hook_type = hook_context.hook_class_name
161
+
162
+ if only_hooks.any? || skipped_hooks.include?('all') || skipped_hooks.include?('ALL')
163
+ @hash[hook_type]['ALL']['skip'] = true
164
+ end
165
+
166
+ only_hooks.select { |hook_name| hook_exists?(hook_context, hook_name) }.
167
+ map { |hook_name| Overcommit::Utils.camel_case(hook_name) }.
168
+ each do |hook_name|
169
+ @hash[hook_type][hook_name] ||= {}
170
+ @hash[hook_type][hook_name]['skip'] = false
171
+ end
172
+
173
+ skipped_hooks.select { |hook_name| hook_exists?(hook_context, hook_name) }.
174
+ map { |hook_name| Overcommit::Utils.camel_case(hook_name) }.
175
+ each do |hook_name|
176
+ @hash[hook_type][hook_name] ||= {}
177
+ @hash[hook_type][hook_name]['skip'] = true
178
+ end
179
+ end
180
+
181
+ def plugin_hook?(hook_context_or_type, hook_name)
182
+ hook_type_name =
183
+ if hook_context_or_type.is_a?(String)
184
+ Overcommit::Utils.snake_case(hook_context_or_type)
185
+ else
186
+ hook_context_or_type.hook_type_name
187
+ end
188
+ hook_name = Overcommit::Utils.snake_case(hook_name)
189
+
190
+ File.exist?(File.join(plugin_directory, hook_type_name, "#{hook_name}.rb"))
191
+ end
192
+
193
+ # Return whether the signature for this configuration has changed since it
194
+ # was last calculated.
195
+ #
196
+ # @return [true,false]
197
+ def signature_changed?
198
+ signature != stored_signature
199
+ end
200
+
201
+ # Return whether a previous signature has been recorded for this
202
+ # configuration.
203
+ #
204
+ # @return [true,false]
205
+ def previous_signature?
206
+ !stored_signature.empty?
207
+ end
208
+
209
+ # Returns whether this configuration should verify itself by checking the
210
+ # stored configuration for the repo.
211
+ #
212
+ # @return [true,false]
213
+ def verify_signatures?
214
+ return false if ENV['OVERCOMMIT_NO_VERIFY']
215
+ return true if @hash['verify_signatures'] != false
216
+
217
+ result = Overcommit::Utils.execute(
218
+ %W[git config --local --get #{verify_signature_config_key}]
219
+ )
220
+
221
+ if result.status == 1 # Key doesn't exist
222
+ return true
223
+ elsif result.status != 0
224
+ raise Overcommit::Exceptions::GitConfigError,
225
+ "Unable to read from local repo git config: #{result.stderr}"
226
+ end
227
+
228
+ # We don't cast since we want to allow anything to count as "true" except
229
+ # a literal zero
230
+ result.stdout.strip != '0'
231
+ end
232
+
233
+ # Update the currently stored signature for this hook.
234
+ def update_signature!
235
+ result = Overcommit::Utils.execute(
236
+ %w[git config --local] + [signature_config_key, signature]
237
+ )
238
+
239
+ verify_signature_value = @hash['verify_signatures'] ? 1 : 0
240
+ result &&= Overcommit::Utils.execute(
241
+ %W[git config --local #{verify_signature_config_key} #{verify_signature_value}]
242
+ )
243
+
244
+ unless result.success?
245
+ raise Overcommit::Exceptions::GitConfigError,
246
+ "Unable to write to local repo git config: #{result.stderr}"
247
+ end
248
+ end
249
+
250
+ protected
251
+
252
+ attr_reader :hash
253
+
254
+ private
255
+
256
+ def ad_hoc_hook?(hook_context, hook_name)
257
+ ad_hoc_conf = @hash.fetch(hook_context.hook_class_name) { {} }.fetch(hook_name) { {} }
258
+
259
+ # Ad hoc hooks are neither built-in nor have a plugin file written but
260
+ # still have a `command` specified to be run
261
+ !built_in_hook?(hook_context, hook_name) &&
262
+ !plugin_hook?(hook_context, hook_name) &&
263
+ (ad_hoc_conf['command'] || ad_hoc_conf['required_executable'])
264
+ end
265
+
266
+ def built_in_hook?(hook_context, hook_name)
267
+ hook_name = Overcommit::Utils.snake_case(hook_name)
268
+
269
+ File.exist?(File.join(Overcommit::HOME, 'lib', 'overcommit', 'hook',
270
+ hook_context.hook_type_name, "#{hook_name}.rb"))
271
+ end
272
+
273
+ def hook_exists?(hook_context, hook_name)
274
+ built_in_hook?(hook_context, hook_name) ||
275
+ plugin_hook?(hook_context, hook_name) ||
276
+ ad_hoc_hook?(hook_context, hook_name)
277
+ end
278
+
279
+ def hook_enabled?(hook_context_or_type, hook_name)
280
+ hook_type =
281
+ if hook_context_or_type.is_a?(String)
282
+ hook_context_or_type
283
+ else
284
+ hook_context_or_type.hook_class_name
285
+ end
286
+
287
+ individual_enabled = @hash[hook_type].fetch(hook_name) { {} }['enabled']
288
+ return individual_enabled unless individual_enabled.nil?
289
+
290
+ all_enabled = @hash[hook_type]['ALL']['enabled']
291
+ return all_enabled unless all_enabled.nil?
292
+
293
+ false
294
+ end
295
+
296
+ def smart_merge(parent, child)
297
+ # Treat the ALL hook specially so that it overrides any configuration
298
+ # specified by the default configuration.
299
+ child_all = child['ALL']
300
+ unless child_all.nil?
301
+ parent = Hash[parent.collect { |k, v| [k, smart_merge(v, child_all)] }]
302
+ end
303
+
304
+ parent.merge(child) do |_key, old, new|
305
+ case old
306
+ when Hash
307
+ smart_merge(old, new)
308
+ else
309
+ new
310
+ end
311
+ end
312
+ end
313
+
314
+ # Returns the unique signature of this configuration.
315
+ #
316
+ # @return [String]
317
+ def signature
318
+ Digest::SHA256.hexdigest(@hash.to_json)
319
+ end
320
+
321
+ # Returns the stored signature of this repo's Overcommit configuration.
322
+ #
323
+ # This is intended to be compared against the current signature of this
324
+ # configuration object.
325
+ #
326
+ # @return [String]
327
+ def stored_signature
328
+ result = Overcommit::Utils.execute(
329
+ %w[git config --local --get] + [signature_config_key]
330
+ )
331
+
332
+ if result.status == 1 # Key doesn't exist
333
+ return ''
334
+ elsif result.status != 0
335
+ raise Overcommit::Exceptions::GitConfigError,
336
+ "Unable to read from local repo git config: #{result.stderr}"
337
+ end
338
+
339
+ result.stdout.chomp
340
+ end
341
+
342
+ def signature_config_key
343
+ 'overcommit.configuration.signature'
344
+ end
345
+
346
+ def verify_signature_config_key
347
+ 'overcommit.configuration.verifysignatures'
348
+ end
349
+ end
350
+ end