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,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yaml'
4
+
5
+ module Overcommit
6
+ # Manages configuration file loading.
7
+ class ConfigurationLoader
8
+ DEFAULT_CONFIG_PATH = File.join(Overcommit::HOME, 'config', 'default.yml')
9
+
10
+ class << self
11
+ # Loads and returns the default configuration.
12
+ #
13
+ # @return [Overcommit::Configuration]
14
+ def default_configuration
15
+ @default_configuration ||= load_from_file(DEFAULT_CONFIG_PATH, default: true, verify: false)
16
+ end
17
+
18
+ # Loads configuration from file.
19
+ #
20
+ # @param file [String] path to file
21
+ # @param options [Hash]
22
+ # @option default [Boolean] whether this is the default built-in configuration
23
+ # @option verify [Boolean] whether to verify the signature of the configuration
24
+ # @option logger [Overcommit::Logger]
25
+ # @return [Overcommit::Configuration]
26
+ def load_from_file(file, options = {})
27
+ hash =
28
+ if yaml = YAML.load_file(file)
29
+ yaml.to_hash
30
+ else
31
+ {}
32
+ end
33
+
34
+ Overcommit::Configuration.new(hash, options)
35
+ end
36
+ end
37
+
38
+ # Create a configuration loader which writes warnings/errors to the given
39
+ # {Overcommit::Logger} instance.
40
+ #
41
+ # @param logger [Overcommit::Logger]
42
+ # @param options [Hash]
43
+ # @option verify [Boolean] whether to verify signatures
44
+ def initialize(logger, options = {})
45
+ @log = logger
46
+ @options = options
47
+ end
48
+
49
+ # Loads and returns the configuration for the repository we're running in.
50
+ #
51
+ # @return [Overcommit::Configuration]
52
+ def load_repo_config
53
+ overcommit_yml = File.join(Overcommit::Utils.repo_root,
54
+ Overcommit::CONFIG_FILE_NAME)
55
+
56
+ if File.exist?(overcommit_yml)
57
+ load_file(overcommit_yml)
58
+ else
59
+ self.class.default_configuration
60
+ end
61
+ end
62
+
63
+ # Loads a configuration, ensuring it extends the default configuration.
64
+ def load_file(file)
65
+ config = self.class.load_from_file(file, default: false, logger: @log)
66
+ config = self.class.default_configuration.merge(config)
67
+
68
+ if @options.fetch(:verify) { config.verify_signatures? }
69
+ verify_signatures(config)
70
+ end
71
+
72
+ config
73
+ rescue Overcommit::Exceptions::ConfigurationSignatureChanged
74
+ raise
75
+ rescue StandardError => error
76
+ raise Overcommit::Exceptions::ConfigurationError,
77
+ "Unable to load configuration from '#{file}': #{error}",
78
+ error.backtrace
79
+ end
80
+
81
+ private
82
+
83
+ def verify_signatures(config)
84
+ if !config.previous_signature?
85
+ raise Overcommit::Exceptions::ConfigurationSignatureChanged,
86
+ "No previously recorded signature for configuration file.\n" \
87
+ 'Run `overcommit --sign` if you trust the hooks in this repository.'
88
+
89
+ elsif config.signature_changed?
90
+ raise Overcommit::Exceptions::ConfigurationSignatureChanged,
91
+ "Signature of configuration file has changed!\n" \
92
+ "Run `overcommit --sign` once you've verified the configuration changes."
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,186 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rubocop:disable Metrics/ClassLength, Metrics/CyclomaticComplexity, Metrics/MethodLength
4
+ module Overcommit
5
+ # Validates and normalizes a configuration.
6
+ class ConfigurationValidator
7
+ # Validates hash for any invalid options, normalizing where possible.
8
+ #
9
+ # @param config [Overcommit::Configuration]
10
+ # @param hash [Hash] hash representation of YAML config
11
+ # @param options[Hash]
12
+ # @option default [Boolean] whether hash represents the default built-in config
13
+ # @option logger [Overcommit::Logger] logger to output warnings to
14
+ # @return [Hash] validated hash (potentially modified)
15
+ def validate(config, hash, options)
16
+ @options = options.dup
17
+ @log = options[:logger]
18
+
19
+ hash = convert_nils_to_empty_hashes(hash)
20
+ ensure_hook_type_sections_exist(hash)
21
+ check_hook_name_format(hash)
22
+ check_hook_env(hash)
23
+ check_for_missing_enabled_option(hash) unless @options[:default]
24
+ check_for_too_many_processors(config, hash)
25
+ check_for_verify_plugin_signatures_option(hash)
26
+
27
+ hash
28
+ end
29
+
30
+ private
31
+
32
+ # Ensures that keys for all supported hook types exist (PreCommit,
33
+ # CommitMsg, etc.)
34
+ def ensure_hook_type_sections_exist(hash)
35
+ Overcommit::Utils.supported_hook_type_classes.each do |hook_type|
36
+ hash[hook_type] ||= {}
37
+ hash[hook_type]['ALL'] ||= {}
38
+ end
39
+ end
40
+
41
+ # Normalizes `nil` values to empty hashes.
42
+ #
43
+ # This is useful for when we want to merge two configuration hashes
44
+ # together, since it's easier to merge two hashes than to have to check if
45
+ # one of the values is nil.
46
+ def convert_nils_to_empty_hashes(hash)
47
+ hash.each_with_object({}) do |(key, value), h|
48
+ h[key] =
49
+ case value
50
+ when nil then {}
51
+ when Hash then convert_nils_to_empty_hashes(value)
52
+ else
53
+ value
54
+ end
55
+ end
56
+ end
57
+
58
+ def check_hook_env(hash)
59
+ errors = []
60
+
61
+ Overcommit::Utils.supported_hook_type_classes.each do |hook_type|
62
+ hash.fetch(hook_type) { {} }.each do |hook_name, hook_config|
63
+ hook_env = hook_config.fetch('env') { {} }
64
+
65
+ unless hook_env.is_a?(Hash)
66
+ errors << "#{hook_type}::#{hook_name} has an invalid `env` specified: " \
67
+ 'must be a hash of environment variable name to string value.'
68
+ next
69
+ end
70
+
71
+ hook_env.each do |var_name, var_value|
72
+ if var_name.include?('=')
73
+ errors << "#{hook_type}::#{hook_name} has an invalid `env` specified: " \
74
+ "variable name `#{var_name}` cannot contain `=`."
75
+ end
76
+
77
+ unless var_value.nil? || var_value.is_a?(String)
78
+ errors << "#{hook_type}::#{hook_name} has an invalid `env` specified: " \
79
+ "value of `#{var_name}` must be a string or `nil`, but was " \
80
+ "#{var_value.inspect} (#{var_value.class})"
81
+ end
82
+ end
83
+ end
84
+ end
85
+
86
+ if errors.any?
87
+ if @log
88
+ @log.error errors.join("\n")
89
+ @log.newline
90
+ end
91
+ raise Overcommit::Exceptions::ConfigurationError,
92
+ 'One or more hooks had an invalid `env` configuration option'
93
+ end
94
+ end
95
+
96
+ # Prints an error message and raises an exception if a hook has an
97
+ # invalid name, since this can result in strange errors elsewhere.
98
+ def check_hook_name_format(hash)
99
+ errors = []
100
+
101
+ Overcommit::Utils.supported_hook_type_classes.each do |hook_type|
102
+ hash.fetch(hook_type) { {} }.each_key do |hook_name|
103
+ next if hook_name == 'ALL'
104
+
105
+ unless hook_name.match?(/\A[A-Za-z0-9]+\z/)
106
+ errors << "#{hook_type}::#{hook_name} has an invalid name " \
107
+ "#{hook_name}. It must contain only alphanumeric " \
108
+ 'characters (no underscores or dashes, etc.)'
109
+ end
110
+ end
111
+ end
112
+
113
+ if errors.any?
114
+ if @log
115
+ @log.error errors.join("\n")
116
+ @log.newline
117
+ end
118
+ raise Overcommit::Exceptions::ConfigurationError,
119
+ 'One or more hooks had invalid names'
120
+ end
121
+ end
122
+
123
+ # Prints a warning if there are any hooks listed in the configuration
124
+ # without `enabled` explicitly set.
125
+ def check_for_missing_enabled_option(hash)
126
+ return unless @log
127
+
128
+ any_warnings = false
129
+
130
+ Overcommit::Utils.supported_hook_type_classes.each do |hook_type|
131
+ hash.fetch(hook_type) { {} }.each do |hook_name, hook_config|
132
+ next if hook_name == 'ALL'
133
+
134
+ if hook_config['enabled'].nil?
135
+ @log.warning "#{hook_type}::#{hook_name} hook does not explicitly " \
136
+ 'set `enabled` option in .overcommit.yml'
137
+ any_warnings = true
138
+ end
139
+ end
140
+ end
141
+
142
+ @log.newline if any_warnings
143
+ end
144
+
145
+ # Prints a warning if any hook has a number of processors larger than the
146
+ # global `concurrency` setting.
147
+ def check_for_too_many_processors(config, hash)
148
+ concurrency = config.concurrency
149
+
150
+ errors = []
151
+ Overcommit::Utils.supported_hook_type_classes.each do |hook_type|
152
+ hash.fetch(hook_type) { {} }.each do |hook_name, hook_config|
153
+ processors = hook_config.fetch('processors') { 1 }
154
+ if processors > concurrency
155
+ errors << "#{hook_type}::#{hook_name} `processors` value " \
156
+ "(#{processors}) is larger than the global `concurrency` " \
157
+ "option (#{concurrency})"
158
+ end
159
+ end
160
+ end
161
+
162
+ if errors.any?
163
+ if @log
164
+ @log.error errors.join("\n")
165
+ @log.newline
166
+ end
167
+ raise Overcommit::Exceptions::ConfigurationError,
168
+ 'One or more hooks had invalid `processor` value configured'
169
+ end
170
+ end
171
+
172
+ # Prints a warning if the `verify_plugin_signatures` option is used instead
173
+ # of the new `verify_signatures` option.
174
+ def check_for_verify_plugin_signatures_option(hash)
175
+ return unless @log
176
+
177
+ if hash.key?('verify_plugin_signatures')
178
+ @log.warning '`verify_plugin_signatures` has been renamed to ' \
179
+ '`verify_signatures`. Defaulting to verifying signatures.'
180
+ @log.warning "See change log at #{REPO_URL}/blob/v0.29.0/CHANGELOG.md for details."
181
+ @log.newline
182
+ end
183
+ end
184
+ end
185
+ end
186
+ # rubocop:enable Metrics/ClassLength, Metrics/CyclomaticComplexity, Metrics/MethodLength
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Global application constants.
4
+ module Overcommit
5
+ HOME = File.expand_path(File.join(File.dirname(__FILE__), '..', '..')).freeze
6
+ CONFIG_FILE_NAME = '.overcommit.yml'
7
+
8
+ HOOK_DIRECTORY = File.join(HOME, 'lib', 'overcommit', 'hook').freeze
9
+
10
+ REPO_URL = 'https://github.com/sds/overcommit'
11
+ BUG_REPORT_URL = "#{REPO_URL}/issues"
12
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Overcommit::Exceptions
4
+ # Raised when a {Configuration} could not be loaded from a file.
5
+ class ConfigurationError < StandardError; end
6
+
7
+ # Raised when the Overcommit configuration file signature has changed.
8
+ class ConfigurationSignatureChanged < StandardError; end
9
+
10
+ # Raised when trying to read/write to/from the local repo git config fails.
11
+ class GitConfigError < StandardError; end
12
+
13
+ # Raised when there was a problem reading submodule information for a repo.
14
+ class GitSubmoduleError < StandardError; end
15
+
16
+ # Raised when there was a problem reading git revision information with `rev-list`.
17
+ class GitRevListError < StandardError; end
18
+
19
+ # Raised when a {HookContext} is unable to setup the environment before a run.
20
+ class HookSetupFailed < StandardError; end
21
+
22
+ # Raised when a {HookContext} is unable to clean the environment after a run.
23
+ class HookCleanupFailed < StandardError; end
24
+
25
+ # Raised when a hook run was cancelled by the user.
26
+ class HookCancelled < StandardError; end
27
+
28
+ # Raised when a hook could not be loaded by a {HookRunner}.
29
+ class HookLoadError < StandardError; end
30
+
31
+ # Raised when a {HookRunner} could not be loaded.
32
+ class HookContextLoadError < StandardError; end
33
+
34
+ # Raised when a pipe character is used in the `execute` helper, as this was
35
+ # likely used in error.
36
+ class InvalidCommandArgs < StandardError; end
37
+
38
+ # Raised when an installation target is not a valid git repository.
39
+ class InvalidGitRepo < StandardError; end
40
+
41
+ # Raised when a hook was defined incorrectly.
42
+ class InvalidHookDefinition < StandardError; end
43
+
44
+ # Raised when one or more hook plugin signatures have changed.
45
+ class InvalidHookSignature < StandardError; end
46
+
47
+ # Raised when there is a problem processing output into {Hook::Messages}s.
48
+ class MessageProcessingError < StandardError; end
49
+
50
+ # Raised when an installation target already contains non-Overcommit hooks.
51
+ class PreExistingHooks < StandardError; end
52
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'overcommit/utils'
4
+
5
+ module Overcommit
6
+ # Get configuration options from git
7
+ module GitConfig
8
+ module_function
9
+
10
+ def comment_character
11
+ char = `git config --get core.commentchar`.chomp
12
+ char = '#' if char == ''
13
+ char
14
+ end
15
+
16
+ def hooks_path
17
+ path = `git config --get core.hooksPath`.chomp
18
+ return File.join(Overcommit::Utils.git_dir, 'hooks') if path.empty?
19
+ File.absolute_path(path, Dir.pwd)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,286 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'iniparse'
4
+ require 'shellwords'
5
+
6
+ module Overcommit
7
+ # Provide a set of utilities for certain interactions with `git`.
8
+ module GitRepo
9
+ module_function
10
+
11
+ # Regular expression used to extract diff ranges from hunks of diff output.
12
+ DIFF_HUNK_REGEX = /
13
+ ^@@\s
14
+ [^\s]+\s # Ignore old file range
15
+ \+(\d+)(?:,(\d+))? # Extract range of hunk containing start line and number of lines
16
+ \s@@.*$
17
+ /x
18
+
19
+ # Regular expression used to extract information from lines of
20
+ # `git submodule status` output
21
+ SUBMODULE_STATUS_REGEX = /
22
+ ^\s*(?<prefix>[-+U]?)(?<sha1>\w+)
23
+ \s(?<path>[^\s]+?)
24
+ (?:\s\((?<describe>.+)\))?$
25
+ /x
26
+
27
+ # Struct encapsulating submodule information extracted from the
28
+ # output of `git submodule status`
29
+ SubmoduleStatus = Struct.new(:prefix, :sha1, :path, :describe) do
30
+ # Returns whether the submodule has not been initialized
31
+ def uninitialized?
32
+ prefix == '-'
33
+ end
34
+
35
+ # Returns whether the submodule is out of date with the current
36
+ # index, i.e. its checked-out commit differs from that stored in
37
+ # the index of the parent repo
38
+ def outdated?
39
+ prefix == '+'
40
+ end
41
+
42
+ # Returns whether the submodule reference has a merge conflict
43
+ def merge_conflict?
44
+ prefix == 'U'
45
+ end
46
+ end
47
+
48
+ # Returns a list of SubmoduleStatus objects, one for each submodule in the
49
+ # parent repository.
50
+ #
51
+ # @option options [Boolean] recursive check submodules recursively
52
+ # @return [Array<SubmoduleStatus>]
53
+ def submodule_statuses(options = {})
54
+ flags = '--recursive' if options[:recursive]
55
+
56
+ `git submodule status #{flags}`.
57
+ scan(SUBMODULE_STATUS_REGEX).
58
+ map do |prefix, sha1, path, describe|
59
+ SubmoduleStatus.new(prefix, sha1, path, describe)
60
+ end
61
+ end
62
+
63
+ # Extract the set of modified lines from a given file.
64
+ #
65
+ # @param file_path [String]
66
+ # @param options [Hash]
67
+ # @return [Set] line numbers that have been modified in file
68
+ def extract_modified_lines(file_path, options)
69
+ lines = Set.new
70
+
71
+ flags = '--cached' if options[:staged]
72
+ refs = options[:refs]
73
+ subcmd = options[:subcmd] || 'diff'
74
+
75
+ `git #{subcmd} --no-color --no-ext-diff -U0 #{flags} #{refs} -- "#{file_path}"`.
76
+ scan(DIFF_HUNK_REGEX) do |start_line, lines_added|
77
+ lines_added = (lines_added || 1).to_i # When blank, one line was added
78
+ cur_line = start_line.to_i
79
+
80
+ lines_added.times do
81
+ lines.add cur_line
82
+ cur_line += 1
83
+ end
84
+ end
85
+
86
+ lines
87
+ end
88
+
89
+ # Returns the names of all files that have been modified compared to HEAD.
90
+ #
91
+ # @param options [Hash]
92
+ # @return [Array<String>] list of absolute file paths
93
+ def modified_files(options)
94
+ flags = '--cached' if options[:staged]
95
+ refs = options[:refs]
96
+ subcmd = options[:subcmd] || 'diff'
97
+
98
+ `git #{subcmd} --name-only -z --diff-filter=ACMR --ignore-submodules=all #{flags} #{refs}`.
99
+ split("\0").
100
+ map(&:strip).
101
+ reject(&:empty?).
102
+ map { |relative_file| File.expand_path(relative_file) }
103
+ end
104
+
105
+ # Returns the names of files in the given paths that are tracked by git.
106
+ #
107
+ # @param paths [Array<String>] list of paths to check
108
+ # @option options [String] ref ('HEAD') Git ref to check
109
+ # @return [Array<String>] list of absolute file paths
110
+ def list_files(paths = [], options = {})
111
+ ref = options[:ref] || 'HEAD'
112
+ path_list =
113
+ if OS.windows?
114
+ paths = paths.map { |path| path.gsub('"', '""') }
115
+ paths.empty? ? '' : "\"#{paths.join('" "')}\""
116
+ else
117
+ paths.shelljoin
118
+ end
119
+ `git ls-tree --name-only #{ref} #{path_list}`.
120
+ split(/\n/).
121
+ map { |relative_file| File.expand_path(relative_file) }.
122
+ reject { |file| File.directory?(file) } # Exclude submodule directories
123
+ end
124
+
125
+ # Returns whether the specified file/path is tracked by this repository.
126
+ #
127
+ # @param path [String]
128
+ # @return [true,false]
129
+ def tracked?(path)
130
+ Overcommit::Utils.execute(%W[git ls-files #{path} --error-unmatch]).success?
131
+ end
132
+
133
+ # Returns the names of all files that are tracked by git.
134
+ #
135
+ # @return [Array<String>] list of absolute file paths
136
+ def all_files
137
+ `git ls-files`.
138
+ split(/\n/).
139
+ map { |relative_file| File.expand_path(relative_file) }.
140
+ reject { |file| File.directory?(file) } # Exclude submodule directories
141
+ end
142
+
143
+ # Returns whether the current git branch is empty (has no commits).
144
+ # @return [true,false]
145
+ def initial_commit?
146
+ !Overcommit::Utils.execute(%w[git rev-parse HEAD]).success?
147
+ end
148
+
149
+ # Store any relevant files that are present when repo is in the middle of a
150
+ # merge.
151
+ #
152
+ # Restored via [#restore_merge_state].
153
+ def store_merge_state
154
+ merge_head = `git rev-parse MERGE_HEAD 2> #{File::NULL}`.chomp
155
+
156
+ # Store the merge state if we're in the middle of resolving a merge
157
+ # conflict. This is necessary since stashing removes the merge state.
158
+ if merge_head != 'MERGE_HEAD'
159
+ @merge_head = merge_head
160
+ end
161
+
162
+ merge_msg_file = File.expand_path('MERGE_MSG', Overcommit::Utils.git_dir)
163
+ @merge_msg = File.open(merge_msg_file).read if File.exist?(merge_msg_file)
164
+ end
165
+
166
+ # Store any relevant files that are present when repo is in the middle of a
167
+ # cherry-pick.
168
+ #
169
+ # Restored via [#restore_cherry_pick_state].
170
+ def store_cherry_pick_state
171
+ cherry_head = `git rev-parse CHERRY_PICK_HEAD 2> #{File::NULL}`.chomp
172
+
173
+ # Store the merge state if we're in the middle of resolving a merge
174
+ # conflict. This is necessary since stashing removes the merge state.
175
+ if cherry_head != 'CHERRY_PICK_HEAD'
176
+ @cherry_head = cherry_head
177
+ end
178
+ end
179
+
180
+ # Restore any relevant files that were present when repo was in the middle
181
+ # of a merge.
182
+ def restore_merge_state
183
+ if @merge_head
184
+ FileUtils.touch(File.expand_path('MERGE_MODE', Overcommit::Utils.git_dir))
185
+
186
+ File.open(File.expand_path('MERGE_HEAD', Overcommit::Utils.git_dir), 'w') do |f|
187
+ f.write(@merge_head)
188
+ end
189
+ @merge_head = nil
190
+ end
191
+
192
+ if @merge_msg
193
+ File.open(File.expand_path('MERGE_MSG', Overcommit::Utils.git_dir), 'w') do |f|
194
+ f.write("#{@merge_msg}\n")
195
+ end
196
+ @merge_msg = nil
197
+ end
198
+ end
199
+
200
+ # Restore any relevant files that were present when repo was in the middle
201
+ # of a cherry-pick.
202
+ def restore_cherry_pick_state
203
+ if @cherry_head
204
+ File.open(File.expand_path('CHERRY_PICK_HEAD',
205
+ Overcommit::Utils.git_dir), 'w') do |f|
206
+ f.write(@cherry_head)
207
+ end
208
+ @cherry_head = nil
209
+ end
210
+ end
211
+
212
+ # Contains information about a registered submodule.
213
+ Submodule = Struct.new(:path, :url)
214
+
215
+ # Returns the submodules that have been staged for removal.
216
+ #
217
+ # `git` has an unexpected behavior where removing a submodule without
218
+ # committing (i.e. such that the submodule directory is removed and the
219
+ # changes to the index are staged) and then doing a hard reset results in
220
+ # the index being wiped but the empty directory of the once existent
221
+ # submodule being restored (but with no content).
222
+ #
223
+ # This prevents restoration of the stash of the submodule index changes,
224
+ # which breaks pre-commit hook restorations of the working index.
225
+ #
226
+ # Thus we expose this helper so the restoration code can manually delete the
227
+ # directory.
228
+ #
229
+ # @raise [Overcommit::Exceptions::GitSubmoduleError] when
230
+ def staged_submodule_removals
231
+ # There were no submodules before, so none could have been removed
232
+ return [] if `git ls-files .gitmodules`.empty?
233
+
234
+ previous = submodules(ref: 'HEAD')
235
+ current = submodules
236
+
237
+ previous - current
238
+ end
239
+
240
+ # Returns the current set of registered submodules.
241
+ #
242
+ # @param options [Hash]
243
+ # @return [Array<Overcommit::GitRepo::Submodule>]
244
+ def submodules(options = {})
245
+ ref = options[:ref]
246
+
247
+ modules = []
248
+ IniParse.parse(`git show #{ref}:.gitmodules 2> #{File::NULL}`).each do |section|
249
+ # git < 1.8.5 does not update the .gitmodules file with submodule
250
+ # changes, so when we are looking at the current state of the work tree,
251
+ # we need to check if the submodule actually exists via another method,
252
+ # since the .gitmodules file we parsed does not represent reality.
253
+ if ref.nil? && GIT_VERSION < '1.8.5'
254
+ result = Overcommit::Utils.execute(%W[
255
+ git submodule status #{section['path']}
256
+ ])
257
+ next unless result.success?
258
+ end
259
+
260
+ modules << Submodule.new(section['path'], section['url'])
261
+ end
262
+
263
+ modules
264
+ rescue IniParse::IniParseError => ex
265
+ raise Overcommit::Exceptions::GitSubmoduleError,
266
+ "Unable to read submodule information from #{ref}:.gitmodules file: #{ex.message}"
267
+ end
268
+
269
+ # Returns the names of all branches containing the given commit.
270
+ #
271
+ # @param commit_ref [String] git tree ref that resolves to a commit
272
+ # @return [Array<String>] list of branches containing the given commit
273
+ def branches_containing_commit(commit_ref)
274
+ `git branch --column=dense --contains #{commit_ref}`.
275
+ sub(/\((HEAD )?detached (from|at) .*?\)/, ''). # ignore detached HEAD
276
+ split(/\s+/).
277
+ reject { |s| s.empty? || s == '*' }
278
+ end
279
+
280
+ # Returns the name of the currently checked out branch.
281
+ # @return [String]
282
+ def current_branch
283
+ `git symbolic-ref --short -q HEAD`.chomp
284
+ end
285
+ end
286
+ end