rails_git_hooks 0.7.0 → 0.7.2
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 +4 -4
- data/CHANGELOG.md +33 -6
- data/README.md +72 -115
- data/lib/rails_git_hooks/checks/base.rb +55 -0
- data/lib/rails_git_hooks/checks/commit_msg/jira_prefix.rb +31 -0
- data/lib/rails_git_hooks/checks/commit_msg.rb +10 -0
- data/lib/rails_git_hooks/checks/post_checkout/bundle_install.rb +16 -0
- data/lib/rails_git_hooks/checks/post_checkout/db_migrate.rb +16 -0
- data/lib/rails_git_hooks/checks/post_checkout.rb +11 -0
- data/lib/rails_git_hooks/checks/post_merge/bundle_install.rb +16 -0
- data/lib/rails_git_hooks/checks/post_merge/db_migrate.rb +16 -0
- data/lib/rails_git_hooks/checks/post_merge.rb +11 -0
- data/lib/rails_git_hooks/checks/pre_commit/debugger_check.rb +43 -0
- data/lib/rails_git_hooks/checks/pre_commit/default_branch.rb +20 -0
- data/lib/rails_git_hooks/checks/pre_commit/json_format_check.rb +30 -0
- data/lib/rails_git_hooks/checks/pre_commit/migrations_check.rb +37 -0
- data/lib/rails_git_hooks/checks/pre_commit/rubocop.rb +30 -0
- data/lib/rails_git_hooks/checks/pre_commit/whitespace_check.rb +31 -0
- data/lib/rails_git_hooks/checks/pre_commit/yaml_format_check.rb +31 -0
- data/lib/rails_git_hooks/checks/pre_commit.rb +16 -0
- data/lib/rails_git_hooks/checks/pre_push/run_tests.rb +24 -0
- data/lib/rails_git_hooks/checks/pre_push.rb +10 -0
- data/lib/rails_git_hooks/checks/shared/bundle_install_check.rb +28 -0
- data/lib/rails_git_hooks/checks/shared/db_migrate_check.rb +28 -0
- data/lib/rails_git_hooks/checks.rb +10 -0
- data/lib/rails_git_hooks/cli.rb +17 -90
- data/lib/rails_git_hooks/config/constants.rb +26 -0
- data/lib/rails_git_hooks/config/defaults.yml +190 -0
- data/lib/rails_git_hooks/config/defaults_loader.rb +42 -0
- data/lib/rails_git_hooks/core/check_definition.rb +63 -0
- data/lib/rails_git_hooks/core/check_result.rb +41 -0
- data/lib/rails_git_hooks/core/error.rb +5 -0
- data/lib/rails_git_hooks/install/installer.rb +79 -0
- data/lib/rails_git_hooks/runtime/check_registry.rb +33 -0
- data/lib/rails_git_hooks/runtime/dependency_checker.rb +51 -0
- data/lib/rails_git_hooks/runtime/file_matcher.rb +23 -0
- data/lib/rails_git_hooks/runtime/override_config.rb +131 -0
- data/lib/rails_git_hooks/runtime/policy_resolver.rb +36 -0
- data/lib/rails_git_hooks/runtime/repository.rb +69 -0
- data/lib/rails_git_hooks/runtime/runner.rb +80 -0
- data/lib/rails_git_hooks/runtime.rb +25 -0
- data/lib/rails_git_hooks/version.rb +1 -1
- data/lib/rails_git_hooks.rb +14 -6
- data/templates/hooks/commit-msg +7 -17
- data/templates/hooks/post-checkout +13 -0
- data/templates/hooks/post-merge +13 -0
- data/templates/hooks/pre-commit +7 -21
- data/templates/hooks/pre-push +7 -17
- metadata +41 -52
- data/lib/rails_git_hooks/constants.rb +0 -21
- data/lib/rails_git_hooks/installer.rb +0 -156
- data/templates/shared/commit_msg/jira_prefix.rb +0 -20
- data/templates/shared/pre_commit/debugger_check.rb +0 -48
- data/templates/shared/pre_commit/default_branch.rb +0 -9
- data/templates/shared/pre_commit/rubocop_check.rb +0 -24
- data/templates/shared/pre_commit/whitespace_check.rb +0 -25
- data/templates/shared/pre_push/run_tests.rb +0 -9
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GitHooks
|
|
4
|
+
module Checks
|
|
5
|
+
module PreCommit
|
|
6
|
+
class RuboCop < Base
|
|
7
|
+
check_definition key: 'rubocop-check',
|
|
8
|
+
hook: :pre_commit,
|
|
9
|
+
description: 'Run RuboCop on staged Ruby files',
|
|
10
|
+
file_based: true,
|
|
11
|
+
enabled: false,
|
|
12
|
+
quiet: true,
|
|
13
|
+
dependencies: { 'executables' => ['bundle'], 'libraries' => ['rubocop'] },
|
|
14
|
+
command: %w[bundle exec rubocop],
|
|
15
|
+
install_hint: 'Add `gem "rubocop"` to your Gemfile and run bundle install'
|
|
16
|
+
|
|
17
|
+
def run
|
|
18
|
+
ruby_files = applicable_files.select { |path| File.extname(path) == '.rb' && File.file?(path) }
|
|
19
|
+
return CheckResult.pass if ruby_files.empty?
|
|
20
|
+
|
|
21
|
+
output, status = capture(*Array(config['command']), *ruby_files)
|
|
22
|
+
return CheckResult.pass if status.success?
|
|
23
|
+
|
|
24
|
+
messages = output.split("\n").map(&:rstrip).reject(&:empty?)
|
|
25
|
+
CheckResult.fail(messages: messages)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GitHooks
|
|
4
|
+
module Checks
|
|
5
|
+
module PreCommit
|
|
6
|
+
class WhitespaceCheck < Base
|
|
7
|
+
check_definition key: 'whitespace-check',
|
|
8
|
+
hook: :pre_commit,
|
|
9
|
+
description: 'Reject trailing whitespace and conflict markers',
|
|
10
|
+
file_based: true,
|
|
11
|
+
enabled: false
|
|
12
|
+
|
|
13
|
+
def run
|
|
14
|
+
errors = []
|
|
15
|
+
|
|
16
|
+
applicable_files.each do |path|
|
|
17
|
+
next unless File.file?(path)
|
|
18
|
+
|
|
19
|
+
File.read(path).lines.each_with_index do |line, index|
|
|
20
|
+
errors << "#{path}:#{index + 1}: trailing whitespace" if line.match?(/[ \t]\z/)
|
|
21
|
+
stripped = line.strip
|
|
22
|
+
errors << "#{path}:#{index + 1}: conflict marker" if stripped.start_with?('<<<<<<<', '=======', '>>>>>>>')
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
errors.empty? ? CheckResult.pass : CheckResult.fail(messages: errors.uniq)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GitHooks
|
|
4
|
+
module Checks
|
|
5
|
+
module PreCommit
|
|
6
|
+
class YAMLFormatCheck < Base
|
|
7
|
+
check_definition key: 'yaml-format-check',
|
|
8
|
+
hook: :pre_commit,
|
|
9
|
+
description: 'Warn on invalid YAML',
|
|
10
|
+
file_based: true,
|
|
11
|
+
on_fail: :warn
|
|
12
|
+
|
|
13
|
+
def run
|
|
14
|
+
warnings = []
|
|
15
|
+
|
|
16
|
+
applicable_files.each do |path|
|
|
17
|
+
next unless File.file?(path)
|
|
18
|
+
next unless %w[.yml .yaml].include?(File.extname(path))
|
|
19
|
+
|
|
20
|
+
YAML.load_file(path)
|
|
21
|
+
rescue Psych::SyntaxError => e
|
|
22
|
+
location = e.line ? "#{path}:#{e.line}" : path
|
|
23
|
+
warnings << "#{location}: #{e.message}"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
warnings.empty? ? CheckResult.pass : CheckResult.fail(messages: warnings)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GitHooks
|
|
4
|
+
module Checks
|
|
5
|
+
module PreCommit
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
require_relative 'pre_commit/default_branch'
|
|
11
|
+
require_relative 'pre_commit/debugger_check'
|
|
12
|
+
require_relative 'pre_commit/yaml_format_check'
|
|
13
|
+
require_relative 'pre_commit/json_format_check'
|
|
14
|
+
require_relative 'pre_commit/migrations_check'
|
|
15
|
+
require_relative 'pre_commit/whitespace_check'
|
|
16
|
+
require_relative 'pre_commit/rubocop'
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GitHooks
|
|
4
|
+
module Checks
|
|
5
|
+
module PrePush
|
|
6
|
+
class RunTests < Base
|
|
7
|
+
check_definition key: 'run-tests',
|
|
8
|
+
hook: :pre_push,
|
|
9
|
+
description: 'Run test suite before push',
|
|
10
|
+
dependencies: { 'executables' => ['bundle'] },
|
|
11
|
+
command: %w[bundle exec rspec],
|
|
12
|
+
install_hint: 'Install test dependencies and ensure `bundle exec rspec` runs successfully'
|
|
13
|
+
|
|
14
|
+
def run
|
|
15
|
+
output, status = capture(*Array(config['command']))
|
|
16
|
+
return CheckResult.pass if status.success?
|
|
17
|
+
|
|
18
|
+
messages = output.split("\n").map(&:rstrip).reject(&:empty?)
|
|
19
|
+
CheckResult.fail(messages: messages)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GitHooks
|
|
4
|
+
module Checks
|
|
5
|
+
# Shared logic and options for "run bundle install when Gemfile/Gemfile.lock changed"
|
|
6
|
+
# (post-checkout and post-merge). Each hook has its own class that passes hook + description.
|
|
7
|
+
module BundleInstallCheck
|
|
8
|
+
DEFINITION_OPTIONS = {
|
|
9
|
+
file_based: true,
|
|
10
|
+
enabled: false,
|
|
11
|
+
include: %w[Gemfile Gemfile.lock],
|
|
12
|
+
dependencies: { executables: ['bundle'] },
|
|
13
|
+
command: %w[bundle install],
|
|
14
|
+
install_hint: 'Ensure bundle is available'
|
|
15
|
+
}.freeze
|
|
16
|
+
|
|
17
|
+
def run
|
|
18
|
+
return CheckResult.pass if applicable_files.empty?
|
|
19
|
+
|
|
20
|
+
output, status = capture(*Array(config['command']))
|
|
21
|
+
return CheckResult.pass if status.success?
|
|
22
|
+
|
|
23
|
+
messages = output.split("\n").map(&:rstrip).reject(&:empty?)
|
|
24
|
+
CheckResult.fail(messages: messages)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GitHooks
|
|
4
|
+
module Checks
|
|
5
|
+
# Shared logic and options for "run db:migrate when migrations or schema changed"
|
|
6
|
+
# (post-checkout and post-merge). Each hook has its own class that passes hook + description.
|
|
7
|
+
module DbMigrateCheck
|
|
8
|
+
DEFINITION_OPTIONS = {
|
|
9
|
+
file_based: true,
|
|
10
|
+
enabled: false,
|
|
11
|
+
include: ['db/migrate/*.rb', 'db/schema.rb', 'db/structure.sql'],
|
|
12
|
+
dependencies: { executables: ['bundle'] },
|
|
13
|
+
command: %w[bundle exec rails db:migrate],
|
|
14
|
+
install_hint: 'Rails app with db:migrate (or override command in config)'
|
|
15
|
+
}.freeze
|
|
16
|
+
|
|
17
|
+
def run
|
|
18
|
+
return CheckResult.pass if applicable_files.empty?
|
|
19
|
+
|
|
20
|
+
output, status = capture(*Array(config['command']))
|
|
21
|
+
return CheckResult.pass if status.success?
|
|
22
|
+
|
|
23
|
+
messages = output.split("\n").map(&:rstrip).reject(&:empty?)
|
|
24
|
+
CheckResult.fail(messages: messages)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'checks/base'
|
|
4
|
+
require_relative 'checks/pre_commit'
|
|
5
|
+
require_relative 'checks/commit_msg'
|
|
6
|
+
require_relative 'checks/pre_push'
|
|
7
|
+
require_relative 'checks/shared/bundle_install_check'
|
|
8
|
+
require_relative 'checks/shared/db_migrate_check'
|
|
9
|
+
require_relative 'checks/post_checkout'
|
|
10
|
+
require_relative 'checks/post_merge'
|
data/lib/rails_git_hooks/cli.rb
CHANGED
|
@@ -4,25 +4,18 @@ require 'rails_git_hooks'
|
|
|
4
4
|
|
|
5
5
|
module GitHooks
|
|
6
6
|
class CLI
|
|
7
|
-
FEATURE_FLAG_TOKENS = GitHooks::Constants::FEATURE_FLAG_FILES.keys.freeze
|
|
8
|
-
|
|
9
7
|
def self.run(argv = ARGV)
|
|
10
8
|
new.run(argv)
|
|
11
9
|
end
|
|
12
10
|
|
|
13
11
|
def run(argv)
|
|
14
|
-
|
|
12
|
+
cmd = argv[0].to_s.strip.tr('_', '-')
|
|
13
|
+
case cmd
|
|
15
14
|
when 'install'
|
|
16
|
-
run_install
|
|
17
|
-
when '
|
|
18
|
-
|
|
19
|
-
when '
|
|
20
|
-
run_disable(argv[1..])
|
|
21
|
-
when 'enable'
|
|
22
|
-
run_enable(argv[1..])
|
|
23
|
-
when 'disabled'
|
|
24
|
-
run_disabled
|
|
25
|
-
when nil, '-h', '--help'
|
|
15
|
+
run_install
|
|
16
|
+
when 'init'
|
|
17
|
+
run_init
|
|
18
|
+
when '', '-h', '--help'
|
|
26
19
|
print_help
|
|
27
20
|
else
|
|
28
21
|
warn "Unknown command: #{argv[0]}"
|
|
@@ -33,102 +26,36 @@ module GitHooks
|
|
|
33
26
|
|
|
34
27
|
private
|
|
35
28
|
|
|
36
|
-
def run_install
|
|
29
|
+
def run_install
|
|
37
30
|
installer = Installer.new
|
|
38
|
-
installed = installer.install
|
|
31
|
+
installed = installer.install
|
|
39
32
|
puts "Installed hooks: #{installed.join(', ')}"
|
|
40
33
|
rescue GitHooks::Error => e
|
|
41
34
|
warn "Error: #{e.message}"
|
|
42
35
|
exit 1
|
|
43
36
|
end
|
|
44
37
|
|
|
45
|
-
def
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
def run_disable(args)
|
|
50
|
-
tokens = parse_tokens(args)
|
|
51
|
-
if tokens.empty?
|
|
52
|
-
warn 'Usage: rails_git_hooks disable HOOK [HOOK...] [whitespace-check] [rubocop-check]'
|
|
53
|
-
warn "Use '*' to disable all hooks."
|
|
54
|
-
exit 1
|
|
55
|
-
end
|
|
56
|
-
installer = Installer.new
|
|
57
|
-
hook_names, feature_flags = split_tokens(tokens)
|
|
58
|
-
feature_flags.each { |name| installer.public_send(:"disable_#{name.tr('-', '_')}") }
|
|
59
|
-
installer.disable(*hook_names) if hook_names.any?
|
|
60
|
-
puts "Disabled: #{(hook_names + feature_flags).join(', ')}"
|
|
61
|
-
rescue GitHooks::Error => e
|
|
62
|
-
warn "Error: #{e.message}"
|
|
63
|
-
exit 1
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
def run_enable(args)
|
|
67
|
-
tokens = parse_tokens(args)
|
|
68
|
-
if tokens.empty?
|
|
69
|
-
warn 'Usage: rails_git_hooks enable HOOK [HOOK...] [whitespace-check] [rubocop-check]'
|
|
70
|
-
exit 1
|
|
71
|
-
end
|
|
72
|
-
installer = Installer.new
|
|
73
|
-
hook_names, feature_flags = split_tokens(tokens)
|
|
74
|
-
feature_flags.each { |name| installer.public_send(:"enable_#{name.tr('-', '_')}") }
|
|
75
|
-
installer.enable(*hook_names) if hook_names.any?
|
|
76
|
-
puts "Enabled: #{(hook_names + feature_flags).join(', ')}"
|
|
77
|
-
rescue GitHooks::Error => e
|
|
78
|
-
warn "Error: #{e.message}"
|
|
79
|
-
exit 1
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
def parse_tokens(args)
|
|
83
|
-
args.reject { |a| a.start_with?('-') }
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
def split_tokens(tokens)
|
|
87
|
-
feature_flags = tokens & FEATURE_FLAG_TOKENS
|
|
88
|
-
hook_names = tokens - FEATURE_FLAG_TOKENS
|
|
89
|
-
[hook_names, feature_flags]
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
def run_disabled
|
|
93
|
-
installer = Installer.new
|
|
94
|
-
list = installer.disabled_hooks
|
|
95
|
-
if list.empty?
|
|
96
|
-
puts 'No hooks disabled.'
|
|
97
|
-
else
|
|
98
|
-
puts "Disabled hooks: #{list.join(', ')}"
|
|
99
|
-
end
|
|
100
|
-
rescue GitHooks::Error => e
|
|
101
|
-
warn "Error: #{e.message}"
|
|
102
|
-
exit 1
|
|
38
|
+
def run_init
|
|
39
|
+
config = OverrideConfig.new(repo: Repository.new)
|
|
40
|
+
config.init
|
|
41
|
+
puts "Initialized #{Constants::CONFIG_FILE}"
|
|
103
42
|
end
|
|
104
43
|
|
|
105
44
|
def print_help
|
|
106
45
|
puts <<~HELP
|
|
107
|
-
rails_git_hooks - Install
|
|
46
|
+
rails_git_hooks - Install configurable Git hooks
|
|
108
47
|
|
|
109
48
|
Usage:
|
|
110
|
-
rails_git_hooks install
|
|
111
|
-
rails_git_hooks
|
|
112
|
-
rails_git_hooks enable HOOK [HOOK...] [whitespace-check] [rubocop-check]
|
|
113
|
-
rails_git_hooks disabled
|
|
114
|
-
rails_git_hooks list
|
|
49
|
+
rails_git_hooks install
|
|
50
|
+
rails_git_hooks init
|
|
115
51
|
rails_git_hooks --help
|
|
116
52
|
|
|
117
53
|
Commands:
|
|
118
|
-
install Install hooks
|
|
119
|
-
|
|
120
|
-
enable Re-enable disabled hooks or enable whitespace-check / rubocop-check.
|
|
121
|
-
disabled List currently disabled hooks.
|
|
122
|
-
list List available hook names.
|
|
54
|
+
install Install hooks that have at least one enabled check (merged config: defaults + .rails_git_hooks.yml + .rails_git_hooks.local.yml).
|
|
55
|
+
init Create a sparse #{Constants::CONFIG_FILE} override file.
|
|
123
56
|
|
|
124
57
|
Examples:
|
|
125
58
|
rails_git_hooks install
|
|
126
|
-
rails_git_hooks disable pre-commit
|
|
127
|
-
rails_git_hooks disable * # disable all hooks
|
|
128
|
-
rails_git_hooks enable pre-commit
|
|
129
|
-
rails_git_hooks enable whitespace-check # trailing ws/conflict markers (off by default)
|
|
130
|
-
rails_git_hooks enable rubocop-check # RuboCop on staged .rb files (off by default)
|
|
131
|
-
rails_git_hooks install commit-msg pre-commit
|
|
132
59
|
HELP
|
|
133
60
|
end
|
|
134
61
|
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GitHooks
|
|
4
|
+
# Paths and default config (single source of truth).
|
|
5
|
+
module Constants
|
|
6
|
+
GEM_ROOT = File.expand_path('../../..', __dir__)
|
|
7
|
+
HOOKS_DIR = File.expand_path('templates/hooks', GEM_ROOT).freeze
|
|
8
|
+
RUNTIME_SOURCE_DIR = File.expand_path('lib/rails_git_hooks', GEM_ROOT).freeze
|
|
9
|
+
RUNTIME_DIR_NAME = 'rails_git_hooks'
|
|
10
|
+
CONFIG_FILE = '.rails_git_hooks.yml'
|
|
11
|
+
CONFIG_FILE_LOCAL = '.rails_git_hooks.local.yml'
|
|
12
|
+
|
|
13
|
+
# Default hooks when install is run with no arguments.
|
|
14
|
+
DEFAULT_HOOKS = %w[commit-msg pre-commit].freeze
|
|
15
|
+
HOOK_CONFIG_NAMES = {
|
|
16
|
+
pre_commit: 'PreCommit',
|
|
17
|
+
commit_msg: 'CommitMsg',
|
|
18
|
+
pre_push: 'PrePush',
|
|
19
|
+
post_checkout: 'PostCheckout',
|
|
20
|
+
post_merge: 'PostMerge'
|
|
21
|
+
}.freeze
|
|
22
|
+
|
|
23
|
+
# Section name (from YAML) -> hook script name (e.g. for install)
|
|
24
|
+
SECTION_TO_HOOK = HOOK_CONFIG_NAMES.invert.transform_values { |sym| sym.to_s.tr('_', '-') }.freeze
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# Default config for each check. Overrides live in .rails_git_hooks.yml (sparse).
|
|
2
|
+
# Structure matches .rails_git_hooks.yml: hook section -> check config_name -> options.
|
|
3
|
+
|
|
4
|
+
PreCommit:
|
|
5
|
+
DefaultBranch:
|
|
6
|
+
enabled: true
|
|
7
|
+
quiet: false
|
|
8
|
+
on_fail: fail
|
|
9
|
+
on_warn: warn
|
|
10
|
+
on_missing_dependency: warn
|
|
11
|
+
include: []
|
|
12
|
+
exclude: []
|
|
13
|
+
dependencies: {}
|
|
14
|
+
command: []
|
|
15
|
+
description: Prevent commits on default branch
|
|
16
|
+
file_based: false
|
|
17
|
+
|
|
18
|
+
DebuggerCheck:
|
|
19
|
+
enabled: true
|
|
20
|
+
quiet: false
|
|
21
|
+
on_fail: warn
|
|
22
|
+
on_warn: warn
|
|
23
|
+
on_missing_dependency: warn
|
|
24
|
+
include: []
|
|
25
|
+
exclude: []
|
|
26
|
+
dependencies: {}
|
|
27
|
+
command: []
|
|
28
|
+
description: Warn on debugger statements
|
|
29
|
+
file_based: true
|
|
30
|
+
|
|
31
|
+
YAMLFormatCheck:
|
|
32
|
+
enabled: true
|
|
33
|
+
quiet: false
|
|
34
|
+
on_fail: warn
|
|
35
|
+
on_warn: warn
|
|
36
|
+
on_missing_dependency: warn
|
|
37
|
+
include: []
|
|
38
|
+
exclude: []
|
|
39
|
+
dependencies: {}
|
|
40
|
+
command: []
|
|
41
|
+
description: Warn on invalid YAML
|
|
42
|
+
file_based: true
|
|
43
|
+
|
|
44
|
+
JSONFormatCheck:
|
|
45
|
+
enabled: true
|
|
46
|
+
quiet: false
|
|
47
|
+
on_fail: warn
|
|
48
|
+
on_warn: warn
|
|
49
|
+
on_missing_dependency: warn
|
|
50
|
+
include: []
|
|
51
|
+
exclude: []
|
|
52
|
+
dependencies: {}
|
|
53
|
+
command: []
|
|
54
|
+
description: Warn on invalid JSON
|
|
55
|
+
file_based: true
|
|
56
|
+
|
|
57
|
+
MigrationsCheck:
|
|
58
|
+
enabled: true
|
|
59
|
+
quiet: false
|
|
60
|
+
on_fail: warn
|
|
61
|
+
on_warn: warn
|
|
62
|
+
on_missing_dependency: warn
|
|
63
|
+
include: []
|
|
64
|
+
exclude: []
|
|
65
|
+
dependencies: {}
|
|
66
|
+
command: []
|
|
67
|
+
description: Warn on missing schema files after migrations
|
|
68
|
+
file_based: true
|
|
69
|
+
|
|
70
|
+
WhitespaceCheck:
|
|
71
|
+
enabled: false
|
|
72
|
+
quiet: false
|
|
73
|
+
on_fail: fail
|
|
74
|
+
on_warn: warn
|
|
75
|
+
on_missing_dependency: warn
|
|
76
|
+
include: []
|
|
77
|
+
exclude: []
|
|
78
|
+
dependencies: {}
|
|
79
|
+
command: []
|
|
80
|
+
description: Reject trailing whitespace and conflict markers
|
|
81
|
+
file_based: true
|
|
82
|
+
|
|
83
|
+
RuboCop:
|
|
84
|
+
enabled: false
|
|
85
|
+
quiet: true
|
|
86
|
+
on_fail: fail
|
|
87
|
+
on_warn: warn
|
|
88
|
+
on_missing_dependency: warn
|
|
89
|
+
include: []
|
|
90
|
+
exclude: []
|
|
91
|
+
dependencies:
|
|
92
|
+
executables: [bundle]
|
|
93
|
+
libraries: [rubocop]
|
|
94
|
+
command: [bundle, exec, rubocop]
|
|
95
|
+
description: Run RuboCop on staged Ruby files
|
|
96
|
+
file_based: true
|
|
97
|
+
install_hint: Add `gem "rubocop"` to your Gemfile and run bundle install
|
|
98
|
+
|
|
99
|
+
CommitMsg:
|
|
100
|
+
JiraPrefix:
|
|
101
|
+
enabled: true
|
|
102
|
+
quiet: false
|
|
103
|
+
on_fail: fail
|
|
104
|
+
on_warn: warn
|
|
105
|
+
on_missing_dependency: warn
|
|
106
|
+
include: []
|
|
107
|
+
exclude: []
|
|
108
|
+
dependencies: {}
|
|
109
|
+
command: []
|
|
110
|
+
description: Prefix commit messages with ticket id from branch
|
|
111
|
+
file_based: false
|
|
112
|
+
|
|
113
|
+
PrePush:
|
|
114
|
+
RunTests:
|
|
115
|
+
enabled: false
|
|
116
|
+
quiet: false
|
|
117
|
+
on_fail: fail
|
|
118
|
+
on_warn: warn
|
|
119
|
+
on_missing_dependency: warn
|
|
120
|
+
include: []
|
|
121
|
+
exclude: []
|
|
122
|
+
dependencies:
|
|
123
|
+
executables: [bundle]
|
|
124
|
+
libraries: [rspec]
|
|
125
|
+
command: [bundle, exec, rspec]
|
|
126
|
+
description: Run test suite before push
|
|
127
|
+
file_based: false
|
|
128
|
+
install_hint: Install test dependencies and ensure `bundle exec rspec` runs successfully
|
|
129
|
+
|
|
130
|
+
PostCheckout:
|
|
131
|
+
BundleInstall:
|
|
132
|
+
enabled: true
|
|
133
|
+
quiet: false
|
|
134
|
+
on_fail: fail
|
|
135
|
+
on_warn: warn
|
|
136
|
+
on_missing_dependency: warn
|
|
137
|
+
include: [Gemfile, Gemfile.lock]
|
|
138
|
+
exclude: []
|
|
139
|
+
dependencies:
|
|
140
|
+
executables: [bundle]
|
|
141
|
+
command: [bundle, install]
|
|
142
|
+
description: Run bundle install when Gemfile or Gemfile.lock changed (branch checkout)
|
|
143
|
+
file_based: true
|
|
144
|
+
install_hint: Ensure bundle is available
|
|
145
|
+
|
|
146
|
+
DbMigrate:
|
|
147
|
+
enabled: true
|
|
148
|
+
quiet: false
|
|
149
|
+
on_fail: fail
|
|
150
|
+
on_warn: warn
|
|
151
|
+
on_missing_dependency: warn
|
|
152
|
+
include: [db/migrate/*.rb, db/schema.rb, db/structure.sql]
|
|
153
|
+
exclude: []
|
|
154
|
+
dependencies:
|
|
155
|
+
executables: [bundle]
|
|
156
|
+
command: [bundle, exec, rails, db:migrate]
|
|
157
|
+
description: Run db:migrate when migrations or schema changed (branch checkout)
|
|
158
|
+
file_based: true
|
|
159
|
+
install_hint: Rails app with db:migrate (or override command in config)
|
|
160
|
+
|
|
161
|
+
PostMerge:
|
|
162
|
+
BundleInstall:
|
|
163
|
+
enabled: true
|
|
164
|
+
quiet: false
|
|
165
|
+
on_fail: fail
|
|
166
|
+
on_warn: warn
|
|
167
|
+
on_missing_dependency: warn
|
|
168
|
+
include: [Gemfile, Gemfile.lock]
|
|
169
|
+
exclude: []
|
|
170
|
+
dependencies:
|
|
171
|
+
executables: [bundle]
|
|
172
|
+
command: [bundle, install]
|
|
173
|
+
description: Run bundle install when Gemfile or Gemfile.lock changed (after merge)
|
|
174
|
+
file_based: true
|
|
175
|
+
install_hint: Ensure bundle is available
|
|
176
|
+
|
|
177
|
+
DbMigrate:
|
|
178
|
+
enabled: true
|
|
179
|
+
quiet: false
|
|
180
|
+
on_fail: fail
|
|
181
|
+
on_warn: warn
|
|
182
|
+
on_missing_dependency: warn
|
|
183
|
+
include: [db/migrate/*.rb, db/schema.rb, db/structure.sql]
|
|
184
|
+
exclude: []
|
|
185
|
+
dependencies:
|
|
186
|
+
executables: [bundle]
|
|
187
|
+
command: [bundle, exec, rails, db:migrate]
|
|
188
|
+
description: Run db:migrate when migrations or schema changed (after merge)
|
|
189
|
+
file_based: true
|
|
190
|
+
install_hint: Rails app with db:migrate (or override command in config)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'yaml'
|
|
4
|
+
|
|
5
|
+
module GitHooks
|
|
6
|
+
class DefaultsLoader
|
|
7
|
+
DEFAULTS_PATH = File.expand_path('defaults.yml', __dir__)
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
def config_for(hook_section, config_name)
|
|
11
|
+
section = data.fetch(hook_section, {})
|
|
12
|
+
return nil if section.empty?
|
|
13
|
+
|
|
14
|
+
section.fetch(config_name, nil)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def data
|
|
20
|
+
@data ||= load
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def load
|
|
24
|
+
return {} unless File.exist?(DEFAULTS_PATH)
|
|
25
|
+
|
|
26
|
+
raw = YAML.safe_load(File.read(DEFAULTS_PATH), aliases: true) || {}
|
|
27
|
+
deep_stringify(raw)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def deep_stringify(value)
|
|
31
|
+
case value
|
|
32
|
+
when Hash
|
|
33
|
+
value.each_with_object({}) { |(k, v), out| out[k.to_s] = deep_stringify(v) }
|
|
34
|
+
when Array
|
|
35
|
+
value.map { |v| deep_stringify(v) }
|
|
36
|
+
else
|
|
37
|
+
value
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GitHooks
|
|
4
|
+
class CheckDefinition
|
|
5
|
+
DEFAULTS = {
|
|
6
|
+
enabled: true,
|
|
7
|
+
quiet: false,
|
|
8
|
+
on_fail: :fail,
|
|
9
|
+
on_warn: :warn,
|
|
10
|
+
on_missing_dependency: :warn,
|
|
11
|
+
include: [],
|
|
12
|
+
exclude: [],
|
|
13
|
+
dependencies: {},
|
|
14
|
+
command: nil,
|
|
15
|
+
file_based: false
|
|
16
|
+
}.freeze
|
|
17
|
+
|
|
18
|
+
attr_reader :key, :config_name, :hook, :klass, :description
|
|
19
|
+
|
|
20
|
+
def initialize(key:, config_name:, hook:, klass:, description:, **options)
|
|
21
|
+
@key = key
|
|
22
|
+
@config_name = config_name
|
|
23
|
+
@hook = hook
|
|
24
|
+
@klass = klass
|
|
25
|
+
@description = description
|
|
26
|
+
@options = DEFAULTS.merge(options)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def default_config
|
|
30
|
+
{
|
|
31
|
+
'enabled' => @options[:enabled],
|
|
32
|
+
'quiet' => @options[:quiet],
|
|
33
|
+
'on_fail' => @options[:on_fail].to_s,
|
|
34
|
+
'on_warn' => @options[:on_warn].to_s,
|
|
35
|
+
'on_missing_dependency' => @options[:on_missing_dependency].to_s,
|
|
36
|
+
'include' => Array(@options[:include]),
|
|
37
|
+
'exclude' => Array(@options[:exclude]),
|
|
38
|
+
'dependencies' => deep_stringify(@options[:dependencies]),
|
|
39
|
+
'command' => Array(@options[:command]).compact,
|
|
40
|
+
'description' => description,
|
|
41
|
+
'file_based' => @options[:file_based],
|
|
42
|
+
'install_hint' => @options[:install_hint]
|
|
43
|
+
}.compact
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def hook_section
|
|
47
|
+
Constants::HOOK_CONFIG_NAMES.fetch(hook)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
def deep_stringify(value)
|
|
53
|
+
case value
|
|
54
|
+
when Hash
|
|
55
|
+
value.each_with_object({}) { |(key, nested), out| out[key.to_s] = deep_stringify(nested) }
|
|
56
|
+
when Array
|
|
57
|
+
value.map { |nested| deep_stringify(nested) }
|
|
58
|
+
else
|
|
59
|
+
value
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|