overcommit-jeygeethanmedia 0.53.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/overcommit +50 -0
- data/config/default.yml +1356 -0
- data/config/starter.yml +33 -0
- data/lib/overcommit.rb +26 -0
- data/lib/overcommit/cli.rb +223 -0
- data/lib/overcommit/command_splitter.rb +146 -0
- data/lib/overcommit/configuration.rb +350 -0
- data/lib/overcommit/configuration_loader.rb +96 -0
- data/lib/overcommit/configuration_validator.rb +186 -0
- data/lib/overcommit/constants.rb +12 -0
- data/lib/overcommit/exceptions.rb +52 -0
- data/lib/overcommit/git_config.rb +22 -0
- data/lib/overcommit/git_repo.rb +286 -0
- data/lib/overcommit/git_version.rb +17 -0
- data/lib/overcommit/hook/base.rb +294 -0
- data/lib/overcommit/hook/commit_msg/base.rb +14 -0
- data/lib/overcommit/hook/commit_msg/capitalized_subject.rb +25 -0
- data/lib/overcommit/hook/commit_msg/empty_message.rb +12 -0
- data/lib/overcommit/hook/commit_msg/gerrit_change_id.rb +22 -0
- data/lib/overcommit/hook/commit_msg/hard_tabs.rb +17 -0
- data/lib/overcommit/hook/commit_msg/message_format.rb +31 -0
- data/lib/overcommit/hook/commit_msg/russian_novel.rb +16 -0
- data/lib/overcommit/hook/commit_msg/single_line_subject.rb +16 -0
- data/lib/overcommit/hook/commit_msg/spell_check.rb +45 -0
- data/lib/overcommit/hook/commit_msg/text_width.rb +56 -0
- data/lib/overcommit/hook/commit_msg/trailing_period.rb +16 -0
- data/lib/overcommit/hook/post_checkout/base.rb +22 -0
- data/lib/overcommit/hook/post_checkout/bower_install.rb +13 -0
- data/lib/overcommit/hook/post_checkout/bundle_install.rb +13 -0
- data/lib/overcommit/hook/post_checkout/composer_install.rb +13 -0
- data/lib/overcommit/hook/post_checkout/index_tags.rb +12 -0
- data/lib/overcommit/hook/post_checkout/npm_install.rb +13 -0
- data/lib/overcommit/hook/post_checkout/submodule_status.rb +12 -0
- data/lib/overcommit/hook/post_checkout/yarn_install.rb +13 -0
- data/lib/overcommit/hook/post_commit/base.rb +12 -0
- data/lib/overcommit/hook/post_commit/bower_install.rb +13 -0
- data/lib/overcommit/hook/post_commit/bundle_install.rb +13 -0
- data/lib/overcommit/hook/post_commit/commitplease.rb +16 -0
- data/lib/overcommit/hook/post_commit/composer_install.rb +13 -0
- data/lib/overcommit/hook/post_commit/git_guilt.rb +43 -0
- data/lib/overcommit/hook/post_commit/index_tags.rb +12 -0
- data/lib/overcommit/hook/post_commit/npm_install.rb +13 -0
- data/lib/overcommit/hook/post_commit/submodule_status.rb +12 -0
- data/lib/overcommit/hook/post_commit/yarn_install.rb +13 -0
- data/lib/overcommit/hook/post_merge/base.rb +12 -0
- data/lib/overcommit/hook/post_merge/bower_install.rb +13 -0
- data/lib/overcommit/hook/post_merge/bundle_install.rb +13 -0
- data/lib/overcommit/hook/post_merge/composer_install.rb +13 -0
- data/lib/overcommit/hook/post_merge/index_tags.rb +12 -0
- data/lib/overcommit/hook/post_merge/npm_install.rb +13 -0
- data/lib/overcommit/hook/post_merge/submodule_status.rb +12 -0
- data/lib/overcommit/hook/post_merge/yarn_install.rb +13 -0
- data/lib/overcommit/hook/post_rewrite/base.rb +12 -0
- data/lib/overcommit/hook/post_rewrite/bower_install.rb +13 -0
- data/lib/overcommit/hook/post_rewrite/bundle_install.rb +13 -0
- data/lib/overcommit/hook/post_rewrite/composer_install.rb +13 -0
- data/lib/overcommit/hook/post_rewrite/index_tags.rb +19 -0
- data/lib/overcommit/hook/post_rewrite/npm_install.rb +13 -0
- data/lib/overcommit/hook/post_rewrite/submodule_status.rb +12 -0
- data/lib/overcommit/hook/post_rewrite/yarn_install.rb +13 -0
- data/lib/overcommit/hook/pre_commit/author_email.rb +26 -0
- data/lib/overcommit/hook/pre_commit/author_name.rb +25 -0
- data/lib/overcommit/hook/pre_commit/base.rb +19 -0
- data/lib/overcommit/hook/pre_commit/berksfile_check.rb +24 -0
- data/lib/overcommit/hook/pre_commit/broken_symlinks.rb +17 -0
- data/lib/overcommit/hook/pre_commit/bundle_audit.rb +24 -0
- data/lib/overcommit/hook/pre_commit/bundle_check.rb +32 -0
- data/lib/overcommit/hook/pre_commit/bundle_outdated.rb +25 -0
- data/lib/overcommit/hook/pre_commit/case_conflicts.rb +27 -0
- data/lib/overcommit/hook/pre_commit/chamber_compare.rb +43 -0
- data/lib/overcommit/hook/pre_commit/chamber_security.rb +15 -0
- data/lib/overcommit/hook/pre_commit/chamber_verification.rb +36 -0
- data/lib/overcommit/hook/pre_commit/code_spell_check.rb +36 -0
- data/lib/overcommit/hook/pre_commit/coffee_lint.rb +35 -0
- data/lib/overcommit/hook/pre_commit/cook_style.rb +35 -0
- data/lib/overcommit/hook/pre_commit/credo.rb +27 -0
- data/lib/overcommit/hook/pre_commit/css_lint.rb +26 -0
- data/lib/overcommit/hook/pre_commit/dogma.rb +33 -0
- data/lib/overcommit/hook/pre_commit/es_lint.rb +38 -0
- data/lib/overcommit/hook/pre_commit/execute_permissions.rb +76 -0
- data/lib/overcommit/hook/pre_commit/fasterer.rb +25 -0
- data/lib/overcommit/hook/pre_commit/file_size.rb +47 -0
- data/lib/overcommit/hook/pre_commit/fix_me.rb +17 -0
- data/lib/overcommit/hook/pre_commit/flay.rb +38 -0
- data/lib/overcommit/hook/pre_commit/foodcritic.rb +149 -0
- data/lib/overcommit/hook/pre_commit/forbidden_branches.rb +26 -0
- data/lib/overcommit/hook/pre_commit/ginkgo_focus.rb +23 -0
- data/lib/overcommit/hook/pre_commit/go_fmt.rb +17 -0
- data/lib/overcommit/hook/pre_commit/go_lint.rb +29 -0
- data/lib/overcommit/hook/pre_commit/go_vet.rb +24 -0
- data/lib/overcommit/hook/pre_commit/golangci_lint.rb +21 -0
- data/lib/overcommit/hook/pre_commit/hadolint.rb +27 -0
- data/lib/overcommit/hook/pre_commit/haml_lint.rb +23 -0
- data/lib/overcommit/hook/pre_commit/hard_tabs.rb +15 -0
- data/lib/overcommit/hook/pre_commit/hlint.rb +34 -0
- data/lib/overcommit/hook/pre_commit/html_hint.rb +23 -0
- data/lib/overcommit/hook/pre_commit/html_tidy.rb +30 -0
- data/lib/overcommit/hook/pre_commit/image_optim.rb +28 -0
- data/lib/overcommit/hook/pre_commit/java_checkstyle.rb +27 -0
- data/lib/overcommit/hook/pre_commit/js_hint.rb +23 -0
- data/lib/overcommit/hook/pre_commit/js_lint.rb +22 -0
- data/lib/overcommit/hook/pre_commit/jscs.rb +27 -0
- data/lib/overcommit/hook/pre_commit/jsl.rb +28 -0
- data/lib/overcommit/hook/pre_commit/json_syntax.rb +21 -0
- data/lib/overcommit/hook/pre_commit/kt_lint.rb +19 -0
- data/lib/overcommit/hook/pre_commit/license_finder.rb +14 -0
- data/lib/overcommit/hook/pre_commit/license_header.rb +48 -0
- data/lib/overcommit/hook/pre_commit/line_endings.rb +77 -0
- data/lib/overcommit/hook/pre_commit/local_paths_in_gemfile.rb +16 -0
- data/lib/overcommit/hook/pre_commit/mdl.rb +29 -0
- data/lib/overcommit/hook/pre_commit/merge_conflicts.rb +16 -0
- data/lib/overcommit/hook/pre_commit/nginx_test.rb +26 -0
- data/lib/overcommit/hook/pre_commit/pep257.rb +23 -0
- data/lib/overcommit/hook/pre_commit/pep8.rb +23 -0
- data/lib/overcommit/hook/pre_commit/php_cs.rb +43 -0
- data/lib/overcommit/hook/pre_commit/php_cs_fixer.rb +57 -0
- data/lib/overcommit/hook/pre_commit/php_lint.rb +44 -0
- data/lib/overcommit/hook/pre_commit/php_stan.rb +30 -0
- data/lib/overcommit/hook/pre_commit/pronto.rb +12 -0
- data/lib/overcommit/hook/pre_commit/puppet_lint.rb +26 -0
- data/lib/overcommit/hook/pre_commit/puppet_metadata_json_lint.rb +29 -0
- data/lib/overcommit/hook/pre_commit/pycodestyle.rb +23 -0
- data/lib/overcommit/hook/pre_commit/pydocstyle.rb +23 -0
- data/lib/overcommit/hook/pre_commit/pyflakes.rb +32 -0
- data/lib/overcommit/hook/pre_commit/pylint.rb +32 -0
- data/lib/overcommit/hook/pre_commit/python_flake8.rb +32 -0
- data/lib/overcommit/hook/pre_commit/rails_best_practices.rb +34 -0
- data/lib/overcommit/hook/pre_commit/rails_schema_up_to_date.rb +58 -0
- data/lib/overcommit/hook/pre_commit/rake_target.rb +12 -0
- data/lib/overcommit/hook/pre_commit/reek.rb +26 -0
- data/lib/overcommit/hook/pre_commit/rst_lint.rb +27 -0
- data/lib/overcommit/hook/pre_commit/rubo_cop.rb +35 -0
- data/lib/overcommit/hook/pre_commit/ruby_lint.rb +23 -0
- data/lib/overcommit/hook/pre_commit/ruby_syntax.rb +27 -0
- data/lib/overcommit/hook/pre_commit/scalariform.rb +22 -0
- data/lib/overcommit/hook/pre_commit/scalastyle.rb +31 -0
- data/lib/overcommit/hook/pre_commit/scss_lint.rb +43 -0
- data/lib/overcommit/hook/pre_commit/semi_standard.rb +23 -0
- data/lib/overcommit/hook/pre_commit/shell_check.rb +23 -0
- data/lib/overcommit/hook/pre_commit/slim_lint.rb +23 -0
- data/lib/overcommit/hook/pre_commit/sqlint.rb +26 -0
- data/lib/overcommit/hook/pre_commit/standard.rb +23 -0
- data/lib/overcommit/hook/pre_commit/stylelint.rb +23 -0
- data/lib/overcommit/hook/pre_commit/swift_lint.rb +19 -0
- data/lib/overcommit/hook/pre_commit/terraform_format.rb +19 -0
- data/lib/overcommit/hook/pre_commit/trailing_whitespace.rb +15 -0
- data/lib/overcommit/hook/pre_commit/travis_lint.rb +15 -0
- data/lib/overcommit/hook/pre_commit/ts_lint.rb +28 -0
- data/lib/overcommit/hook/pre_commit/vint.rb +22 -0
- data/lib/overcommit/hook/pre_commit/w3c_css.rb +67 -0
- data/lib/overcommit/hook/pre_commit/w3c_html.rb +64 -0
- data/lib/overcommit/hook/pre_commit/xml_lint.rb +24 -0
- data/lib/overcommit/hook/pre_commit/xml_syntax.rb +21 -0
- data/lib/overcommit/hook/pre_commit/yaml_lint.rb +18 -0
- data/lib/overcommit/hook/pre_commit/yaml_syntax.rb +20 -0
- data/lib/overcommit/hook/pre_commit/yard_coverage.rb +90 -0
- data/lib/overcommit/hook/pre_commit/yarn_check.rb +37 -0
- data/lib/overcommit/hook/pre_push/base.rb +33 -0
- data/lib/overcommit/hook/pre_push/brakeman.rb +15 -0
- data/lib/overcommit/hook/pre_push/cargo_test.rb +12 -0
- data/lib/overcommit/hook/pre_push/go_test.rb +14 -0
- data/lib/overcommit/hook/pre_push/golangci_lint.rb +16 -0
- data/lib/overcommit/hook/pre_push/minitest.rb +20 -0
- data/lib/overcommit/hook/pre_push/php_unit.rb +16 -0
- data/lib/overcommit/hook/pre_push/pronto.rb +12 -0
- data/lib/overcommit/hook/pre_push/protected_branches.rb +74 -0
- data/lib/overcommit/hook/pre_push/pytest.rb +16 -0
- data/lib/overcommit/hook/pre_push/python_nose.rb +16 -0
- data/lib/overcommit/hook/pre_push/r_spec.rb +16 -0
- data/lib/overcommit/hook/pre_push/rake_target.rb +12 -0
- data/lib/overcommit/hook/pre_push/test_unit.rb +16 -0
- data/lib/overcommit/hook/pre_rebase/base.rb +14 -0
- data/lib/overcommit/hook/pre_rebase/merged_commits.rb +31 -0
- data/lib/overcommit/hook/prepare_commit_msg/base.rb +25 -0
- data/lib/overcommit/hook/prepare_commit_msg/replace_branch.rb +57 -0
- data/lib/overcommit/hook/shared/bower_install.rb +15 -0
- data/lib/overcommit/hook/shared/bundle_install.rb +15 -0
- data/lib/overcommit/hook/shared/composer_install.rb +15 -0
- data/lib/overcommit/hook/shared/index_tags.rb +14 -0
- data/lib/overcommit/hook/shared/npm_install.rb +15 -0
- data/lib/overcommit/hook/shared/pronto.rb +21 -0
- data/lib/overcommit/hook/shared/rake_target.rb +26 -0
- data/lib/overcommit/hook/shared/submodule_status.rb +32 -0
- data/lib/overcommit/hook/shared/yarn_install.rb +15 -0
- data/lib/overcommit/hook_context.rb +19 -0
- data/lib/overcommit/hook_context/base.rb +139 -0
- data/lib/overcommit/hook_context/commit_msg.rb +48 -0
- data/lib/overcommit/hook_context/post_checkout.rb +36 -0
- data/lib/overcommit/hook_context/post_commit.rb +33 -0
- data/lib/overcommit/hook_context/post_merge.rb +37 -0
- data/lib/overcommit/hook_context/post_rewrite.rb +49 -0
- data/lib/overcommit/hook_context/pre_commit.rb +212 -0
- data/lib/overcommit/hook_context/pre_push.rb +89 -0
- data/lib/overcommit/hook_context/pre_rebase.rb +38 -0
- data/lib/overcommit/hook_context/prepare_commit_msg.rb +34 -0
- data/lib/overcommit/hook_context/run_all.rb +48 -0
- data/lib/overcommit/hook_loader/base.rb +48 -0
- data/lib/overcommit/hook_loader/built_in_hook_loader.rb +14 -0
- data/lib/overcommit/hook_loader/plugin_hook_loader.rb +102 -0
- data/lib/overcommit/hook_runner.rb +219 -0
- data/lib/overcommit/hook_signer.rb +123 -0
- data/lib/overcommit/installer.rb +193 -0
- data/lib/overcommit/interrupt_handler.rb +91 -0
- data/lib/overcommit/logger.rb +92 -0
- data/lib/overcommit/message_processor.rb +148 -0
- data/lib/overcommit/os.rb +38 -0
- data/lib/overcommit/printer.rb +145 -0
- data/lib/overcommit/subprocess.rb +98 -0
- data/lib/overcommit/utils.rb +309 -0
- data/lib/overcommit/utils/file_utils.rb +71 -0
- data/lib/overcommit/utils/messages_utils.rb +77 -0
- data/lib/overcommit/version.rb +6 -0
- data/libexec/gerrit-change-id +174 -0
- data/libexec/index-tags +17 -0
- data/template-dir/hooks/commit-msg +116 -0
- data/template-dir/hooks/overcommit-hook +116 -0
- data/template-dir/hooks/post-checkout +116 -0
- data/template-dir/hooks/post-commit +116 -0
- data/template-dir/hooks/post-merge +116 -0
- data/template-dir/hooks/post-rewrite +116 -0
- data/template-dir/hooks/pre-commit +116 -0
- data/template-dir/hooks/pre-push +116 -0
- data/template-dir/hooks/pre-rebase +116 -0
- data/template-dir/hooks/prepare-commit-msg +116 -0
- 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
|