overcommit 0.1.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 +7 -0
- data/bin/hooks/commit-msg +8 -0
- data/bin/hooks/post-checkout +8 -0
- data/bin/hooks/post-merge +23 -0
- data/bin/hooks/pre-commit +8 -0
- data/bin/hooks/prepare-commit-msg +160 -0
- data/bin/overcommit +11 -0
- data/bin/run-hook +8 -0
- data/bin/scripts/csslint-rhino.js +9080 -0
- data/bin/scripts/gerrit-change-id +174 -0
- data/bin/scripts/index-tags +19 -0
- data/bin/scripts/jshint.js +5921 -0
- data/bin/scripts/jshint_runner.js +48 -0
- data/config/templates.yml +12 -0
- data/lib/overcommit.rb +8 -0
- data/lib/overcommit/cli.rb +95 -0
- data/lib/overcommit/configuration.rb +58 -0
- data/lib/overcommit/console_methods.rb +23 -0
- data/lib/overcommit/git_hook.rb +50 -0
- data/lib/overcommit/hook_specific_check.rb +81 -0
- data/lib/overcommit/hooks/commit_msg.rb +7 -0
- data/lib/overcommit/hooks/pre_commit.rb +9 -0
- data/lib/overcommit/installer.rb +59 -0
- data/lib/overcommit/plugins/commit_msg/change_id.rb +14 -0
- data/lib/overcommit/plugins/commit_msg/release_note.rb +14 -0
- data/lib/overcommit/plugins/commit_msg/russian_novel.rb +16 -0
- data/lib/overcommit/plugins/commit_msg/text_width.rb +20 -0
- data/lib/overcommit/plugins/commit_msg/trailing_period.rb +13 -0
- data/lib/overcommit/plugins/pre_commit/author_name.rb +16 -0
- data/lib/overcommit/plugins/pre_commit/causes_email.rb +15 -0
- data/lib/overcommit/plugins/pre_commit/css_linter.rb +17 -0
- data/lib/overcommit/plugins/pre_commit/erb_syntax.rb +21 -0
- data/lib/overcommit/plugins/pre_commit/haml_syntax.rb +23 -0
- data/lib/overcommit/plugins/pre_commit/js_console_log.rb +16 -0
- data/lib/overcommit/plugins/pre_commit/js_syntax.rb +18 -0
- data/lib/overcommit/plugins/pre_commit/restricted_paths.rb +15 -0
- data/lib/overcommit/plugins/pre_commit/ruby_syntax.rb +19 -0
- data/lib/overcommit/plugins/pre_commit/scss_lint.rb +20 -0
- data/lib/overcommit/plugins/pre_commit/test_history.rb +58 -0
- data/lib/overcommit/plugins/pre_commit/whitespace.rb +19 -0
- data/lib/overcommit/plugins/pre_commit/yaml_syntax.rb +22 -0
- data/lib/overcommit/reporter.rb +80 -0
- data/lib/overcommit/utils.rb +60 -0
- data/lib/overcommit/version.rb +3 -0
- metadata +88 -0
@@ -0,0 +1,14 @@
|
|
1
|
+
module Overcommit::GitHook
|
2
|
+
class ChangeID < HookSpecificCheck
|
3
|
+
include HookRegistry
|
4
|
+
|
5
|
+
stealth! # Not really a 'check', but we need it to run
|
6
|
+
|
7
|
+
SCRIPT_LOCATION = Overcommit::Utils.script_path 'gerrit-change-id'
|
8
|
+
|
9
|
+
def run_check
|
10
|
+
system `#{SCRIPT_LOCATION} #{@arguments.join(' ')}`
|
11
|
+
:good
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Overcommit::GitHook
|
2
|
+
class ReleaseNote < HookSpecificCheck
|
3
|
+
include HookRegistry
|
4
|
+
|
5
|
+
EMPTY_RELEASE_NOTE = /^release notes?\s*[:.]?\n{2,}/im
|
6
|
+
def run_check
|
7
|
+
if user_commit_message.join =~ EMPTY_RELEASE_NOTE
|
8
|
+
return :warn, 'Empty release note found, either add one or remove it'
|
9
|
+
end
|
10
|
+
|
11
|
+
:good
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Overcommit::GitHook
|
2
|
+
class RussianNovel < HookSpecificCheck
|
3
|
+
include HookRegistry
|
4
|
+
|
5
|
+
stealth!
|
6
|
+
|
7
|
+
RUSSIAN_NOVEL_LENGTH = 30
|
8
|
+
def run_check
|
9
|
+
if user_commit_message.length > RUSSIAN_NOVEL_LENGTH
|
10
|
+
return :warn, 'You seem to have authored a Russian novel; congratulations!'
|
11
|
+
end
|
12
|
+
|
13
|
+
:good
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Overcommit::GitHook
|
2
|
+
class TextWidth < HookSpecificCheck
|
3
|
+
include HookRegistry
|
4
|
+
|
5
|
+
def run_check
|
6
|
+
if user_commit_message.first.size > 60
|
7
|
+
return :warn, 'Please keep the subject < ~60 characters'
|
8
|
+
end
|
9
|
+
|
10
|
+
user_commit_message.each do |line|
|
11
|
+
chomped = line.chomp
|
12
|
+
if chomped.size > 72
|
13
|
+
return :warn, "> 72 characters, please hard wrap: '#{chomped}'"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
:good
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Overcommit::GitHook
|
2
|
+
class TrailingPeriod < HookSpecificCheck
|
3
|
+
include HookRegistry
|
4
|
+
|
5
|
+
def run_check
|
6
|
+
if commit_message[0].rstrip.end_with?('.')
|
7
|
+
return :warn, 'Please omit trailing period from commit message subject.'
|
8
|
+
end
|
9
|
+
|
10
|
+
:good
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Overcommit::GitHook
|
2
|
+
class AuthorName < HookSpecificCheck
|
3
|
+
include HookRegistry
|
4
|
+
|
5
|
+
def run_check
|
6
|
+
name = `git config --get user.name`.chomp
|
7
|
+
unless name.split(' ').count >= 2
|
8
|
+
return :bad, "Author must have at least first and last name; " <<
|
9
|
+
"was: '#{name}'.\n Set your name with " <<
|
10
|
+
"`git config --global user.name 'Your Name'`"
|
11
|
+
end
|
12
|
+
|
13
|
+
:good
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Overcommit::GitHook
|
2
|
+
class CausesEmail < HookSpecificCheck
|
3
|
+
include HookRegistry
|
4
|
+
|
5
|
+
def run_check
|
6
|
+
email = `git config --get user.email`.chomp
|
7
|
+
unless email =~ /@causes\.com$/
|
8
|
+
return :bad, "Author must use a causes.com address; was '#{email}'.\n" <<
|
9
|
+
"Set user with `git config --global user.email YOUR_EMAIL@causes.com`"
|
10
|
+
end
|
11
|
+
|
12
|
+
:good
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Overcommit::GitHook
|
2
|
+
class CssLinter < HookSpecificCheck
|
3
|
+
include HookRegistry
|
4
|
+
file_type :css
|
5
|
+
|
6
|
+
CSS_LINTER_PATH = Overcommit::Utils.script_path 'csslint-rhino.js'
|
7
|
+
|
8
|
+
def run_check
|
9
|
+
return :warn, "Rhino is not installed" unless in_path? 'rhino'
|
10
|
+
|
11
|
+
paths = staged.join(' ')
|
12
|
+
output = `rhino #{CSS_LINTER_PATH} --quiet --format=compact #{paths} | grep 'Error - '`
|
13
|
+
|
14
|
+
return (output !~ /Error - (?!Unknown @ rule)/ ? :good : :bad), output
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'erb'
|
2
|
+
|
3
|
+
module Overcommit::GitHook
|
4
|
+
class ErbSyntax < HookSpecificCheck
|
5
|
+
include HookRegistry
|
6
|
+
file_type :erb
|
7
|
+
ERB_CHECKER = 'bin/check-rails-erb'
|
8
|
+
|
9
|
+
def skip?
|
10
|
+
return 'Bundler is not installed' unless in_path? 'bundle'
|
11
|
+
unless File.executable? ERB_CHECKER
|
12
|
+
return "Can't find/execute #{ERB_CHECKER}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def run_check
|
17
|
+
output = `bundle exec #{ERB_CHECKER} #{staged.join(' ')}`
|
18
|
+
return (output !~ /: compile error$/ ? :good : :bad), output
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Overcommit::GitHook
|
2
|
+
class HamlSyntax < HookSpecificCheck
|
3
|
+
include HookRegistry
|
4
|
+
file_type :haml
|
5
|
+
|
6
|
+
def run_check
|
7
|
+
begin
|
8
|
+
require 'haml'
|
9
|
+
rescue LoadError
|
10
|
+
return :warn, "'haml' gem not installed -- run `gem install haml`"
|
11
|
+
end
|
12
|
+
|
13
|
+
staged.each do |path|
|
14
|
+
begin
|
15
|
+
Haml::Engine.new(File.read(path), :check_syntax => true)
|
16
|
+
rescue Haml::Error => e
|
17
|
+
return :bad, e.message
|
18
|
+
end
|
19
|
+
end
|
20
|
+
return :good, nil
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Overcommit::GitHook
|
2
|
+
class JSConsoleLog < HookSpecificCheck
|
3
|
+
include HookRegistry
|
4
|
+
file_type :js
|
5
|
+
|
6
|
+
# https://www.pivotaltracker.com/story/show/18119495
|
7
|
+
def run_check
|
8
|
+
paths = staged.join(' ')
|
9
|
+
output = `grep -n -e 'console\\.log' #{paths}`.split("\n").reject do |line|
|
10
|
+
/^\d+:\s*\/\// =~ line || # Skip comments
|
11
|
+
/ALLOW_CONSOLE_LOG/ =~ line # and lines with ALLOW_CONSOLE_LOG
|
12
|
+
end.join("\n")
|
13
|
+
return (output.empty? ? :good : :bad), output
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Overcommit::GitHook
|
2
|
+
class JSSyntax < HookSpecificCheck
|
3
|
+
include HookRegistry
|
4
|
+
file_type :js
|
5
|
+
|
6
|
+
JS_HINT_PATH = Overcommit::Utils.script_path 'jshint.js'
|
7
|
+
JS_HINT_RUNNER_PATH = Overcommit::Utils.script_path 'jshint_runner.js'
|
8
|
+
|
9
|
+
def run_check
|
10
|
+
return :warn, "Rhino is not installed" unless in_path? 'rhino'
|
11
|
+
|
12
|
+
paths = staged.join(' ')
|
13
|
+
|
14
|
+
output = `rhino -strict -f #{JS_HINT_PATH} #{JS_HINT_RUNNER_PATH} #{paths} 2>&1 | grep -v warning | grep -v -e '^js: '`
|
15
|
+
return (output !~ /^ERROR/ ? :good : :bad), output
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Overcommit::GitHook
|
2
|
+
class RestrictedPaths < HookSpecificCheck
|
3
|
+
include HookRegistry
|
4
|
+
RESTRICTED_PATHS = %w[vendor]
|
5
|
+
|
6
|
+
def run_check
|
7
|
+
RESTRICTED_PATHS.each do |path|
|
8
|
+
if !system("git diff --cached --quiet -- #{path}")
|
9
|
+
return :stop, "changes staged under #{path}"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
return :good
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Overcommit::GitHook
|
2
|
+
class RubySyntax < HookSpecificCheck
|
3
|
+
include HookRegistry
|
4
|
+
file_type :rb
|
5
|
+
|
6
|
+
def run_check
|
7
|
+
clean = true
|
8
|
+
output = []
|
9
|
+
staged.each do |staged|
|
10
|
+
syntax = `ruby -c #{staged} 2>&1`
|
11
|
+
unless $?.success?
|
12
|
+
output += syntax.lines.to_a
|
13
|
+
clean = false
|
14
|
+
end
|
15
|
+
end
|
16
|
+
return (clean ? :good : :bad), output
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Overcommit::GitHook
|
2
|
+
class ScssLint < HookSpecificCheck
|
3
|
+
include HookRegistry
|
4
|
+
file_type :scss
|
5
|
+
|
6
|
+
def run_check
|
7
|
+
begin
|
8
|
+
require 'scss_lint'
|
9
|
+
rescue LoadError
|
10
|
+
return :warn, 'scss-lint not installed -- run `gem install scss-lint`'
|
11
|
+
end
|
12
|
+
|
13
|
+
paths = staged.join(' ')
|
14
|
+
|
15
|
+
output = `scss-lint #{paths} 2>&1`
|
16
|
+
|
17
|
+
return (output.empty? ? :good : :bad), output
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Overcommit::GitHook
|
2
|
+
class TestHistory < HookSpecificCheck
|
3
|
+
include HookRegistry
|
4
|
+
|
5
|
+
def relevant_tests
|
6
|
+
@relevant_test ||=
|
7
|
+
`relevant-tests 2> /dev/null -- #{modified_files.join(' ')}`.
|
8
|
+
split("\n").map { |r| File.expand_path r }
|
9
|
+
end
|
10
|
+
|
11
|
+
def skip?
|
12
|
+
!FileTest.exist?('spec/support/record_results_formatter.rb')
|
13
|
+
end
|
14
|
+
|
15
|
+
TEST_RESULTS_FILE = '.spec-results'
|
16
|
+
def run_check
|
17
|
+
output = []
|
18
|
+
unless relevant_tests.any?
|
19
|
+
return :warn, 'No relevant tests for this change...write some?'
|
20
|
+
end
|
21
|
+
|
22
|
+
begin
|
23
|
+
good_tests = File.open(TEST_RESULTS_FILE, 'r').readlines.map do |spec_file|
|
24
|
+
File.expand_path spec_file.strip
|
25
|
+
end
|
26
|
+
rescue Errno::ENOENT
|
27
|
+
good_tests = []
|
28
|
+
end
|
29
|
+
|
30
|
+
unless good_tests.any?
|
31
|
+
return :bad,
|
32
|
+
'The relevant tests for this change have not yet been run using `specr`'
|
33
|
+
end
|
34
|
+
|
35
|
+
missed_tests = (relevant_tests - good_tests)
|
36
|
+
unless missed_tests.empty?
|
37
|
+
output << 'The following relevant tests have not been run recently:'
|
38
|
+
output << missed_tests.sort
|
39
|
+
return :bad, output
|
40
|
+
end
|
41
|
+
|
42
|
+
# Find files modified after the tests were run
|
43
|
+
test_time = File.mtime(TEST_RESULTS_FILE)
|
44
|
+
untested_files = modified_files.reject do |file|
|
45
|
+
File.mtime(file) < test_time
|
46
|
+
end
|
47
|
+
|
48
|
+
unless untested_files.empty?
|
49
|
+
output << 'The following files were modified after `specr` was run.'
|
50
|
+
output << '(their associated tests may be broken):'
|
51
|
+
output << untested_files.sort
|
52
|
+
return :bad, output
|
53
|
+
end
|
54
|
+
|
55
|
+
return :good
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Overcommit::GitHook
|
2
|
+
class Whitespace < HookSpecificCheck
|
3
|
+
include HookRegistry
|
4
|
+
|
5
|
+
def run_check
|
6
|
+
# Catches hard tabs
|
7
|
+
output = `grep -Inl "\t" #{staged.join(' ')}`
|
8
|
+
unless output.empty?
|
9
|
+
return :stop, "Don't use hard tabs:\n#{output}"
|
10
|
+
end
|
11
|
+
|
12
|
+
# Catches trailing whitespace, conflict markers etc
|
13
|
+
output = `git diff --check --cached`
|
14
|
+
return :stop, output unless $?.exitstatus.zero?
|
15
|
+
|
16
|
+
:good
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Overcommit::GitHook
|
4
|
+
class YamlSyntax < HookSpecificCheck
|
5
|
+
include HookRegistry
|
6
|
+
file_type :yml
|
7
|
+
|
8
|
+
def run_check
|
9
|
+
clean = true
|
10
|
+
output = []
|
11
|
+
staged.each do |path|
|
12
|
+
begin
|
13
|
+
YAML.load_file(path)
|
14
|
+
rescue ArgumentError => e
|
15
|
+
output << "#{e.message} parsing #{path}"
|
16
|
+
clean = false
|
17
|
+
end
|
18
|
+
end
|
19
|
+
return (clean ? :good : :bad), output
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Overcommit
|
2
|
+
class Reporter
|
3
|
+
include ConsoleMethods
|
4
|
+
|
5
|
+
def initialize(name, checks)
|
6
|
+
@name = name
|
7
|
+
@checks = checks
|
8
|
+
@width = 70 - (@checks.map { |s| s.name.length }.max || 0)
|
9
|
+
@results = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def with_status(check, &block)
|
13
|
+
title = " Checking #{check.name}..."
|
14
|
+
print title unless check.stealth?
|
15
|
+
|
16
|
+
status, output = yield
|
17
|
+
|
18
|
+
print_incremental_result(title, status, output, check.stealth?)
|
19
|
+
@results << status
|
20
|
+
end
|
21
|
+
|
22
|
+
def print_header
|
23
|
+
puts "Running #{@name} checks"
|
24
|
+
end
|
25
|
+
|
26
|
+
def print_result
|
27
|
+
puts
|
28
|
+
case final_result
|
29
|
+
when :good
|
30
|
+
success "+++ All #{@name} checks passed"
|
31
|
+
exit 0
|
32
|
+
when :bad
|
33
|
+
error "!!! One or more #{@name} checks failed"
|
34
|
+
exit 1
|
35
|
+
when :stop
|
36
|
+
warning "*** One or more #{@name} checks needs attention"
|
37
|
+
warning "*** If you really want to commit, use SKIP_CHECKS"
|
38
|
+
warning "*** (takes a space-separated list of checks to skip, or 'all')"
|
39
|
+
exit 1
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def print_incremental_result(title, status, output, stealth = false)
|
46
|
+
if stealth
|
47
|
+
return if status == :good
|
48
|
+
print title
|
49
|
+
end
|
50
|
+
|
51
|
+
print '.' * (@width - title.length)
|
52
|
+
case status
|
53
|
+
when :good
|
54
|
+
success 'OK'
|
55
|
+
when :bad
|
56
|
+
error 'FAILED'
|
57
|
+
print_report output
|
58
|
+
when :warn
|
59
|
+
warning output
|
60
|
+
when :stop
|
61
|
+
warning 'UH OH'
|
62
|
+
print_report output
|
63
|
+
else
|
64
|
+
error '???'
|
65
|
+
print_report "Check didn't return a status"
|
66
|
+
exit 1
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def final_result
|
71
|
+
return :bad if @results.include?(:bad)
|
72
|
+
return :stop if @results.include?(:stop)
|
73
|
+
return :good
|
74
|
+
end
|
75
|
+
|
76
|
+
def print_report(*report)
|
77
|
+
puts report.flatten.map { |line| " #{line}" }.join("\n")
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|