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