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,193 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fileutils'
4
+
5
+ module Overcommit
6
+ # Manages the installation of Overcommit hooks in a git repository.
7
+ class Installer # rubocop:disable ClassLength
8
+ TEMPLATE_DIRECTORY = File.join(Overcommit::HOME, 'template-dir')
9
+ MASTER_HOOK = File.join(TEMPLATE_DIRECTORY, 'hooks', 'overcommit-hook')
10
+
11
+ def initialize(logger)
12
+ @log = logger
13
+ end
14
+
15
+ def run(target, options)
16
+ @target = target
17
+ @options = options
18
+ validate_target
19
+
20
+ case @options[:action]
21
+ when :uninstall then uninstall
22
+ when :update then update
23
+ else
24
+ install
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ attr_reader :log
31
+
32
+ def install
33
+ log.log "Installing hooks into #{@target}"
34
+
35
+ ensure_directory(hooks_path)
36
+ preserve_old_hooks
37
+ install_master_hook
38
+ install_hook_files
39
+ install_starter_config
40
+
41
+ # Auto-sign configuration file on install
42
+ config(verify: false).update_signature!
43
+
44
+ log.success "Successfully installed hooks into #{@target}"
45
+ end
46
+
47
+ def uninstall
48
+ log.log "Removing hooks from #{@target}"
49
+
50
+ uninstall_hook_files
51
+ uninstall_master_hook
52
+ restore_old_hooks
53
+
54
+ log.success "Successfully removed hooks from #{@target}"
55
+ end
56
+
57
+ # @return [true,false] whether the hooks were updated
58
+ def update
59
+ unless FileUtils.compare_file(MASTER_HOOK, master_hook_install_path)
60
+ preserve_old_hooks
61
+ install_master_hook
62
+ install_hook_files
63
+
64
+ log.success "Hooks updated to Overcommit version #{Overcommit::VERSION}"
65
+ true
66
+ end
67
+ end
68
+
69
+ def hooks_path
70
+ @hooks_path ||= Dir.chdir(@target) { GitConfig.hooks_path }
71
+ end
72
+
73
+ def old_hooks_path
74
+ File.join(hooks_path, 'old-hooks')
75
+ end
76
+
77
+ def master_hook_install_path
78
+ File.join(hooks_path, 'overcommit-hook')
79
+ end
80
+
81
+ def ensure_directory(path)
82
+ FileUtils.mkdir_p(path)
83
+ end
84
+
85
+ def validate_target
86
+ absolute_target = File.expand_path(@target)
87
+
88
+ unless File.directory?(absolute_target)
89
+ raise Overcommit::Exceptions::InvalidGitRepo, 'is not a directory'
90
+ end
91
+
92
+ git_dir_check = Dir.chdir(absolute_target) do
93
+ Overcommit::Utils.execute(%w[git rev-parse --git-dir])
94
+ end
95
+
96
+ unless git_dir_check.success?
97
+ raise Overcommit::Exceptions::InvalidGitRepo, 'does not appear to be a git repository'
98
+ end
99
+ end
100
+
101
+ def install_master_hook
102
+ FileUtils.mkdir_p(hooks_path)
103
+ FileUtils.cp(MASTER_HOOK, master_hook_install_path)
104
+ end
105
+
106
+ def uninstall_master_hook
107
+ FileUtils.rm_rf(master_hook_install_path, secure: true)
108
+ end
109
+
110
+ def install_hook_files
111
+ # Copy each hook type (pre-commit, commit-msg, etc.) from the master hook.
112
+ Dir.chdir(hooks_path) do
113
+ Overcommit::Utils.supported_hook_types.each do |hook_type|
114
+ unless can_replace_file?(hook_type)
115
+ raise Overcommit::Exceptions::PreExistingHooks,
116
+ "Hook '#{File.expand_path(hook_type)}' already exists and " \
117
+ 'was not installed by Overcommit'
118
+ end
119
+ FileUtils.rm_f(hook_type)
120
+ FileUtils.cp('overcommit-hook', hook_type)
121
+ end
122
+ end
123
+ end
124
+
125
+ def can_replace_file?(file)
126
+ @options[:force] ||
127
+ !File.exist?(file) ||
128
+ overcommit_hook?(file)
129
+ end
130
+
131
+ def preserve_old_hooks
132
+ return unless File.directory?(hooks_path)
133
+
134
+ ensure_directory(old_hooks_path)
135
+ Overcommit::Utils.supported_hook_types.each do |hook_type|
136
+ hook_file = File.join(hooks_path, hook_type)
137
+ unless can_replace_file?(hook_file)
138
+ log.warning "Hook '#{File.expand_path(hook_type)}' already exists and " \
139
+ "was not installed by Overcommit. Moving to '#{old_hooks_path}'"
140
+ FileUtils.mv(hook_file, old_hooks_path)
141
+ end
142
+ end
143
+ # Remove old-hooks directory if empty (i.e. no old hooks were preserved)
144
+ FileUtils.rmdir(old_hooks_path) if Dir.entries(old_hooks_path).size <= 2
145
+ end
146
+
147
+ def restore_old_hooks
148
+ return unless File.directory?(old_hooks_path)
149
+
150
+ log.log "Restoring old hooks from #{old_hooks_path}"
151
+
152
+ Dir.chdir(old_hooks_path) do
153
+ Overcommit::Utils.supported_hook_types.each do |hook_type|
154
+ FileUtils.mv(hook_type, hooks_path) if File.exist?(hook_type)
155
+ end
156
+ end
157
+ # Remove old-hooks directory if empty
158
+ FileUtils.rmdir(old_hooks_path)
159
+
160
+ log.success "Successfully restored old hooks from #{old_hooks_path}"
161
+ end
162
+
163
+ def uninstall_hook_files
164
+ return unless File.directory?(hooks_path)
165
+
166
+ Dir.chdir(hooks_path) do
167
+ Overcommit::Utils.supported_hook_types.each do |hook_type|
168
+ FileUtils.rm_rf(hook_type, secure: true) if overcommit_hook?(hook_type)
169
+ end
170
+ end
171
+ end
172
+
173
+ def install_starter_config
174
+ repo_config_file = File.join(@target, Overcommit::CONFIG_FILE_NAME)
175
+
176
+ return if File.exist?(repo_config_file)
177
+ FileUtils.cp(File.join(Overcommit::HOME, 'config', 'starter.yml'), repo_config_file)
178
+ end
179
+
180
+ def overcommit_hook?(file)
181
+ File.read(file) =~ /OVERCOMMIT_DISABLE/
182
+ rescue Errno::ENOENT
183
+ # Some Ruby implementations (e.g. JRuby) raise an error when the file
184
+ # doesn't exist. Standardize the behavior to return false.
185
+ false
186
+ end
187
+
188
+ # Returns the configuration for this repository.
189
+ def config(options = {})
190
+ Overcommit::ConfigurationLoader.new(log, options).load_repo_config
191
+ end
192
+ end
193
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'singleton'
4
+
5
+ # Provides a handler for interrupt signals (SIGINT), allowing the application to
6
+ # finish what it's currently working on.
7
+ class InterruptHandler
8
+ include Singleton
9
+
10
+ attr_accessor :isolate_signals, :signal_received, :reenable_on_interrupt
11
+
12
+ # Initialize safe interrupt signal handling.
13
+ def initialize
14
+ self.isolate_signals = false
15
+ self.signal_received = false
16
+ self.reenable_on_interrupt = false
17
+
18
+ Signal.trap('INT') do
19
+ if isolate_signals
20
+ self.signal_received = true
21
+ else
22
+ if reenable_on_interrupt
23
+ self.reenable_on_interrupt = false
24
+ self.isolate_signals = true
25
+ end
26
+
27
+ raise Interrupt # Allow interrupt to propagate to code
28
+ end
29
+ end
30
+ end
31
+
32
+ class << self
33
+ # Provide a way to allow a single Ctrl-C interrupt to happen and atomically
34
+ # re-enable interrupt protections once that interrupt is propagated.
35
+ #
36
+ # This prevents a race condition where code like the following:
37
+ #
38
+ # begin
39
+ # InterruptHandler.disable!
40
+ # ... do stuff ...
41
+ # rescue Interrupt
42
+ # ... handle it ...
43
+ # ensure
44
+ # InterruptHandler.enable!
45
+ # end
46
+ #
47
+ # ...could have the `enable!` call to the interrupt handler not called in
48
+ # the event another interrupt was received in between the interrupt being
49
+ # handled and the `ensure` block being entered.
50
+ #
51
+ # Thus you should always write:
52
+ #
53
+ # begin
54
+ # InterruptHandler.disable_until_finished_or_interrupted do
55
+ # ... do stuff ...
56
+ # end
57
+ # rescue Interrupt
58
+ # ... handle it ...
59
+ # rescue
60
+ # ... handle any other exceptions ...
61
+ # end
62
+ def disable_until_finished_or_interrupted
63
+ instance.reenable_on_interrupt = true
64
+ instance.isolate_signals = false
65
+ yield
66
+ ensure
67
+ instance.isolate_signals = true
68
+ end
69
+
70
+ # Disable interrupt isolation.
71
+ def disable!
72
+ instance.isolate_signals = false
73
+ end
74
+
75
+ # Enable interrupt isolation.
76
+ def enable!
77
+ instance.isolate_signals = true
78
+ end
79
+
80
+ # Enable interrupt isolation while executing the provided block.
81
+ #
82
+ # @yield block to execute with interrupt isolation
83
+ def isolate_from_interrupts
84
+ instance.signal_received = false
85
+ instance.isolate_signals = true
86
+ result = yield
87
+ instance.isolate_signals = false
88
+ result
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Overcommit
4
+ # Encapsulates all communication to an output source.
5
+ class Logger
6
+ # Helper for creating a logger which outputs nothing.
7
+ def self.silent
8
+ new(File.open(File::NULL, 'w'))
9
+ end
10
+
11
+ # Creates a logger that will write to the given output stream.
12
+ #
13
+ # @param out [IO]
14
+ def initialize(out)
15
+ @out = out
16
+ @colorize =
17
+ if ENV.key?('OVERCOMMIT_COLOR')
18
+ !%w[0 false no].include?(ENV['OVERCOMMIT_COLOR'])
19
+ else
20
+ @out.tty?
21
+ end
22
+ end
23
+
24
+ # Write output without a trailing newline.
25
+ def partial(*args)
26
+ @out.print(*args)
27
+ end
28
+
29
+ # Prints a newline character (alias for readability).
30
+ def newline
31
+ log
32
+ end
33
+
34
+ # Write a line of output.
35
+ #
36
+ # A newline character will always be appended.
37
+ def log(*args)
38
+ @out.puts(*args)
39
+ end
40
+
41
+ # Write a line of output if debug mode is enabled.
42
+ def debug(*args)
43
+ color('35', *args) unless ENV.fetch('OVERCOMMIT_DEBUG') { '' }.empty?
44
+ end
45
+
46
+ # Write a line of output that is intended to be emphasized.
47
+ def bold(*args)
48
+ color('1', *args)
49
+ end
50
+
51
+ # Write a line of output indicating a problem or error.
52
+ def error(*args)
53
+ color(31, *args)
54
+ end
55
+
56
+ # Write a line of output indicating a problem or error which is emphasized
57
+ # over a regular problem or error.
58
+ def bold_error(*args)
59
+ color('1;31', *args)
60
+ end
61
+
62
+ # Write a line of output indicating a successful or noteworthy event.
63
+ def success(*args)
64
+ color(32, *args)
65
+ end
66
+
67
+ # Write a line of output indicating a potential cause for concern, but not
68
+ # an actual error.
69
+ def warning(*args)
70
+ color(33, *args)
71
+ end
72
+
73
+ # Write a line of output indicating a potential cause for concern, but with
74
+ # greater emphasize compared to other warnings.
75
+ def bold_warning(*args)
76
+ color('1;33', *args)
77
+ end
78
+
79
+ private
80
+
81
+ # Outputs text wrapped in ANSI escape code necessary to produce a given
82
+ # color/text display.
83
+ #
84
+ # @param code [String] ANSI escape code, e.g. '1;33' for "bold yellow"
85
+ # @param str [String] string to wrap
86
+ # @param partial [true,false] whether to omit a newline
87
+ def color(code, str, partial = false)
88
+ send(partial ? :partial : :log,
89
+ @colorize ? "\033[#{code}m#{str}\033[0m" : str)
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,148 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Overcommit
4
+ # Utility class that encapsulates the handling of hook messages and whether
5
+ # they affect lines the user has modified or not.
6
+ #
7
+ # This class exposes an endpoint that extracts an appropriate hook/status
8
+ # output tuple from an array of {Overcommit::Hook::Message}s, respecting the
9
+ # configuration settings for the given hook.
10
+ class MessageProcessor
11
+ ERRORS_MODIFIED_HEADER = 'Errors on modified lines:'
12
+ WARNINGS_MODIFIED_HEADER = 'Warnings on modified lines:'
13
+ ERRORS_UNMODIFIED_HEADER = "Errors on lines you didn't modify:"
14
+ WARNINGS_UNMODIFIED_HEADER = "Warnings on lines you didn't modify:"
15
+ ERRORS_GENERIC_HEADER = 'Errors:'
16
+ WARNINGS_GENERIC_HEADER = 'Warnings:'
17
+
18
+ # @param hook [Overcommit::Hook::Base]
19
+ # @param unmodified_lines_setting [String] how to treat messages on
20
+ # unmodified lines
21
+ def initialize(hook, unmodified_lines_setting)
22
+ @hook = hook
23
+ @setting = unmodified_lines_setting
24
+ end
25
+
26
+ # Returns a hook status/output tuple from the messages this processor was
27
+ # initialized with.
28
+ #
29
+ # @return [Array<Symbol,String>]
30
+ def hook_result(messages)
31
+ status, output = basic_status_and_output(messages)
32
+
33
+ # Nothing to do if there are no problems to begin with
34
+ return [status, output] if status == :pass
35
+
36
+ # Return as-is if this type of hook doesn't have the concept of modified lines
37
+ return [status, output] unless @hook.respond_to?(:modified_lines_in_file)
38
+
39
+ handle_modified_lines(messages, status)
40
+ end
41
+
42
+ private
43
+
44
+ def handle_modified_lines(messages, status)
45
+ messages = remove_ignored_messages(messages)
46
+
47
+ messages_with_line, generic_messages = messages.partition(&:line)
48
+
49
+ # Always print generic messages first
50
+ output = print_messages(
51
+ generic_messages,
52
+ ERRORS_GENERIC_HEADER,
53
+ WARNINGS_GENERIC_HEADER
54
+ )
55
+
56
+ messages_on_modified_lines, messages_on_unmodified_lines =
57
+ messages_with_line.partition { |message| message_on_modified_line?(message) }
58
+
59
+ output += print_messages(
60
+ messages_on_modified_lines,
61
+ ERRORS_MODIFIED_HEADER,
62
+ WARNINGS_MODIFIED_HEADER
63
+ )
64
+ output += print_messages(
65
+ messages_on_unmodified_lines,
66
+ ERRORS_UNMODIFIED_HEADER,
67
+ WARNINGS_UNMODIFIED_HEADER
68
+ )
69
+
70
+ [transform_status(status, generic_messages + messages_on_modified_lines), output]
71
+ end
72
+
73
+ def transform_status(status, messages_on_modified_lines)
74
+ # `report` indicates user wants the original status
75
+ return status if @setting == 'report'
76
+
77
+ error_messages, warning_messages =
78
+ messages_on_modified_lines.partition { |msg| msg.type == :error }
79
+
80
+ if can_upgrade_to_warning?(status, error_messages)
81
+ status = :warn
82
+ end
83
+
84
+ if can_upgrade_to_passing?(status, warning_messages)
85
+ status = :pass
86
+ end
87
+
88
+ status
89
+ end
90
+
91
+ def can_upgrade_to_warning?(status, error_messages)
92
+ status == :fail && error_messages.empty?
93
+ end
94
+
95
+ def can_upgrade_to_passing?(status, warning_messages)
96
+ status == :warn && @setting == 'ignore' && warning_messages.empty?
97
+ end
98
+
99
+ # Returns status and output for messages assuming no special treatment of
100
+ # messages occurring on unmodified lines.
101
+ def basic_status_and_output(messages)
102
+ status =
103
+ if messages.any? { |message| message.type == :error }
104
+ :fail
105
+ elsif messages.any? { |message| message.type == :warning }
106
+ :warn
107
+ else
108
+ :pass
109
+ end
110
+
111
+ output = ''
112
+ if messages.any?
113
+ output += messages.join("\n") + "\n"
114
+ end
115
+
116
+ [status, output]
117
+ end
118
+
119
+ def print_messages(messages, error_heading, warning_heading)
120
+ output = ''
121
+ errors, warnings = messages.partition { |msg| msg.type == :error }
122
+
123
+ if errors.any?
124
+ output += "#{error_heading}\n#{errors.join("\n")}\n"
125
+ end
126
+
127
+ if warnings.any?
128
+ output += "#{warning_heading}\n#{warnings.join("\n")}\n"
129
+ end
130
+
131
+ output
132
+ end
133
+
134
+ def remove_ignored_messages(messages)
135
+ # If user wants to ignore messages on unmodified lines, simply remove them
136
+ return messages unless @setting == 'ignore'
137
+
138
+ messages.select { |message| message_on_modified_line?(message) }
139
+ end
140
+
141
+ def message_on_modified_line?(message)
142
+ # Message without line number assumed to apply to entire file
143
+ return true unless message.line
144
+
145
+ @hook.modified_lines_in_file(message.file).include?(message.line)
146
+ end
147
+ end
148
+ end