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
data/config/starter.yml
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Use this file to configure the Overcommit hooks you wish to use. This will
|
|
2
|
+
# extend the default configuration defined in:
|
|
3
|
+
# https://github.com/sds/overcommit/blob/master/config/default.yml
|
|
4
|
+
#
|
|
5
|
+
# At the topmost level of this YAML file is a key representing type of hook
|
|
6
|
+
# being run (e.g. pre-commit, commit-msg, etc.). Within each type you can
|
|
7
|
+
# customize each hook, such as whether to only run it on certain files (via
|
|
8
|
+
# `include`), whether to only display output if it fails (via `quiet`), etc.
|
|
9
|
+
#
|
|
10
|
+
# For a complete list of hooks, see:
|
|
11
|
+
# https://github.com/sds/overcommit/tree/master/lib/overcommit/hook
|
|
12
|
+
#
|
|
13
|
+
# For a complete list of options that you can use to customize hooks, see:
|
|
14
|
+
# https://github.com/sds/overcommit#configuration
|
|
15
|
+
#
|
|
16
|
+
# Uncomment the following lines to make the configuration take effect.
|
|
17
|
+
|
|
18
|
+
#PreCommit:
|
|
19
|
+
# RuboCop:
|
|
20
|
+
# enabled: true
|
|
21
|
+
# on_warn: fail # Treat all warnings as failures
|
|
22
|
+
#
|
|
23
|
+
# TrailingWhitespace:
|
|
24
|
+
# enabled: true
|
|
25
|
+
# exclude:
|
|
26
|
+
# - '**/db/structure.sql' # Ignore trailing whitespace in generated files
|
|
27
|
+
#
|
|
28
|
+
#PostCheckout:
|
|
29
|
+
# ALL: # Special hook name that customizes all hooks of this type
|
|
30
|
+
# quiet: true # Change all post-checkout hooks to only display output on failure
|
|
31
|
+
#
|
|
32
|
+
# IndexTags:
|
|
33
|
+
# enabled: true # Generate a tags file with `ctags` each time HEAD changes
|
data/lib/overcommit.rb
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'overcommit/os'
|
|
4
|
+
require 'overcommit/constants'
|
|
5
|
+
require 'overcommit/exceptions'
|
|
6
|
+
require 'overcommit/utils/file_utils'
|
|
7
|
+
require 'overcommit/utils'
|
|
8
|
+
require 'overcommit/git_version'
|
|
9
|
+
require 'overcommit/configuration_validator'
|
|
10
|
+
require 'overcommit/configuration'
|
|
11
|
+
require 'overcommit/configuration_loader'
|
|
12
|
+
require 'overcommit/hook/base'
|
|
13
|
+
require 'overcommit/hook_context/base'
|
|
14
|
+
require 'overcommit/hook_context'
|
|
15
|
+
require 'overcommit/git_config'
|
|
16
|
+
require 'overcommit/git_repo'
|
|
17
|
+
require 'overcommit/hook_signer'
|
|
18
|
+
require 'overcommit/hook_loader/base'
|
|
19
|
+
require 'overcommit/hook_loader/built_in_hook_loader'
|
|
20
|
+
require 'overcommit/hook_loader/plugin_hook_loader'
|
|
21
|
+
require 'overcommit/interrupt_handler'
|
|
22
|
+
require 'overcommit/printer'
|
|
23
|
+
require 'overcommit/hook_runner'
|
|
24
|
+
require 'overcommit/installer'
|
|
25
|
+
require 'overcommit/logger'
|
|
26
|
+
require 'overcommit/version'
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'overcommit'
|
|
4
|
+
require 'optparse'
|
|
5
|
+
|
|
6
|
+
module Overcommit
|
|
7
|
+
# Responsible for parsing command-line options and executing appropriate
|
|
8
|
+
# application logic based on those options.
|
|
9
|
+
class CLI # rubocop:disable ClassLength
|
|
10
|
+
def initialize(arguments, input, logger)
|
|
11
|
+
@arguments = arguments
|
|
12
|
+
@input = input
|
|
13
|
+
@log = logger
|
|
14
|
+
@options = {}
|
|
15
|
+
|
|
16
|
+
Overcommit::Utils.log = logger
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def run
|
|
20
|
+
parse_arguments
|
|
21
|
+
|
|
22
|
+
case @options[:action]
|
|
23
|
+
when :install, :uninstall
|
|
24
|
+
install_or_uninstall
|
|
25
|
+
when :template_dir
|
|
26
|
+
print_template_directory_path
|
|
27
|
+
when :sign
|
|
28
|
+
sign
|
|
29
|
+
when :run_all
|
|
30
|
+
run_all
|
|
31
|
+
end
|
|
32
|
+
rescue Overcommit::Exceptions::ConfigurationSignatureChanged => ex
|
|
33
|
+
puts ex
|
|
34
|
+
exit 78 # EX_CONFIG
|
|
35
|
+
rescue Overcommit::Exceptions::HookContextLoadError => ex
|
|
36
|
+
puts ex
|
|
37
|
+
exit 64 # EX_USAGE
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
attr_reader :log
|
|
43
|
+
|
|
44
|
+
def parse_arguments
|
|
45
|
+
@parser = create_option_parser
|
|
46
|
+
|
|
47
|
+
begin
|
|
48
|
+
@parser.parse!(@arguments)
|
|
49
|
+
|
|
50
|
+
# Default action is to install
|
|
51
|
+
@options[:action] ||= :install
|
|
52
|
+
|
|
53
|
+
# Unconsumed arguments are our targets
|
|
54
|
+
@options[:targets] = @arguments
|
|
55
|
+
rescue OptionParser::InvalidOption => ex
|
|
56
|
+
print_help @parser.help, ex
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def create_option_parser
|
|
61
|
+
OptionParser.new do |opts|
|
|
62
|
+
opts.banner = "Usage: #{opts.program_name} [options] [target-repo]"
|
|
63
|
+
|
|
64
|
+
add_information_options(opts)
|
|
65
|
+
add_installation_options(opts)
|
|
66
|
+
add_other_options(opts)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def add_information_options(opts)
|
|
71
|
+
opts.on_tail('-h', '--help', 'Show this message') do
|
|
72
|
+
print_help opts.help
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
opts.on_tail('-v', '--version', 'Show version') do
|
|
76
|
+
print_version(opts.program_name)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
opts.on_tail('-l', '--list-hooks', 'List installed hooks') do
|
|
80
|
+
print_installed_hooks
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def add_installation_options(opts)
|
|
85
|
+
opts.on('-u', '--uninstall', 'Remove Overcommit hooks from a repository') do
|
|
86
|
+
@options[:action] = :uninstall
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
opts.on('-i', '--install', 'Install Overcommit hooks in a repository') do
|
|
90
|
+
@options[:action] = :install
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
opts.on('-f', '--force', 'Overwrite any previously installed hooks') do
|
|
94
|
+
@options[:force] = true
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
opts.on('-r', '--run', 'Run pre-commit hook against all git tracked files') do
|
|
98
|
+
@options[:action] = :run_all
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def add_other_options(opts)
|
|
103
|
+
opts.on('-s', '--sign [hook]', 'Update hook signatures', String) do |hook_to_sign|
|
|
104
|
+
@options[:hook_to_sign] = hook_to_sign if hook_to_sign.is_a?(String)
|
|
105
|
+
@options[:action] = :sign
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
opts.on('-t', '--template-dir', 'Print location of template directory') do
|
|
109
|
+
@options[:action] = :template_dir
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def install_or_uninstall
|
|
114
|
+
if Array(@options[:targets]).empty?
|
|
115
|
+
@options[:targets] = [Overcommit::Utils.repo_root].compact
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
if @options[:targets].empty?
|
|
119
|
+
log.warning 'You are not in a git repository.'
|
|
120
|
+
log.log 'You must either specify the path to a repository or ' \
|
|
121
|
+
'change your current directory to a repository.'
|
|
122
|
+
halt 64 # EX_USAGE
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
@options[:targets].each do |target|
|
|
126
|
+
begin
|
|
127
|
+
Installer.new(log).run(target, @options)
|
|
128
|
+
rescue Overcommit::Exceptions::InvalidGitRepo => error
|
|
129
|
+
log.warning "Invalid repo #{target}: #{error}"
|
|
130
|
+
halt 69 # EX_UNAVAILABLE
|
|
131
|
+
rescue Overcommit::Exceptions::PreExistingHooks => error
|
|
132
|
+
log.warning "Unable to install into #{target}: #{error}"
|
|
133
|
+
halt 73 # EX_CANTCREAT
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def print_template_directory_path
|
|
139
|
+
puts File.join(Overcommit::HOME, 'template-dir')
|
|
140
|
+
halt
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def print_help(message, error = nil)
|
|
144
|
+
log.error "#{error}\n" if error
|
|
145
|
+
log.log message
|
|
146
|
+
halt(error ? 64 : 0) # 64 = EX_USAGE
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def print_version(program_name)
|
|
150
|
+
log.log "#{program_name} #{Overcommit::VERSION}"
|
|
151
|
+
halt
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# Prints the hooks available in the current repo and whether they're
|
|
155
|
+
# enabled/disabled.
|
|
156
|
+
def print_installed_hooks
|
|
157
|
+
config.all_hook_configs.each do |hook_type, hook_configs|
|
|
158
|
+
print_hooks_for_hook_type(config, hook_configs, hook_type)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
halt
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def print_hooks_for_hook_type(repo_config, hook_configs, hook_type)
|
|
165
|
+
log.log "#{hook_type}:"
|
|
166
|
+
hook_configs.each do |hook_name, config|
|
|
167
|
+
log.partial " #{hook_name}: "
|
|
168
|
+
|
|
169
|
+
if config['enabled']
|
|
170
|
+
log.success('enabled', true)
|
|
171
|
+
else
|
|
172
|
+
log.error('disabled', true)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
if repo_config.plugin_hook?(hook_type, hook_name)
|
|
176
|
+
log.warning(' (plugin)')
|
|
177
|
+
else
|
|
178
|
+
log.newline
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def sign
|
|
184
|
+
if @options[:hook_to_sign]
|
|
185
|
+
context = Overcommit::HookContext.create(@options[:hook_to_sign],
|
|
186
|
+
config,
|
|
187
|
+
@arguments,
|
|
188
|
+
@input)
|
|
189
|
+
Overcommit::HookLoader::PluginHookLoader.new(config,
|
|
190
|
+
context,
|
|
191
|
+
log).update_signatures
|
|
192
|
+
else
|
|
193
|
+
log.log 'Updating signature for configuration file...'
|
|
194
|
+
config(verify: false).update_signature!
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
halt
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def run_all
|
|
201
|
+
empty_stdin = File.open(File::NULL) # pre-commit hooks don't take input
|
|
202
|
+
context = Overcommit::HookContext.create('run-all', config, @arguments, empty_stdin)
|
|
203
|
+
config.apply_environment!(context, ENV)
|
|
204
|
+
|
|
205
|
+
printer = Overcommit::Printer.new(config, log, context)
|
|
206
|
+
runner = Overcommit::HookRunner.new(config, log, context, printer)
|
|
207
|
+
|
|
208
|
+
status = runner.run
|
|
209
|
+
|
|
210
|
+
halt(status ? 0 : 65)
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
# Used for ease of stubbing in tests
|
|
214
|
+
def halt(status = 0)
|
|
215
|
+
exit status
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# Returns the configuration for this repository.
|
|
219
|
+
def config(options = {})
|
|
220
|
+
@config ||= Overcommit::ConfigurationLoader.new(log, options).load_repo_config
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
end
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Overcommit
|
|
4
|
+
# Distributes a list of arguments over multiple invocations of a command.
|
|
5
|
+
#
|
|
6
|
+
# This accomplishes the same functionality provided by `xargs` but in a
|
|
7
|
+
# cross-platform way that does not require any pre-existing tools.
|
|
8
|
+
#
|
|
9
|
+
# One of the tradeoffs with this approach is that we no longer deal with a
|
|
10
|
+
# single exit status from a command, but multiple (one for each invocation).
|
|
11
|
+
#
|
|
12
|
+
# This will return a struct similar to `Subprocess::Result` but with
|
|
13
|
+
# additional `statuses`, `stdouts`, and `stderrs` fields so hook authors can
|
|
14
|
+
# actually see the results of each invocation. If they don't care, the
|
|
15
|
+
# standard `status`, `stdout`, and `stderr` will still work but be a
|
|
16
|
+
# aggregation/concatenation of all statuses/outputs.
|
|
17
|
+
class CommandSplitter
|
|
18
|
+
# Encapsulates the result of a split argument run.
|
|
19
|
+
#
|
|
20
|
+
# @attr_reader statuses [Array<Integer>] status codes for invocations
|
|
21
|
+
# @attr_reader stdouts [Array<String>] standard outputs from invocations
|
|
22
|
+
# @attr_reader stderrs [Array<String>] standard error outputs from invocations
|
|
23
|
+
Result = Struct.new(:statuses, :stdouts, :stderrs) do
|
|
24
|
+
# Returns whether all invocations were successful.
|
|
25
|
+
#
|
|
26
|
+
# @return [true,false]
|
|
27
|
+
def success?
|
|
28
|
+
status == 0
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Returns `0` if all invocations returned `0`; `1` otherwise.
|
|
32
|
+
#
|
|
33
|
+
# @return [true,false]
|
|
34
|
+
def status
|
|
35
|
+
statuses.all? { |code| code == 0 } ? 0 : 1
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Returns concatenated standard output streams of all invocations in the
|
|
39
|
+
# order they were executed.
|
|
40
|
+
#
|
|
41
|
+
# @return [String]
|
|
42
|
+
def stdout
|
|
43
|
+
stdouts.join
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Returns concatenated standard error streams of all invocations in the
|
|
47
|
+
# order they were executed.
|
|
48
|
+
#
|
|
49
|
+
# @return [String]
|
|
50
|
+
def stderr
|
|
51
|
+
stderrs.join
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
class << self
|
|
56
|
+
def execute(initial_args, options)
|
|
57
|
+
options = options.dup
|
|
58
|
+
|
|
59
|
+
if (splittable_args = (options.delete(:args) { [] })).empty?
|
|
60
|
+
raise Overcommit::Exceptions::InvalidCommandArgs,
|
|
61
|
+
'Must specify list of arguments to split on'
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Execute each chunk of arguments in serial. We don't parallelize (yet)
|
|
65
|
+
# since in theory we want to support parallelization at the hook level
|
|
66
|
+
# and not within individual hooks.
|
|
67
|
+
results = extract_argument_lists(initial_args, splittable_args).map do |arg_list|
|
|
68
|
+
Overcommit::Subprocess.spawn(arg_list, options)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
Result.new(results.map(&:status), results.map(&:stdout), results.map(&:stderr))
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
private
|
|
75
|
+
|
|
76
|
+
# Given a list of prefix arguments and suffix arguments that can be split,
|
|
77
|
+
# returns a list of argument lists that are executable on the current OS
|
|
78
|
+
# without exceeding command line limitations.
|
|
79
|
+
def extract_argument_lists(args, splittable_args)
|
|
80
|
+
# Total number of bytes needed to contain the prefix command
|
|
81
|
+
# (including byte separators between each argument)
|
|
82
|
+
prefix_bytes = (args.size - 1) + args.reduce(0) { |sum, arg| sum + arg.bytesize }
|
|
83
|
+
|
|
84
|
+
if prefix_bytes >= max_command_length
|
|
85
|
+
raise Overcommit::Exceptions::InvalidCommandArgs,
|
|
86
|
+
"Command `#{args.take(5).join(' ')} ...` is longer than the " \
|
|
87
|
+
'maximum number of bytes allowed by the operating system ' \
|
|
88
|
+
"(#{max_command_length})"
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
arg_lists = []
|
|
92
|
+
index = 0
|
|
93
|
+
while index <= splittable_args.length - 1
|
|
94
|
+
arg_list, index = arguments_under_limit(splittable_args,
|
|
95
|
+
index,
|
|
96
|
+
max_command_length - prefix_bytes)
|
|
97
|
+
arg_lists << args + arg_list
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
arg_lists
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# @return [Array<Array<String>, Integer>] tuple of arguments and new index
|
|
104
|
+
def arguments_under_limit(splittable_args, start_index, byte_limit)
|
|
105
|
+
index = start_index
|
|
106
|
+
total_bytes = 0
|
|
107
|
+
|
|
108
|
+
loop do
|
|
109
|
+
break if index > splittable_args.length - 1
|
|
110
|
+
total_bytes += splittable_args[index].bytesize
|
|
111
|
+
break if total_bytes > byte_limit # Not enough room
|
|
112
|
+
index += 1
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
if index == start_index
|
|
116
|
+
# No argument was consumed; perhaps a really long argument?
|
|
117
|
+
raise Overcommit::Exceptions::InvalidCommandArgs,
|
|
118
|
+
"Argument `#{splittable_args[index][0..5]}...` exceeds the " \
|
|
119
|
+
'maximum command length when appended to command prefix and ' \
|
|
120
|
+
"can't be split further"
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
[splittable_args[start_index...index], index]
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# Returns the maximum number of arguments allowed in a single command on
|
|
127
|
+
# this system.
|
|
128
|
+
#
|
|
129
|
+
# @return [Integer]
|
|
130
|
+
def max_command_length
|
|
131
|
+
@max_command_length ||=
|
|
132
|
+
if Gem.win_platform?
|
|
133
|
+
# Windows is limited to 2048 since that is a worst-case scenario.
|
|
134
|
+
# http://blogs.msdn.com/b/oldnewthing/archive/2003/12/10/56028.aspx
|
|
135
|
+
2048
|
|
136
|
+
else
|
|
137
|
+
# We fudge factor this by halving the buffer size since *nix systems
|
|
138
|
+
# usually have pretty large limits, and the actual limit changes
|
|
139
|
+
# depending on how much of your stack is environment variables.
|
|
140
|
+
# Definitely erring on the side of overly cautious.
|
|
141
|
+
`getconf ARG_MAX`.to_i / 2
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'digest'
|
|
4
|
+
require 'json'
|
|
5
|
+
|
|
6
|
+
module Overcommit
|
|
7
|
+
# Stores configuration for Overcommit and the hooks it runs.
|
|
8
|
+
class Configuration # rubocop:disable ClassLength
|
|
9
|
+
# Creates a configuration from the given hash.
|
|
10
|
+
#
|
|
11
|
+
# @param hash [Hash] loaded YAML config file as a hash
|
|
12
|
+
# @param options [Hash]
|
|
13
|
+
# @option default [Boolean] whether this is the default built-in configuration
|
|
14
|
+
# @option logger [Overcommit::Logger]
|
|
15
|
+
def initialize(hash, options = {})
|
|
16
|
+
@options = options.dup
|
|
17
|
+
@options[:logger] ||= Overcommit::Logger.silent
|
|
18
|
+
@hash = hash # Assign so validator can read original values
|
|
19
|
+
unless options[:validate] == false
|
|
20
|
+
@hash = Overcommit::ConfigurationValidator.new.validate(self, hash, options)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def ==(other)
|
|
25
|
+
super || @hash == other.hash
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Access the configuration as if it were a hash.
|
|
29
|
+
#
|
|
30
|
+
# @param key [String]
|
|
31
|
+
# @return [Array,Hash,Number,String]
|
|
32
|
+
def [](key)
|
|
33
|
+
@hash[key]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Returns absolute path to the directory that external hook plugins should
|
|
37
|
+
# be loaded from.
|
|
38
|
+
def plugin_directory
|
|
39
|
+
File.join(Overcommit::Utils.repo_root, @hash['plugin_directory'] || '.git-hooks')
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def concurrency
|
|
43
|
+
@concurrency ||=
|
|
44
|
+
begin
|
|
45
|
+
cores = Overcommit::Utils.processor_count
|
|
46
|
+
content = @hash.fetch('concurrency') { '%<processors>d' }
|
|
47
|
+
if content.is_a?(String)
|
|
48
|
+
concurrency_expr = content % { processors: cores }
|
|
49
|
+
|
|
50
|
+
a, op, b = concurrency_expr.scan(%r{(\d+)\s*([+\-*\/])\s*(\d+)})[0]
|
|
51
|
+
if a
|
|
52
|
+
a.to_i.send(op, b.to_i)
|
|
53
|
+
else
|
|
54
|
+
concurrency_expr.to_i
|
|
55
|
+
end
|
|
56
|
+
else
|
|
57
|
+
content.to_i
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Returns configuration for all hooks in each hook type.
|
|
63
|
+
#
|
|
64
|
+
# @return [Hash]
|
|
65
|
+
def all_hook_configs
|
|
66
|
+
smart_merge(all_builtin_hook_configs, all_plugin_hook_configs)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Returns configuration for all built-in hooks in each hook type.
|
|
70
|
+
#
|
|
71
|
+
# @return [Hash]
|
|
72
|
+
def all_builtin_hook_configs
|
|
73
|
+
hook_configs = {}
|
|
74
|
+
|
|
75
|
+
Overcommit::Utils.supported_hook_type_classes.each do |hook_type|
|
|
76
|
+
hook_names = @hash[hook_type].keys.reject { |name| name == 'ALL' }
|
|
77
|
+
|
|
78
|
+
hook_configs[hook_type] = Hash[
|
|
79
|
+
hook_names.map do |hook_name|
|
|
80
|
+
[hook_name, for_hook(hook_name, hook_type)]
|
|
81
|
+
end
|
|
82
|
+
]
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
hook_configs
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Returns configuration for all plugin hooks in each hook type.
|
|
89
|
+
#
|
|
90
|
+
# @return [Hash]
|
|
91
|
+
def all_plugin_hook_configs
|
|
92
|
+
hook_configs = {}
|
|
93
|
+
|
|
94
|
+
Overcommit::Utils.supported_hook_types.each do |hook_type|
|
|
95
|
+
hook_type_class_name = Overcommit::Utils.camel_case(hook_type)
|
|
96
|
+
|
|
97
|
+
directory = File.join(plugin_directory, hook_type.tr('-', '_'))
|
|
98
|
+
plugin_paths = Dir[File.join(directory, '*.rb')].sort
|
|
99
|
+
|
|
100
|
+
hook_names = plugin_paths.map do |path|
|
|
101
|
+
Overcommit::Utils.camel_case(File.basename(path, '.rb'))
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
hook_configs[hook_type_class_name] = Hash[
|
|
105
|
+
hook_names.map do |hook_name|
|
|
106
|
+
[hook_name, for_hook(hook_name, Overcommit::Utils.camel_case(hook_type))]
|
|
107
|
+
end
|
|
108
|
+
]
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
hook_configs
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Returns the built-in hooks that have been enabled for a hook type.
|
|
115
|
+
def enabled_builtin_hooks(hook_context)
|
|
116
|
+
@hash[hook_context.hook_class_name].keys.
|
|
117
|
+
reject { |hook_name| hook_name == 'ALL' }.
|
|
118
|
+
select { |hook_name| built_in_hook?(hook_context, hook_name) }.
|
|
119
|
+
select { |hook_name| hook_enabled?(hook_context, hook_name) }
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Returns the ad hoc hooks that have been enabled for a hook type.
|
|
123
|
+
def enabled_ad_hoc_hooks(hook_context)
|
|
124
|
+
@hash[hook_context.hook_class_name].keys.
|
|
125
|
+
reject { |hook_name| hook_name == 'ALL' }.
|
|
126
|
+
select { |hook_name| ad_hoc_hook?(hook_context, hook_name) }.
|
|
127
|
+
select { |hook_name| hook_enabled?(hook_context, hook_name) }
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Returns a non-modifiable configuration for a hook.
|
|
131
|
+
def for_hook(hook, hook_type = nil)
|
|
132
|
+
unless hook_type
|
|
133
|
+
components = hook.class.name.split('::')
|
|
134
|
+
hook = components.last
|
|
135
|
+
hook_type = components[-2]
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# Merge hook configuration with special 'ALL' config
|
|
139
|
+
hook_config = smart_merge(@hash[hook_type]['ALL'], @hash[hook_type][hook] || {})
|
|
140
|
+
|
|
141
|
+
# Need to specially handle `enabled` option since not setting it does not
|
|
142
|
+
# necessarily mean the hook is disabled
|
|
143
|
+
hook_config['enabled'] = hook_enabled?(hook_type, hook)
|
|
144
|
+
|
|
145
|
+
hook_config.freeze
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Merges the given configuration with this one, returning a new
|
|
149
|
+
# {Configuration}. The provided configuration will either add to or replace
|
|
150
|
+
# any options defined in this configuration.
|
|
151
|
+
def merge(config)
|
|
152
|
+
self.class.new(smart_merge(@hash, config.hash))
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Applies additional configuration settings based on the provided
|
|
156
|
+
# environment variables.
|
|
157
|
+
def apply_environment!(hook_context, env)
|
|
158
|
+
skipped_hooks = "#{env['SKIP']} #{env['SKIP_CHECKS']} #{env['SKIP_HOOKS']}".split(/[:, ]/)
|
|
159
|
+
only_hooks = env.fetch('ONLY') { '' }.split(/[:, ]/)
|
|
160
|
+
hook_type = hook_context.hook_class_name
|
|
161
|
+
|
|
162
|
+
if only_hooks.any? || skipped_hooks.include?('all') || skipped_hooks.include?('ALL')
|
|
163
|
+
@hash[hook_type]['ALL']['skip'] = true
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
only_hooks.select { |hook_name| hook_exists?(hook_context, hook_name) }.
|
|
167
|
+
map { |hook_name| Overcommit::Utils.camel_case(hook_name) }.
|
|
168
|
+
each do |hook_name|
|
|
169
|
+
@hash[hook_type][hook_name] ||= {}
|
|
170
|
+
@hash[hook_type][hook_name]['skip'] = false
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
skipped_hooks.select { |hook_name| hook_exists?(hook_context, hook_name) }.
|
|
174
|
+
map { |hook_name| Overcommit::Utils.camel_case(hook_name) }.
|
|
175
|
+
each do |hook_name|
|
|
176
|
+
@hash[hook_type][hook_name] ||= {}
|
|
177
|
+
@hash[hook_type][hook_name]['skip'] = true
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def plugin_hook?(hook_context_or_type, hook_name)
|
|
182
|
+
hook_type_name =
|
|
183
|
+
if hook_context_or_type.is_a?(String)
|
|
184
|
+
Overcommit::Utils.snake_case(hook_context_or_type)
|
|
185
|
+
else
|
|
186
|
+
hook_context_or_type.hook_type_name
|
|
187
|
+
end
|
|
188
|
+
hook_name = Overcommit::Utils.snake_case(hook_name)
|
|
189
|
+
|
|
190
|
+
File.exist?(File.join(plugin_directory, hook_type_name, "#{hook_name}.rb"))
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
# Return whether the signature for this configuration has changed since it
|
|
194
|
+
# was last calculated.
|
|
195
|
+
#
|
|
196
|
+
# @return [true,false]
|
|
197
|
+
def signature_changed?
|
|
198
|
+
signature != stored_signature
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
# Return whether a previous signature has been recorded for this
|
|
202
|
+
# configuration.
|
|
203
|
+
#
|
|
204
|
+
# @return [true,false]
|
|
205
|
+
def previous_signature?
|
|
206
|
+
!stored_signature.empty?
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
# Returns whether this configuration should verify itself by checking the
|
|
210
|
+
# stored configuration for the repo.
|
|
211
|
+
#
|
|
212
|
+
# @return [true,false]
|
|
213
|
+
def verify_signatures?
|
|
214
|
+
return false if ENV['OVERCOMMIT_NO_VERIFY']
|
|
215
|
+
return true if @hash['verify_signatures'] != false
|
|
216
|
+
|
|
217
|
+
result = Overcommit::Utils.execute(
|
|
218
|
+
%W[git config --local --get #{verify_signature_config_key}]
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
if result.status == 1 # Key doesn't exist
|
|
222
|
+
return true
|
|
223
|
+
elsif result.status != 0
|
|
224
|
+
raise Overcommit::Exceptions::GitConfigError,
|
|
225
|
+
"Unable to read from local repo git config: #{result.stderr}"
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
# We don't cast since we want to allow anything to count as "true" except
|
|
229
|
+
# a literal zero
|
|
230
|
+
result.stdout.strip != '0'
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
# Update the currently stored signature for this hook.
|
|
234
|
+
def update_signature!
|
|
235
|
+
result = Overcommit::Utils.execute(
|
|
236
|
+
%w[git config --local] + [signature_config_key, signature]
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
verify_signature_value = @hash['verify_signatures'] ? 1 : 0
|
|
240
|
+
result &&= Overcommit::Utils.execute(
|
|
241
|
+
%W[git config --local #{verify_signature_config_key} #{verify_signature_value}]
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
unless result.success?
|
|
245
|
+
raise Overcommit::Exceptions::GitConfigError,
|
|
246
|
+
"Unable to write to local repo git config: #{result.stderr}"
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
protected
|
|
251
|
+
|
|
252
|
+
attr_reader :hash
|
|
253
|
+
|
|
254
|
+
private
|
|
255
|
+
|
|
256
|
+
def ad_hoc_hook?(hook_context, hook_name)
|
|
257
|
+
ad_hoc_conf = @hash.fetch(hook_context.hook_class_name) { {} }.fetch(hook_name) { {} }
|
|
258
|
+
|
|
259
|
+
# Ad hoc hooks are neither built-in nor have a plugin file written but
|
|
260
|
+
# still have a `command` specified to be run
|
|
261
|
+
!built_in_hook?(hook_context, hook_name) &&
|
|
262
|
+
!plugin_hook?(hook_context, hook_name) &&
|
|
263
|
+
(ad_hoc_conf['command'] || ad_hoc_conf['required_executable'])
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def built_in_hook?(hook_context, hook_name)
|
|
267
|
+
hook_name = Overcommit::Utils.snake_case(hook_name)
|
|
268
|
+
|
|
269
|
+
File.exist?(File.join(Overcommit::HOME, 'lib', 'overcommit', 'hook',
|
|
270
|
+
hook_context.hook_type_name, "#{hook_name}.rb"))
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
def hook_exists?(hook_context, hook_name)
|
|
274
|
+
built_in_hook?(hook_context, hook_name) ||
|
|
275
|
+
plugin_hook?(hook_context, hook_name) ||
|
|
276
|
+
ad_hoc_hook?(hook_context, hook_name)
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
def hook_enabled?(hook_context_or_type, hook_name)
|
|
280
|
+
hook_type =
|
|
281
|
+
if hook_context_or_type.is_a?(String)
|
|
282
|
+
hook_context_or_type
|
|
283
|
+
else
|
|
284
|
+
hook_context_or_type.hook_class_name
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
individual_enabled = @hash[hook_type].fetch(hook_name) { {} }['enabled']
|
|
288
|
+
return individual_enabled unless individual_enabled.nil?
|
|
289
|
+
|
|
290
|
+
all_enabled = @hash[hook_type]['ALL']['enabled']
|
|
291
|
+
return all_enabled unless all_enabled.nil?
|
|
292
|
+
|
|
293
|
+
false
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
def smart_merge(parent, child)
|
|
297
|
+
# Treat the ALL hook specially so that it overrides any configuration
|
|
298
|
+
# specified by the default configuration.
|
|
299
|
+
child_all = child['ALL']
|
|
300
|
+
unless child_all.nil?
|
|
301
|
+
parent = Hash[parent.collect { |k, v| [k, smart_merge(v, child_all)] }]
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
parent.merge(child) do |_key, old, new|
|
|
305
|
+
case old
|
|
306
|
+
when Hash
|
|
307
|
+
smart_merge(old, new)
|
|
308
|
+
else
|
|
309
|
+
new
|
|
310
|
+
end
|
|
311
|
+
end
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
# Returns the unique signature of this configuration.
|
|
315
|
+
#
|
|
316
|
+
# @return [String]
|
|
317
|
+
def signature
|
|
318
|
+
Digest::SHA256.hexdigest(@hash.to_json)
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
# Returns the stored signature of this repo's Overcommit configuration.
|
|
322
|
+
#
|
|
323
|
+
# This is intended to be compared against the current signature of this
|
|
324
|
+
# configuration object.
|
|
325
|
+
#
|
|
326
|
+
# @return [String]
|
|
327
|
+
def stored_signature
|
|
328
|
+
result = Overcommit::Utils.execute(
|
|
329
|
+
%w[git config --local --get] + [signature_config_key]
|
|
330
|
+
)
|
|
331
|
+
|
|
332
|
+
if result.status == 1 # Key doesn't exist
|
|
333
|
+
return ''
|
|
334
|
+
elsif result.status != 0
|
|
335
|
+
raise Overcommit::Exceptions::GitConfigError,
|
|
336
|
+
"Unable to read from local repo git config: #{result.stderr}"
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
result.stdout.chomp
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
def signature_config_key
|
|
343
|
+
'overcommit.configuration.signature'
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
def verify_signature_config_key
|
|
347
|
+
'overcommit.configuration.verifysignatures'
|
|
348
|
+
end
|
|
349
|
+
end
|
|
350
|
+
end
|