overcommit-jeygeethanmedia 0.53.1

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.
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