overcommit-jeygeethanmedia 0.53.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (226) hide show
  1. checksums.yaml +7 -0
  2. data/bin/overcommit +50 -0
  3. data/config/default.yml +1356 -0
  4. data/config/starter.yml +33 -0
  5. data/lib/overcommit.rb +26 -0
  6. data/lib/overcommit/cli.rb +223 -0
  7. data/lib/overcommit/command_splitter.rb +146 -0
  8. data/lib/overcommit/configuration.rb +350 -0
  9. data/lib/overcommit/configuration_loader.rb +96 -0
  10. data/lib/overcommit/configuration_validator.rb +186 -0
  11. data/lib/overcommit/constants.rb +12 -0
  12. data/lib/overcommit/exceptions.rb +52 -0
  13. data/lib/overcommit/git_config.rb +22 -0
  14. data/lib/overcommit/git_repo.rb +286 -0
  15. data/lib/overcommit/git_version.rb +17 -0
  16. data/lib/overcommit/hook/base.rb +294 -0
  17. data/lib/overcommit/hook/commit_msg/base.rb +14 -0
  18. data/lib/overcommit/hook/commit_msg/capitalized_subject.rb +25 -0
  19. data/lib/overcommit/hook/commit_msg/empty_message.rb +12 -0
  20. data/lib/overcommit/hook/commit_msg/gerrit_change_id.rb +22 -0
  21. data/lib/overcommit/hook/commit_msg/hard_tabs.rb +17 -0
  22. data/lib/overcommit/hook/commit_msg/message_format.rb +31 -0
  23. data/lib/overcommit/hook/commit_msg/russian_novel.rb +16 -0
  24. data/lib/overcommit/hook/commit_msg/single_line_subject.rb +16 -0
  25. data/lib/overcommit/hook/commit_msg/spell_check.rb +45 -0
  26. data/lib/overcommit/hook/commit_msg/text_width.rb +56 -0
  27. data/lib/overcommit/hook/commit_msg/trailing_period.rb +16 -0
  28. data/lib/overcommit/hook/post_checkout/base.rb +22 -0
  29. data/lib/overcommit/hook/post_checkout/bower_install.rb +13 -0
  30. data/lib/overcommit/hook/post_checkout/bundle_install.rb +13 -0
  31. data/lib/overcommit/hook/post_checkout/composer_install.rb +13 -0
  32. data/lib/overcommit/hook/post_checkout/index_tags.rb +12 -0
  33. data/lib/overcommit/hook/post_checkout/npm_install.rb +13 -0
  34. data/lib/overcommit/hook/post_checkout/submodule_status.rb +12 -0
  35. data/lib/overcommit/hook/post_checkout/yarn_install.rb +13 -0
  36. data/lib/overcommit/hook/post_commit/base.rb +12 -0
  37. data/lib/overcommit/hook/post_commit/bower_install.rb +13 -0
  38. data/lib/overcommit/hook/post_commit/bundle_install.rb +13 -0
  39. data/lib/overcommit/hook/post_commit/commitplease.rb +16 -0
  40. data/lib/overcommit/hook/post_commit/composer_install.rb +13 -0
  41. data/lib/overcommit/hook/post_commit/git_guilt.rb +43 -0
  42. data/lib/overcommit/hook/post_commit/index_tags.rb +12 -0
  43. data/lib/overcommit/hook/post_commit/npm_install.rb +13 -0
  44. data/lib/overcommit/hook/post_commit/submodule_status.rb +12 -0
  45. data/lib/overcommit/hook/post_commit/yarn_install.rb +13 -0
  46. data/lib/overcommit/hook/post_merge/base.rb +12 -0
  47. data/lib/overcommit/hook/post_merge/bower_install.rb +13 -0
  48. data/lib/overcommit/hook/post_merge/bundle_install.rb +13 -0
  49. data/lib/overcommit/hook/post_merge/composer_install.rb +13 -0
  50. data/lib/overcommit/hook/post_merge/index_tags.rb +12 -0
  51. data/lib/overcommit/hook/post_merge/npm_install.rb +13 -0
  52. data/lib/overcommit/hook/post_merge/submodule_status.rb +12 -0
  53. data/lib/overcommit/hook/post_merge/yarn_install.rb +13 -0
  54. data/lib/overcommit/hook/post_rewrite/base.rb +12 -0
  55. data/lib/overcommit/hook/post_rewrite/bower_install.rb +13 -0
  56. data/lib/overcommit/hook/post_rewrite/bundle_install.rb +13 -0
  57. data/lib/overcommit/hook/post_rewrite/composer_install.rb +13 -0
  58. data/lib/overcommit/hook/post_rewrite/index_tags.rb +19 -0
  59. data/lib/overcommit/hook/post_rewrite/npm_install.rb +13 -0
  60. data/lib/overcommit/hook/post_rewrite/submodule_status.rb +12 -0
  61. data/lib/overcommit/hook/post_rewrite/yarn_install.rb +13 -0
  62. data/lib/overcommit/hook/pre_commit/author_email.rb +26 -0
  63. data/lib/overcommit/hook/pre_commit/author_name.rb +25 -0
  64. data/lib/overcommit/hook/pre_commit/base.rb +19 -0
  65. data/lib/overcommit/hook/pre_commit/berksfile_check.rb +24 -0
  66. data/lib/overcommit/hook/pre_commit/broken_symlinks.rb +17 -0
  67. data/lib/overcommit/hook/pre_commit/bundle_audit.rb +24 -0
  68. data/lib/overcommit/hook/pre_commit/bundle_check.rb +32 -0
  69. data/lib/overcommit/hook/pre_commit/bundle_outdated.rb +25 -0
  70. data/lib/overcommit/hook/pre_commit/case_conflicts.rb +27 -0
  71. data/lib/overcommit/hook/pre_commit/chamber_compare.rb +43 -0
  72. data/lib/overcommit/hook/pre_commit/chamber_security.rb +15 -0
  73. data/lib/overcommit/hook/pre_commit/chamber_verification.rb +36 -0
  74. data/lib/overcommit/hook/pre_commit/code_spell_check.rb +36 -0
  75. data/lib/overcommit/hook/pre_commit/coffee_lint.rb +35 -0
  76. data/lib/overcommit/hook/pre_commit/cook_style.rb +35 -0
  77. data/lib/overcommit/hook/pre_commit/credo.rb +27 -0
  78. data/lib/overcommit/hook/pre_commit/css_lint.rb +26 -0
  79. data/lib/overcommit/hook/pre_commit/dogma.rb +33 -0
  80. data/lib/overcommit/hook/pre_commit/es_lint.rb +38 -0
  81. data/lib/overcommit/hook/pre_commit/execute_permissions.rb +76 -0
  82. data/lib/overcommit/hook/pre_commit/fasterer.rb +25 -0
  83. data/lib/overcommit/hook/pre_commit/file_size.rb +47 -0
  84. data/lib/overcommit/hook/pre_commit/fix_me.rb +17 -0
  85. data/lib/overcommit/hook/pre_commit/flay.rb +38 -0
  86. data/lib/overcommit/hook/pre_commit/foodcritic.rb +149 -0
  87. data/lib/overcommit/hook/pre_commit/forbidden_branches.rb +26 -0
  88. data/lib/overcommit/hook/pre_commit/ginkgo_focus.rb +23 -0
  89. data/lib/overcommit/hook/pre_commit/go_fmt.rb +17 -0
  90. data/lib/overcommit/hook/pre_commit/go_lint.rb +29 -0
  91. data/lib/overcommit/hook/pre_commit/go_vet.rb +24 -0
  92. data/lib/overcommit/hook/pre_commit/golangci_lint.rb +21 -0
  93. data/lib/overcommit/hook/pre_commit/hadolint.rb +27 -0
  94. data/lib/overcommit/hook/pre_commit/haml_lint.rb +23 -0
  95. data/lib/overcommit/hook/pre_commit/hard_tabs.rb +15 -0
  96. data/lib/overcommit/hook/pre_commit/hlint.rb +34 -0
  97. data/lib/overcommit/hook/pre_commit/html_hint.rb +23 -0
  98. data/lib/overcommit/hook/pre_commit/html_tidy.rb +30 -0
  99. data/lib/overcommit/hook/pre_commit/image_optim.rb +28 -0
  100. data/lib/overcommit/hook/pre_commit/java_checkstyle.rb +27 -0
  101. data/lib/overcommit/hook/pre_commit/js_hint.rb +23 -0
  102. data/lib/overcommit/hook/pre_commit/js_lint.rb +22 -0
  103. data/lib/overcommit/hook/pre_commit/jscs.rb +27 -0
  104. data/lib/overcommit/hook/pre_commit/jsl.rb +28 -0
  105. data/lib/overcommit/hook/pre_commit/json_syntax.rb +21 -0
  106. data/lib/overcommit/hook/pre_commit/kt_lint.rb +19 -0
  107. data/lib/overcommit/hook/pre_commit/license_finder.rb +14 -0
  108. data/lib/overcommit/hook/pre_commit/license_header.rb +48 -0
  109. data/lib/overcommit/hook/pre_commit/line_endings.rb +77 -0
  110. data/lib/overcommit/hook/pre_commit/local_paths_in_gemfile.rb +16 -0
  111. data/lib/overcommit/hook/pre_commit/mdl.rb +29 -0
  112. data/lib/overcommit/hook/pre_commit/merge_conflicts.rb +16 -0
  113. data/lib/overcommit/hook/pre_commit/nginx_test.rb +26 -0
  114. data/lib/overcommit/hook/pre_commit/pep257.rb +23 -0
  115. data/lib/overcommit/hook/pre_commit/pep8.rb +23 -0
  116. data/lib/overcommit/hook/pre_commit/php_cs.rb +43 -0
  117. data/lib/overcommit/hook/pre_commit/php_cs_fixer.rb +57 -0
  118. data/lib/overcommit/hook/pre_commit/php_lint.rb +44 -0
  119. data/lib/overcommit/hook/pre_commit/php_stan.rb +30 -0
  120. data/lib/overcommit/hook/pre_commit/pronto.rb +12 -0
  121. data/lib/overcommit/hook/pre_commit/puppet_lint.rb +26 -0
  122. data/lib/overcommit/hook/pre_commit/puppet_metadata_json_lint.rb +29 -0
  123. data/lib/overcommit/hook/pre_commit/pycodestyle.rb +23 -0
  124. data/lib/overcommit/hook/pre_commit/pydocstyle.rb +23 -0
  125. data/lib/overcommit/hook/pre_commit/pyflakes.rb +32 -0
  126. data/lib/overcommit/hook/pre_commit/pylint.rb +32 -0
  127. data/lib/overcommit/hook/pre_commit/python_flake8.rb +32 -0
  128. data/lib/overcommit/hook/pre_commit/rails_best_practices.rb +34 -0
  129. data/lib/overcommit/hook/pre_commit/rails_schema_up_to_date.rb +58 -0
  130. data/lib/overcommit/hook/pre_commit/rake_target.rb +12 -0
  131. data/lib/overcommit/hook/pre_commit/reek.rb +26 -0
  132. data/lib/overcommit/hook/pre_commit/rst_lint.rb +27 -0
  133. data/lib/overcommit/hook/pre_commit/rubo_cop.rb +35 -0
  134. data/lib/overcommit/hook/pre_commit/ruby_lint.rb +23 -0
  135. data/lib/overcommit/hook/pre_commit/ruby_syntax.rb +27 -0
  136. data/lib/overcommit/hook/pre_commit/scalariform.rb +22 -0
  137. data/lib/overcommit/hook/pre_commit/scalastyle.rb +31 -0
  138. data/lib/overcommit/hook/pre_commit/scss_lint.rb +43 -0
  139. data/lib/overcommit/hook/pre_commit/semi_standard.rb +23 -0
  140. data/lib/overcommit/hook/pre_commit/shell_check.rb +23 -0
  141. data/lib/overcommit/hook/pre_commit/slim_lint.rb +23 -0
  142. data/lib/overcommit/hook/pre_commit/sqlint.rb +26 -0
  143. data/lib/overcommit/hook/pre_commit/standard.rb +23 -0
  144. data/lib/overcommit/hook/pre_commit/stylelint.rb +23 -0
  145. data/lib/overcommit/hook/pre_commit/swift_lint.rb +19 -0
  146. data/lib/overcommit/hook/pre_commit/terraform_format.rb +19 -0
  147. data/lib/overcommit/hook/pre_commit/trailing_whitespace.rb +15 -0
  148. data/lib/overcommit/hook/pre_commit/travis_lint.rb +15 -0
  149. data/lib/overcommit/hook/pre_commit/ts_lint.rb +28 -0
  150. data/lib/overcommit/hook/pre_commit/vint.rb +22 -0
  151. data/lib/overcommit/hook/pre_commit/w3c_css.rb +67 -0
  152. data/lib/overcommit/hook/pre_commit/w3c_html.rb +64 -0
  153. data/lib/overcommit/hook/pre_commit/xml_lint.rb +24 -0
  154. data/lib/overcommit/hook/pre_commit/xml_syntax.rb +21 -0
  155. data/lib/overcommit/hook/pre_commit/yaml_lint.rb +18 -0
  156. data/lib/overcommit/hook/pre_commit/yaml_syntax.rb +20 -0
  157. data/lib/overcommit/hook/pre_commit/yard_coverage.rb +90 -0
  158. data/lib/overcommit/hook/pre_commit/yarn_check.rb +37 -0
  159. data/lib/overcommit/hook/pre_push/base.rb +33 -0
  160. data/lib/overcommit/hook/pre_push/brakeman.rb +15 -0
  161. data/lib/overcommit/hook/pre_push/cargo_test.rb +12 -0
  162. data/lib/overcommit/hook/pre_push/go_test.rb +14 -0
  163. data/lib/overcommit/hook/pre_push/golangci_lint.rb +16 -0
  164. data/lib/overcommit/hook/pre_push/minitest.rb +20 -0
  165. data/lib/overcommit/hook/pre_push/php_unit.rb +16 -0
  166. data/lib/overcommit/hook/pre_push/pronto.rb +12 -0
  167. data/lib/overcommit/hook/pre_push/protected_branches.rb +74 -0
  168. data/lib/overcommit/hook/pre_push/pytest.rb +16 -0
  169. data/lib/overcommit/hook/pre_push/python_nose.rb +16 -0
  170. data/lib/overcommit/hook/pre_push/r_spec.rb +16 -0
  171. data/lib/overcommit/hook/pre_push/rake_target.rb +12 -0
  172. data/lib/overcommit/hook/pre_push/test_unit.rb +16 -0
  173. data/lib/overcommit/hook/pre_rebase/base.rb +14 -0
  174. data/lib/overcommit/hook/pre_rebase/merged_commits.rb +31 -0
  175. data/lib/overcommit/hook/prepare_commit_msg/base.rb +25 -0
  176. data/lib/overcommit/hook/prepare_commit_msg/replace_branch.rb +57 -0
  177. data/lib/overcommit/hook/shared/bower_install.rb +15 -0
  178. data/lib/overcommit/hook/shared/bundle_install.rb +15 -0
  179. data/lib/overcommit/hook/shared/composer_install.rb +15 -0
  180. data/lib/overcommit/hook/shared/index_tags.rb +14 -0
  181. data/lib/overcommit/hook/shared/npm_install.rb +15 -0
  182. data/lib/overcommit/hook/shared/pronto.rb +21 -0
  183. data/lib/overcommit/hook/shared/rake_target.rb +26 -0
  184. data/lib/overcommit/hook/shared/submodule_status.rb +32 -0
  185. data/lib/overcommit/hook/shared/yarn_install.rb +15 -0
  186. data/lib/overcommit/hook_context.rb +19 -0
  187. data/lib/overcommit/hook_context/base.rb +139 -0
  188. data/lib/overcommit/hook_context/commit_msg.rb +48 -0
  189. data/lib/overcommit/hook_context/post_checkout.rb +36 -0
  190. data/lib/overcommit/hook_context/post_commit.rb +33 -0
  191. data/lib/overcommit/hook_context/post_merge.rb +37 -0
  192. data/lib/overcommit/hook_context/post_rewrite.rb +49 -0
  193. data/lib/overcommit/hook_context/pre_commit.rb +212 -0
  194. data/lib/overcommit/hook_context/pre_push.rb +89 -0
  195. data/lib/overcommit/hook_context/pre_rebase.rb +38 -0
  196. data/lib/overcommit/hook_context/prepare_commit_msg.rb +34 -0
  197. data/lib/overcommit/hook_context/run_all.rb +48 -0
  198. data/lib/overcommit/hook_loader/base.rb +48 -0
  199. data/lib/overcommit/hook_loader/built_in_hook_loader.rb +14 -0
  200. data/lib/overcommit/hook_loader/plugin_hook_loader.rb +102 -0
  201. data/lib/overcommit/hook_runner.rb +219 -0
  202. data/lib/overcommit/hook_signer.rb +123 -0
  203. data/lib/overcommit/installer.rb +193 -0
  204. data/lib/overcommit/interrupt_handler.rb +91 -0
  205. data/lib/overcommit/logger.rb +92 -0
  206. data/lib/overcommit/message_processor.rb +148 -0
  207. data/lib/overcommit/os.rb +38 -0
  208. data/lib/overcommit/printer.rb +145 -0
  209. data/lib/overcommit/subprocess.rb +98 -0
  210. data/lib/overcommit/utils.rb +309 -0
  211. data/lib/overcommit/utils/file_utils.rb +71 -0
  212. data/lib/overcommit/utils/messages_utils.rb +77 -0
  213. data/lib/overcommit/version.rb +6 -0
  214. data/libexec/gerrit-change-id +174 -0
  215. data/libexec/index-tags +17 -0
  216. data/template-dir/hooks/commit-msg +116 -0
  217. data/template-dir/hooks/overcommit-hook +116 -0
  218. data/template-dir/hooks/post-checkout +116 -0
  219. data/template-dir/hooks/post-commit +116 -0
  220. data/template-dir/hooks/post-merge +116 -0
  221. data/template-dir/hooks/post-rewrite +116 -0
  222. data/template-dir/hooks/pre-commit +116 -0
  223. data/template-dir/hooks/pre-push +116 -0
  224. data/template-dir/hooks/pre-rebase +116 -0
  225. data/template-dir/hooks/prepare-commit-msg +116 -0
  226. metadata +303 -0
@@ -0,0 +1,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