overcommit 0.13.0 → 0.14.0
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/config/default.yml +2 -0
- data/lib/overcommit.rb +3 -0
- data/lib/overcommit/cli.rb +41 -27
- data/lib/overcommit/configuration.rb +1 -29
- data/lib/overcommit/configuration_validator.rb +41 -0
- data/lib/overcommit/git_repo.rb +121 -0
- data/lib/overcommit/hook/base.rb +13 -2
- data/lib/overcommit/hook/pre_commit/image_optim.rb +3 -3
- data/lib/overcommit/hook/pre_commit/jscs.rb +1 -1
- data/lib/overcommit/hook/pre_commit/rails_schema_up_to_date.rb +1 -1
- data/lib/overcommit/hook_context/pre_commit.rb +17 -93
- data/lib/overcommit/hook_runner.rb +15 -64
- data/lib/overcommit/printer.rb +105 -0
- data/lib/overcommit/version.rb +1 -1
- data/template-dir/hooks/commit-msg +2 -1
- data/template-dir/hooks/overcommit-hook +2 -1
- data/template-dir/hooks/post-checkout +2 -1
- data/template-dir/hooks/pre-commit +2 -1
- metadata +17 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fb17024356867bde9bd05acbeee3d3e21d1c2c4d
|
4
|
+
data.tar.gz: 6d0e29731c275e36832826d17b9261a256f75738
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fc9754e4d5eeed0c7e0f53c3743fdf1d2ee76829c7e085053a795a3950b57c7cd7cd1aaa47a84a4c2943bb4a40377ef70900b0fffd4b226ad5ef6e85402600ca
|
7
|
+
data.tar.gz: fa43ebdc705f91361e7e6964ca0a1315d0d42cffff876e9389d573997f3835b321ba339e0f266bd9a646ded011db32d5feeed7e29aa1d48127ebe36dec17f583
|
data/config/default.yml
CHANGED
data/lib/overcommit.rb
CHANGED
@@ -1,16 +1,19 @@
|
|
1
1
|
require 'overcommit/constants'
|
2
2
|
require 'overcommit/exceptions'
|
3
|
+
require 'overcommit/configuration_validator'
|
3
4
|
require 'overcommit/configuration'
|
4
5
|
require 'overcommit/configuration_loader'
|
5
6
|
require 'overcommit/hook/base'
|
6
7
|
require 'overcommit/hook_context/base'
|
7
8
|
require 'overcommit/hook_context'
|
8
9
|
require 'overcommit/user_input'
|
10
|
+
require 'overcommit/git_repo'
|
9
11
|
require 'overcommit/hook_signer'
|
10
12
|
require 'overcommit/hook_loader/base'
|
11
13
|
require 'overcommit/hook_loader/built_in_hook_loader'
|
12
14
|
require 'overcommit/hook_loader/plugin_hook_loader'
|
13
15
|
require 'overcommit/interrupt_handler'
|
16
|
+
require 'overcommit/printer'
|
14
17
|
require 'overcommit/hook_runner'
|
15
18
|
require 'overcommit/installer'
|
16
19
|
require 'overcommit/logger'
|
data/lib/overcommit/cli.rb
CHANGED
@@ -26,33 +26,7 @@ module Overcommit
|
|
26
26
|
attr_reader :log
|
27
27
|
|
28
28
|
def parse_arguments
|
29
|
-
@parser =
|
30
|
-
opts.banner = "Usage: #{opts.program_name} [options] [target-repo]"
|
31
|
-
|
32
|
-
opts.on_tail('-h', '--help', 'Show this message') do
|
33
|
-
print_help opts.help
|
34
|
-
end
|
35
|
-
|
36
|
-
opts.on_tail('-v', '--version', 'Show version') do
|
37
|
-
print_version(opts.program_name)
|
38
|
-
end
|
39
|
-
|
40
|
-
opts.on('-u', '--uninstall', 'Remove Overcommit hooks from a repository') do
|
41
|
-
@options[:action] = :uninstall
|
42
|
-
end
|
43
|
-
|
44
|
-
opts.on('-i', '--install', 'Install Overcommit hooks in a repository') do
|
45
|
-
@options[:action] = :install
|
46
|
-
end
|
47
|
-
|
48
|
-
opts.on('-f', '--force', 'Overwrite any previously installed hooks') do
|
49
|
-
@options[:force] = true
|
50
|
-
end
|
51
|
-
|
52
|
-
opts.on('-t', '--template-dir', 'Print location of template directory') do
|
53
|
-
@options[:action] = :template_dir
|
54
|
-
end
|
55
|
-
end
|
29
|
+
@parser = create_option_parser
|
56
30
|
|
57
31
|
begin
|
58
32
|
@parser.parse!(@arguments)
|
@@ -67,6 +41,46 @@ module Overcommit
|
|
67
41
|
end
|
68
42
|
end
|
69
43
|
|
44
|
+
def create_option_parser
|
45
|
+
OptionParser.new do |opts|
|
46
|
+
opts.banner = "Usage: #{opts.program_name} [options] [target-repo]"
|
47
|
+
|
48
|
+
add_information_options(opts)
|
49
|
+
add_installation_options(opts)
|
50
|
+
add_other_options(opts)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def add_information_options(opts)
|
55
|
+
opts.on_tail('-h', '--help', 'Show this message') do
|
56
|
+
print_help opts.help
|
57
|
+
end
|
58
|
+
|
59
|
+
opts.on_tail('-v', '--version', 'Show version') do
|
60
|
+
print_version(opts.program_name)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def add_installation_options(opts)
|
65
|
+
opts.on('-u', '--uninstall', 'Remove Overcommit hooks from a repository') do
|
66
|
+
@options[:action] = :uninstall
|
67
|
+
end
|
68
|
+
|
69
|
+
opts.on('-i', '--install', 'Install Overcommit hooks in a repository') do
|
70
|
+
@options[:action] = :install
|
71
|
+
end
|
72
|
+
|
73
|
+
opts.on('-f', '--force', 'Overwrite any previously installed hooks') do
|
74
|
+
@options[:force] = true
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def add_other_options(opts)
|
79
|
+
opts.on('-t', '--template-dir', 'Print location of template directory') do
|
80
|
+
@options[:action] = :template_dir
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
70
84
|
def install_or_uninstall
|
71
85
|
if Array(@options[:targets]).empty?
|
72
86
|
@options[:targets] = [Overcommit::Utils.repo_root].compact
|
@@ -3,8 +3,7 @@ module Overcommit
|
|
3
3
|
class Configuration
|
4
4
|
# Creates a configuration from the given hash.
|
5
5
|
def initialize(hash)
|
6
|
-
@hash = hash
|
7
|
-
validate
|
6
|
+
@hash = ConfigurationValidator.new.validate(hash)
|
8
7
|
end
|
9
8
|
|
10
9
|
def ==(other)
|
@@ -104,13 +103,6 @@ module Overcommit
|
|
104
103
|
true
|
105
104
|
end
|
106
105
|
|
107
|
-
# Validates the configuration for any invalid options, normalizing it where
|
108
|
-
# possible.
|
109
|
-
def validate
|
110
|
-
@hash = convert_nils_to_empty_hashes(@hash)
|
111
|
-
ensure_hook_type_sections_exist(@hash)
|
112
|
-
end
|
113
|
-
|
114
106
|
def smart_merge(parent, child)
|
115
107
|
parent.merge(child) do |_key, old, new|
|
116
108
|
case old
|
@@ -123,25 +115,5 @@ module Overcommit
|
|
123
115
|
end
|
124
116
|
end
|
125
117
|
end
|
126
|
-
|
127
|
-
def ensure_hook_type_sections_exist(hash)
|
128
|
-
Overcommit::Utils.supported_hook_type_classes.each do |hook_type|
|
129
|
-
hash[hook_type] ||= {}
|
130
|
-
hash[hook_type]['ALL'] ||= {}
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
def convert_nils_to_empty_hashes(hash)
|
135
|
-
hash.inject({}) do |h, (key, value)|
|
136
|
-
h[key] =
|
137
|
-
case value
|
138
|
-
when nil then {}
|
139
|
-
when Hash then convert_nils_to_empty_hashes(value)
|
140
|
-
else
|
141
|
-
value
|
142
|
-
end
|
143
|
-
h
|
144
|
-
end
|
145
|
-
end
|
146
118
|
end
|
147
119
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Overcommit
|
2
|
+
# Validates and normalizes a configuration.
|
3
|
+
class ConfigurationValidator
|
4
|
+
# Validates hash for any invalid options, normalizing where possible.
|
5
|
+
def validate(hash)
|
6
|
+
hash = convert_nils_to_empty_hashes(hash)
|
7
|
+
ensure_hook_type_sections_exist(hash)
|
8
|
+
|
9
|
+
hash
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
# Ensures that keys for all supported hook types exist (PreCommit,
|
15
|
+
# CommitMsg, etc.)
|
16
|
+
def ensure_hook_type_sections_exist(hash)
|
17
|
+
Overcommit::Utils.supported_hook_type_classes.each do |hook_type|
|
18
|
+
hash[hook_type] ||= {}
|
19
|
+
hash[hook_type]['ALL'] ||= {}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Normalizes `nil` values to empty hashes.
|
24
|
+
#
|
25
|
+
# This is useful for when we want to merge two configuration hashes
|
26
|
+
# together, since it's easier to merge two hashes than to have to check if
|
27
|
+
# one of the values is nil.
|
28
|
+
def convert_nils_to_empty_hashes(hash)
|
29
|
+
hash.inject({}) do |h, (key, value)|
|
30
|
+
h[key] =
|
31
|
+
case value
|
32
|
+
when nil then {}
|
33
|
+
when Hash then convert_nils_to_empty_hashes(value)
|
34
|
+
else
|
35
|
+
value
|
36
|
+
end
|
37
|
+
h
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
module Overcommit
|
2
|
+
# Provide a set of utilities for certain interactions with `git`.
|
3
|
+
module GitRepo
|
4
|
+
module_function
|
5
|
+
|
6
|
+
# Regular expression used to extract diff ranges from hunks of diff output.
|
7
|
+
DIFF_HUNK_REGEX = /
|
8
|
+
^@@\s
|
9
|
+
[^\s]+\s # Ignore old file range
|
10
|
+
\+(\d+)(?:,(\d+))? # Extract range of hunk containing start line and number of lines
|
11
|
+
\s@@.*$
|
12
|
+
/x
|
13
|
+
|
14
|
+
# Extract the set of modified lines from a given file.
|
15
|
+
#
|
16
|
+
# @param file_path [String]
|
17
|
+
# @param options [Hash]
|
18
|
+
# @return [Set] line numbers that have been modified in file
|
19
|
+
def extract_modified_lines(file_path, options)
|
20
|
+
lines = Set.new
|
21
|
+
|
22
|
+
flags = '--cached' if options[:staged]
|
23
|
+
|
24
|
+
`git diff --no-ext-diff -U0 #{flags} -- #{file_path}`.
|
25
|
+
scan(DIFF_HUNK_REGEX) do |start_line, lines_added|
|
26
|
+
|
27
|
+
lines_added = (lines_added || 1).to_i # When blank, one line was added
|
28
|
+
cur_line = start_line.to_i
|
29
|
+
|
30
|
+
lines_added.times do
|
31
|
+
lines.add cur_line
|
32
|
+
cur_line += 1
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
lines
|
37
|
+
end
|
38
|
+
|
39
|
+
# Returns the names of all files that have been modified from compared to
|
40
|
+
# HEAD.
|
41
|
+
#
|
42
|
+
# @param options [Hash]
|
43
|
+
# @return [Array<String>] list of absolute file paths
|
44
|
+
def modified_files(options)
|
45
|
+
flags = '--cached' if options[:staged]
|
46
|
+
|
47
|
+
`git diff --name-only -z --diff-filter=ACM --ignore-submodules=all #{flags}`.
|
48
|
+
split("\0").
|
49
|
+
map { |relative_file| File.expand_path(relative_file) }
|
50
|
+
end
|
51
|
+
|
52
|
+
# Returns whether the current git branch is empty (has no commits).
|
53
|
+
# @return [true,false]
|
54
|
+
def initial_commit?
|
55
|
+
!Overcommit::Utils.execute(%w[git rev-parse HEAD]).success?
|
56
|
+
end
|
57
|
+
|
58
|
+
# Store any relevant files that are present when repo is in the middle of a
|
59
|
+
# merge.
|
60
|
+
#
|
61
|
+
# Restored via [#restore_merge_state].
|
62
|
+
def store_merge_state
|
63
|
+
merge_head = `git rev-parse MERGE_HEAD 2> /dev/null`.chomp
|
64
|
+
|
65
|
+
# Store the merge state if we're in the middle of resolving a merge
|
66
|
+
# conflict. This is necessary since stashing removes the merge state.
|
67
|
+
if merge_head != 'MERGE_HEAD'
|
68
|
+
@merge_head = merge_head
|
69
|
+
|
70
|
+
merge_msg_file = File.expand_path('.git/MERGE_MSG', Overcommit::Utils.repo_root)
|
71
|
+
@merge_msg = File.open(merge_msg_file).read if File.exist?(merge_msg_file)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Store any relevant files that are present when repo is in the middle of a
|
76
|
+
# cherry-pick.
|
77
|
+
#
|
78
|
+
# Restored via [#restore_cherry_pick_state].
|
79
|
+
def store_cherry_pick_state
|
80
|
+
cherry_head = `git rev-parse CHERRY_PICK_HEAD 2> /dev/null`.chomp
|
81
|
+
|
82
|
+
# Store the merge state if we're in the middle of resolving a merge
|
83
|
+
# conflict. This is necessary since stashing removes the merge state.
|
84
|
+
if cherry_head != 'CHERRY_PICK_HEAD'
|
85
|
+
@cherry_head = cherry_head
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Restore any relevant files that were present when repo was in the middle
|
90
|
+
# of a merge.
|
91
|
+
def restore_merge_state
|
92
|
+
if @merge_head
|
93
|
+
FileUtils.touch(File.expand_path('.git/MERGE_MODE', Overcommit::Utils.repo_root))
|
94
|
+
|
95
|
+
File.open(File.expand_path('.git/MERGE_HEAD', Overcommit::Utils.repo_root), 'w') do |f|
|
96
|
+
f.write("#{@merge_head}\n")
|
97
|
+
end
|
98
|
+
@merge_head = nil
|
99
|
+
end
|
100
|
+
|
101
|
+
if @merge_msg
|
102
|
+
File.open(File.expand_path('.git/MERGE_MSG', Overcommit::Utils.repo_root), 'w') do |f|
|
103
|
+
f.write("#{@merge_msg}\n")
|
104
|
+
end
|
105
|
+
@merge_msg = nil
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# Restore any relevant files that were present when repo was in the middle
|
110
|
+
# of a cherry-pick.
|
111
|
+
def restore_cherry_pick_state
|
112
|
+
if @cherry_head
|
113
|
+
File.open(File.expand_path('.git/CHERRY_PICK_HEAD',
|
114
|
+
Overcommit::Utils.repo_root), 'w') do |f|
|
115
|
+
f.write("#{@cherry_head}\n")
|
116
|
+
end
|
117
|
+
@cherry_head = nil
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
data/lib/overcommit/hook/base.rb
CHANGED
@@ -70,10 +70,10 @@ module Overcommit::Hook
|
|
70
70
|
def applicable_file?(file)
|
71
71
|
includes = Array(@config['include']).map { |glob| convert_glob_to_absolute(glob) }
|
72
72
|
included = includes.empty? ||
|
73
|
-
includes.any? { |glob|
|
73
|
+
includes.any? { |glob| matches_path?(glob, file) }
|
74
74
|
|
75
75
|
excludes = Array(@config['exclude']).map { |glob| convert_glob_to_absolute(glob) }
|
76
|
-
excluded = excludes.any? { |glob|
|
76
|
+
excluded = excludes.any? { |glob| matches_path?(glob, file) }
|
77
77
|
|
78
78
|
included && !excluded
|
79
79
|
end
|
@@ -82,5 +82,16 @@ module Overcommit::Hook
|
|
82
82
|
repo_root = Overcommit::Utils.repo_root
|
83
83
|
File.join(repo_root, glob)
|
84
84
|
end
|
85
|
+
|
86
|
+
# Return whether a pattern matches the given path.
|
87
|
+
#
|
88
|
+
# @param pattern [String]
|
89
|
+
# @param path [String]
|
90
|
+
def matches_path?(pattern, path)
|
91
|
+
File.fnmatch?(pattern, path,
|
92
|
+
File::FNM_PATHNAME | # Wildcard doesn't match separator
|
93
|
+
File::FNM_DOTMATCH # Wildcards match dotfiles
|
94
|
+
)
|
95
|
+
end
|
85
96
|
end
|
86
97
|
end
|
@@ -17,9 +17,9 @@ module Overcommit::Hook::PreCommit
|
|
17
17
|
|
18
18
|
if optimized_images.any?
|
19
19
|
return :bad,
|
20
|
-
"The following images
|
21
|
-
|
22
|
-
"
|
20
|
+
"The following images are optimizable:\n#{optimized_images.join("\n")}" \
|
21
|
+
"\n\nOptimize them by running:\n" \
|
22
|
+
" image_optim #{optimized_images.join(' ')}"
|
23
23
|
end
|
24
24
|
|
25
25
|
:good
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Overcommit::Hook::PreCommit
|
2
2
|
# Check to see whether the schema file is in line with the migrations
|
3
3
|
class RailsSchemaUpToDate < Base
|
4
|
-
def run
|
4
|
+
def run # rubocop:disable CyclomaticComplexity
|
5
5
|
if migration_files.any? && schema_files.none?
|
6
6
|
return :bad, "It looks like you're adding a migration, but did not update the schema file"
|
7
7
|
elsif migration_files.none? && schema_files.any?
|
@@ -5,14 +5,15 @@ module Overcommit::HookContext
|
|
5
5
|
# Contains helpers related to contextual information used by pre-commit hooks.
|
6
6
|
#
|
7
7
|
# This includes staged files, which lines of those files have been modified,
|
8
|
-
# etc.
|
8
|
+
# etc. It is also responsible for saving/restoring the state of the repo so
|
9
|
+
# hooks only inspect staged changes.
|
9
10
|
class PreCommit < Base
|
10
11
|
# Stash unstaged contents of files so hooks don't see changes that aren't
|
11
12
|
# about to be committed.
|
12
13
|
def setup_environment
|
13
14
|
store_modified_times
|
14
|
-
store_merge_state
|
15
|
-
store_cherry_pick_state
|
15
|
+
Overcommit::GitRepo.store_merge_state
|
16
|
+
Overcommit::GitRepo.store_cherry_pick_state
|
16
17
|
|
17
18
|
if !initial_commit? && any_changes?
|
18
19
|
@changes_stashed = true
|
@@ -33,28 +34,25 @@ module Overcommit::HookContext
|
|
33
34
|
end
|
34
35
|
|
35
36
|
if @changes_stashed
|
36
|
-
`git stash
|
37
|
+
`git stash pop --index --quiet`
|
37
38
|
end
|
38
39
|
|
39
|
-
restore_merge_state
|
40
|
-
restore_cherry_pick_state
|
40
|
+
Overcommit::GitRepo.restore_merge_state
|
41
|
+
Overcommit::GitRepo.restore_cherry_pick_state
|
41
42
|
restore_modified_times
|
42
43
|
end
|
43
44
|
|
44
45
|
# Get a list of added, copied, or modified files that have been staged.
|
45
46
|
# Renames and deletions are ignored, since there should be nothing to check.
|
46
47
|
def modified_files
|
47
|
-
@modified_files ||=
|
48
|
-
`git diff --cached --name-only -z --diff-filter=ACM --ignore-submodules=all`.
|
49
|
-
split("\0").
|
50
|
-
map { |relative_file| File.expand_path(relative_file) }
|
48
|
+
@modified_files ||= Overcommit::GitRepo.modified_files(:staged => true)
|
51
49
|
end
|
52
50
|
|
53
51
|
# Returns the set of line numbers corresponding to the lines that were
|
54
52
|
# changed in a specified file.
|
55
53
|
def modified_lines(file)
|
56
54
|
@modified_lines ||= {}
|
57
|
-
@modified_lines[file] ||= extract_modified_lines(file)
|
55
|
+
@modified_lines[file] ||= Overcommit::GitRepo.extract_modified_lines(file, :staged => true)
|
58
56
|
end
|
59
57
|
|
60
58
|
private
|
@@ -72,85 +70,14 @@ module Overcommit::HookContext
|
|
72
70
|
# Returns whether the current git branch is empty (has no commits).
|
73
71
|
def initial_commit?
|
74
72
|
return @initial_commit unless @initial_commit.nil?
|
75
|
-
@initial_commit =
|
76
|
-
end
|
77
|
-
|
78
|
-
DIFF_HUNK_REGEX = /
|
79
|
-
^@@\s
|
80
|
-
[^\s]+\s # Ignore old file range
|
81
|
-
\+(\d+)(?:,(\d+))? # Extract range of hunk containing start line and number of lines
|
82
|
-
\s@@.*$
|
83
|
-
/x
|
84
|
-
|
85
|
-
def extract_modified_lines(staged_file)
|
86
|
-
lines = Set.new
|
87
|
-
|
88
|
-
`git diff --no-ext-diff --cached -U0 -- #{staged_file}`.
|
89
|
-
scan(DIFF_HUNK_REGEX) do |start_line, lines_added|
|
90
|
-
|
91
|
-
lines_added = (lines_added || 1).to_i # When blank, one line was added
|
92
|
-
cur_line = start_line.to_i
|
93
|
-
|
94
|
-
lines_added.times do
|
95
|
-
lines.add cur_line
|
96
|
-
cur_line += 1
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
lines
|
101
|
-
end
|
102
|
-
|
103
|
-
def store_merge_state
|
104
|
-
merge_head = `git rev-parse MERGE_HEAD 2> /dev/null`.chomp
|
105
|
-
|
106
|
-
# Store the merge state if we're in the middle of resolving a merge
|
107
|
-
# conflict. This is necessary since stashing removes the merge state.
|
108
|
-
if merge_head != 'MERGE_HEAD'
|
109
|
-
@merge_head = merge_head
|
110
|
-
|
111
|
-
merge_msg_file = File.expand_path('.git/MERGE_MSG', Overcommit::Utils.repo_root)
|
112
|
-
@merge_msg = File.open(merge_msg_file).read if File.exist?(merge_msg_file)
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
def store_cherry_pick_state
|
117
|
-
cherry_head = `git rev-parse CHERRY_PICK_HEAD 2> /dev/null`.chomp
|
118
|
-
|
119
|
-
# Store the merge state if we're in the middle of resolving a merge
|
120
|
-
# conflict. This is necessary since stashing removes the merge state.
|
121
|
-
if cherry_head != 'CHERRY_PICK_HEAD'
|
122
|
-
@cherry_head = cherry_head
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
def restore_merge_state
|
127
|
-
if @merge_head
|
128
|
-
FileUtils.touch(File.expand_path('.git/MERGE_MODE', Overcommit::Utils.repo_root))
|
129
|
-
|
130
|
-
File.open(File.expand_path('.git/MERGE_HEAD', Overcommit::Utils.repo_root), 'w') do |f|
|
131
|
-
f.write("#{@merge_head}\n")
|
132
|
-
end
|
133
|
-
@merge_head = nil
|
134
|
-
end
|
135
|
-
|
136
|
-
if @merge_msg
|
137
|
-
File.open(File.expand_path('.git/MERGE_MSG', Overcommit::Utils.repo_root), 'w') do |f|
|
138
|
-
f.write("#{@merge_msg}\n")
|
139
|
-
end
|
140
|
-
@merge_msg = nil
|
141
|
-
end
|
142
|
-
end
|
143
|
-
|
144
|
-
def restore_cherry_pick_state
|
145
|
-
if @cherry_head
|
146
|
-
File.open(File.expand_path('.git/CHERRY_PICK_HEAD',
|
147
|
-
Overcommit::Utils.repo_root), 'w') do |f|
|
148
|
-
f.write("#{@cherry_head}\n")
|
149
|
-
end
|
150
|
-
@cherry_head = nil
|
151
|
-
end
|
73
|
+
@initial_commit = Overcommit::GitRepo.initial_commit?
|
152
74
|
end
|
153
75
|
|
76
|
+
# Stores the modification times for all modified files to make it appear like
|
77
|
+
# they never changed.
|
78
|
+
#
|
79
|
+
# This prevents (some) editors from complaining about files changing when we
|
80
|
+
# stash changes before running the hooks.
|
154
81
|
def store_modified_times
|
155
82
|
@modified_times = {}
|
156
83
|
|
@@ -159,11 +86,8 @@ module Overcommit::HookContext
|
|
159
86
|
end
|
160
87
|
end
|
161
88
|
|
162
|
-
#
|
163
|
-
# they never changed.
|
164
|
-
#
|
165
|
-
# This prevents editors from complaining about files changing when we stash
|
166
|
-
# changes before running the hooks.
|
89
|
+
# Restores the file modification times for all modified files to make it
|
90
|
+
# appear like they never changed.
|
167
91
|
def restore_modified_times
|
168
92
|
modified_files.each do |file|
|
169
93
|
time = @modified_times[file]
|
@@ -1,5 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
module Overcommit
|
4
2
|
# Responsible for loading the hooks the repository has configured and running
|
5
3
|
# them, collecting and displaying the results.
|
@@ -8,11 +6,12 @@ module Overcommit
|
|
8
6
|
# @param logger [Overcommit::Logger]
|
9
7
|
# @param context [Overcommit::HookContext]
|
10
8
|
# @param input [Overcommit::UserInput]
|
11
|
-
def initialize(config, logger, context, input)
|
9
|
+
def initialize(config, logger, context, input, printer)
|
12
10
|
@config = config
|
13
11
|
@log = logger
|
14
12
|
@context = context
|
15
13
|
@input = input
|
14
|
+
@printer = printer
|
16
15
|
@hooks = []
|
17
16
|
end
|
18
17
|
|
@@ -33,39 +32,28 @@ module Overcommit
|
|
33
32
|
|
34
33
|
def run_hooks
|
35
34
|
if @hooks.any? { |hook| hook.run? || hook.skip? }
|
36
|
-
|
35
|
+
@printer.start_run
|
37
36
|
|
38
37
|
interrupted = false
|
38
|
+
run_failed = false
|
39
39
|
|
40
|
-
|
40
|
+
@hooks.each do |hook|
|
41
41
|
hook_status = run_hook(hook)
|
42
42
|
|
43
|
+
run_failed = true if hook_status == :bad
|
44
|
+
|
43
45
|
if hook_status == :interrupted
|
44
46
|
# Stop running any more hooks and assume a bad result
|
45
47
|
interrupted = true
|
46
|
-
break
|
48
|
+
break
|
47
49
|
end
|
48
|
-
|
49
|
-
hook_status
|
50
|
-
end.compact
|
51
|
-
|
52
|
-
log.log # Newline
|
53
|
-
|
54
|
-
run_failed = statuses.include?(:bad)
|
55
|
-
|
56
|
-
if interrupted
|
57
|
-
log.warning '⚠ Hook run interrupted by user'
|
58
|
-
elsif run_failed
|
59
|
-
log.error "✗ One or more #{hook_script_name} hooks failed"
|
60
|
-
else
|
61
|
-
log.success "✓ All #{hook_script_name} hooks passed"
|
62
50
|
end
|
63
51
|
|
64
|
-
|
52
|
+
@printer.end_run(interrupted, run_failed)
|
65
53
|
|
66
|
-
!run_failed
|
54
|
+
!(run_failed || interrupted)
|
67
55
|
else
|
68
|
-
|
56
|
+
@printer.nothing_to_run
|
69
57
|
true # Run was successful
|
70
58
|
end
|
71
59
|
end
|
@@ -73,9 +61,7 @@ module Overcommit
|
|
73
61
|
def run_hook(hook)
|
74
62
|
return if should_skip?(hook)
|
75
63
|
|
76
|
-
|
77
|
-
print_header(hook)
|
78
|
-
end
|
64
|
+
@printer.start_hook(hook)
|
79
65
|
|
80
66
|
begin
|
81
67
|
# Disable the interrupt handler during individual hook run so that
|
@@ -93,30 +79,19 @@ module Overcommit
|
|
93
79
|
InterruptHandler.enable!
|
94
80
|
end
|
95
81
|
|
96
|
-
|
97
|
-
# user knows what failed
|
98
|
-
if hook.quiet? && status != :good
|
99
|
-
print_header(hook)
|
100
|
-
end
|
101
|
-
|
102
|
-
print_result(hook, status, output)
|
82
|
+
@printer.end_hook(hook, status, output)
|
103
83
|
|
104
84
|
status
|
105
85
|
end
|
106
86
|
|
107
|
-
def print_header(hook)
|
108
|
-
log.partial hook.description
|
109
|
-
log.partial '.' * (70 - hook.description.length)
|
110
|
-
end
|
111
|
-
|
112
87
|
def should_skip?(hook)
|
113
88
|
return true unless hook.enabled?
|
114
89
|
|
115
90
|
if hook.skip?
|
116
91
|
if hook.required?
|
117
|
-
|
92
|
+
@printer.required_hook_not_skipped
|
118
93
|
else
|
119
|
-
|
94
|
+
@printer.hook_skipped
|
120
95
|
return true
|
121
96
|
end
|
122
97
|
end
|
@@ -124,26 +99,6 @@ module Overcommit
|
|
124
99
|
!hook.run?
|
125
100
|
end
|
126
101
|
|
127
|
-
def print_result(hook, status, output)
|
128
|
-
case status
|
129
|
-
when :good
|
130
|
-
log.success 'OK' unless hook.quiet?
|
131
|
-
when :warn
|
132
|
-
log.warning 'WARNING'
|
133
|
-
print_report(output, :bold_warning)
|
134
|
-
when :bad
|
135
|
-
log.error 'FAILED'
|
136
|
-
print_report(output, :bold_error)
|
137
|
-
when :interrupted
|
138
|
-
log.error 'INTERRUPTED'
|
139
|
-
print_report(output, :bold_error)
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
def print_report(output, format = :log)
|
144
|
-
log.send(format, output) unless output.nil? || output.empty?
|
145
|
-
end
|
146
|
-
|
147
102
|
def load_hooks
|
148
103
|
require "overcommit/hook/#{@context.hook_type_name}/base"
|
149
104
|
|
@@ -152,9 +107,5 @@ module Overcommit
|
|
152
107
|
# Load plugin hooks after so they can subclass existing hooks
|
153
108
|
@hooks += HookLoader::PluginHookLoader.new(@config, @context, @log, @input).load_hooks
|
154
109
|
end
|
155
|
-
|
156
|
-
def hook_script_name
|
157
|
-
@context.hook_script_name
|
158
|
-
end
|
159
110
|
end
|
160
111
|
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Overcommit
|
4
|
+
# Provide a set of callbacks which can be executed as events occur during the
|
5
|
+
# course of {HookRunner#run}.
|
6
|
+
class Printer
|
7
|
+
attr_reader :log
|
8
|
+
|
9
|
+
def initialize(logger, context)
|
10
|
+
@log = logger
|
11
|
+
@context = context
|
12
|
+
end
|
13
|
+
|
14
|
+
# Executed at the very beginning of running the collection of hooks.
|
15
|
+
def start_run
|
16
|
+
log.bold "Running #{hook_script_name} hooks"
|
17
|
+
end
|
18
|
+
|
19
|
+
def nothing_to_run
|
20
|
+
log.success "✓ No applicable #{hook_script_name} hooks to run"
|
21
|
+
end
|
22
|
+
|
23
|
+
# Executed at the very end of running the collection of hooks.
|
24
|
+
def end_run(run_failed, interrupted)
|
25
|
+
log.log # Newline
|
26
|
+
|
27
|
+
if interrupted
|
28
|
+
log.warning '⚠ Hook run interrupted by user'
|
29
|
+
elsif run_failed
|
30
|
+
log.error "✗ One or more #{hook_script_name} hooks failed"
|
31
|
+
else
|
32
|
+
log.success "✓ All #{hook_script_name} hooks passed"
|
33
|
+
end
|
34
|
+
|
35
|
+
log.log # Newline
|
36
|
+
end
|
37
|
+
|
38
|
+
# Executed at the start of an individual hook run.
|
39
|
+
def start_hook(hook)
|
40
|
+
unless hook.quiet?
|
41
|
+
print_header(hook)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def hook_skipped(hook)
|
46
|
+
log.warning "Skipping #{hook.name}"
|
47
|
+
end
|
48
|
+
|
49
|
+
def required_hook_not_skipped(hook)
|
50
|
+
log.warning "Cannot skip #{hook.name} since it is required"
|
51
|
+
end
|
52
|
+
|
53
|
+
# Executed at the end of an individual hook run.
|
54
|
+
def end_hook(hook, status, output)
|
55
|
+
# Want to print the header for quiet hooks only if the result wasn't good
|
56
|
+
# so that the user knows what failed
|
57
|
+
print_header(hook) if hook.quiet? && status != :good
|
58
|
+
|
59
|
+
print_result(hook, status, output)
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def print_header(hook)
|
65
|
+
log.partial hook.description
|
66
|
+
log.partial '.' * (70 - hook.description.length)
|
67
|
+
end
|
68
|
+
|
69
|
+
def print_result(hook, status, output)
|
70
|
+
case status
|
71
|
+
when :good
|
72
|
+
log.success 'OK' unless hook.quiet?
|
73
|
+
when :warn
|
74
|
+
log.warning 'WARNING'
|
75
|
+
print_report(output, :bold_warning)
|
76
|
+
when :bad
|
77
|
+
log.error 'FAILED'
|
78
|
+
print_report(output, :bold_error)
|
79
|
+
when :interrupted
|
80
|
+
log.error 'INTERRUPTED'
|
81
|
+
print_report(output, :bold_error)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def print_report(output, format = :log)
|
86
|
+
log.send(format, output) unless output.nil? || output.empty?
|
87
|
+
end
|
88
|
+
|
89
|
+
def run_interrupted
|
90
|
+
log.warning '⚠ Hook run interrupted by user'
|
91
|
+
end
|
92
|
+
|
93
|
+
def run_failed
|
94
|
+
log.error "✗ One or more #{hook_script_name} hooks failed"
|
95
|
+
end
|
96
|
+
|
97
|
+
def run_succeeded
|
98
|
+
log.success "✓ All #{hook_script_name} hooks passed"
|
99
|
+
end
|
100
|
+
|
101
|
+
def hook_script_name
|
102
|
+
@context.hook_script_name
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
data/lib/overcommit/version.rb
CHANGED
@@ -65,7 +65,8 @@ begin
|
|
65
65
|
|
66
66
|
input = Overcommit::UserInput.new(STDIN)
|
67
67
|
|
68
|
-
|
68
|
+
printer = Overcommit::Printer.new(logger, context)
|
69
|
+
runner = Overcommit::HookRunner.new(config, logger, context, input, printer)
|
69
70
|
|
70
71
|
status = runner.run
|
71
72
|
|
@@ -65,7 +65,8 @@ begin
|
|
65
65
|
|
66
66
|
input = Overcommit::UserInput.new(STDIN)
|
67
67
|
|
68
|
-
|
68
|
+
printer = Overcommit::Printer.new(logger, context)
|
69
|
+
runner = Overcommit::HookRunner.new(config, logger, context, input, printer)
|
69
70
|
|
70
71
|
status = runner.run
|
71
72
|
|
@@ -65,7 +65,8 @@ begin
|
|
65
65
|
|
66
66
|
input = Overcommit::UserInput.new(STDIN)
|
67
67
|
|
68
|
-
|
68
|
+
printer = Overcommit::Printer.new(logger, context)
|
69
|
+
runner = Overcommit::HookRunner.new(config, logger, context, input, printer)
|
69
70
|
|
70
71
|
status = runner.run
|
71
72
|
|
@@ -65,7 +65,8 @@ begin
|
|
65
65
|
|
66
66
|
input = Overcommit::UserInput.new(STDIN)
|
67
67
|
|
68
|
-
|
68
|
+
printer = Overcommit::Printer.new(logger, context)
|
69
|
+
runner = Overcommit::HookRunner.new(config, logger, context, input, printer)
|
69
70
|
|
70
71
|
status = runner.run
|
71
72
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: overcommit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.14.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Causes Engineering
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-07-
|
12
|
+
date: 2014-07-14 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: childprocess
|
@@ -26,19 +26,19 @@ dependencies:
|
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
version: 0.5.1
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
|
-
name:
|
29
|
+
name: image_optim
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
31
31
|
requirements:
|
32
|
-
- -
|
32
|
+
- - ~>
|
33
33
|
- !ruby/object:Gem::Version
|
34
|
-
version:
|
35
|
-
type: :
|
34
|
+
version: 0.13.0
|
35
|
+
type: :development
|
36
36
|
prerelease: false
|
37
37
|
version_requirements: !ruby/object:Gem::Requirement
|
38
38
|
requirements:
|
39
|
-
- -
|
39
|
+
- - ~>
|
40
40
|
- !ruby/object:Gem::Version
|
41
|
-
version:
|
41
|
+
version: 0.13.0
|
42
42
|
- !ruby/object:Gem::Dependency
|
43
43
|
name: rspec
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|
@@ -54,19 +54,19 @@ dependencies:
|
|
54
54
|
- !ruby/object:Gem::Version
|
55
55
|
version: '3.0'
|
56
56
|
- !ruby/object:Gem::Dependency
|
57
|
-
name:
|
57
|
+
name: rubocop
|
58
58
|
requirement: !ruby/object:Gem::Requirement
|
59
59
|
requirements:
|
60
|
-
- -
|
60
|
+
- - '='
|
61
61
|
- !ruby/object:Gem::Version
|
62
|
-
version: 0.
|
62
|
+
version: 0.24.1
|
63
63
|
type: :development
|
64
64
|
prerelease: false
|
65
65
|
version_requirements: !ruby/object:Gem::Requirement
|
66
66
|
requirements:
|
67
|
-
- -
|
67
|
+
- - '='
|
68
68
|
- !ruby/object:Gem::Version
|
69
|
-
version: 0.
|
69
|
+
version: 0.24.1
|
70
70
|
description: Utility to install, configure, and extend Git hooks
|
71
71
|
email:
|
72
72
|
- eng@causes.com
|
@@ -126,6 +126,8 @@ files:
|
|
126
126
|
- lib/overcommit/hook/pre_commit/base.rb
|
127
127
|
- lib/overcommit/hook/pre_commit/json_syntax.rb
|
128
128
|
- lib/overcommit/hook_signer.rb
|
129
|
+
- lib/overcommit/git_repo.rb
|
130
|
+
- lib/overcommit/configuration_validator.rb
|
129
131
|
- lib/overcommit/hook_context/pre_commit.rb
|
130
132
|
- lib/overcommit/hook_context/commit_msg.rb
|
131
133
|
- lib/overcommit/hook_context/base.rb
|
@@ -138,6 +140,7 @@ files:
|
|
138
140
|
- lib/overcommit/hook_loader/base.rb
|
139
141
|
- lib/overcommit/exceptions.rb
|
140
142
|
- lib/overcommit/configuration.rb
|
143
|
+
- lib/overcommit/printer.rb
|
141
144
|
- lib/overcommit/logger.rb
|
142
145
|
- lib/overcommit/cli.rb
|
143
146
|
- libexec/index-tags
|
@@ -159,7 +162,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
159
162
|
requirements:
|
160
163
|
- - '>='
|
161
164
|
- !ruby/object:Gem::Version
|
162
|
-
version: 1.
|
165
|
+
version: 1.9.3
|
163
166
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
164
167
|
requirements:
|
165
168
|
- - '>='
|