Skip to content

Commit 4a95f97

Browse files
jawshooahsds
authored andcommitted
Add pre-commit hooks for w3c_validators
Change-Id: I0570cc7cca4f16c965ec45f6c8c7a687a57a206a Reviewed-on: http://gerrit.causes.com/47048 Reviewed-by: Shane da Silva <shane.dasilva@brigade.com> Tested-by: Shane da Silva <shane.dasilva@brigade.com>
1 parent a761c8d commit 4a95f97

File tree

6 files changed

+315
-0
lines changed

6 files changed

+315
-0
lines changed

config/default.yml

+19
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,25 @@ PreCommit:
283283
description: 'Checking YAML syntax'
284284
include: '**/*.yml'
285285

286+
W3cCssValidator:
287+
enabled: false
288+
description: 'Analyzing with W3C CSS validation service'
289+
validator_uri: 'http://jigsaw.w3.org/css-validator/validator'
290+
language: 'en'
291+
profile: 'css3'
292+
warn_level: 2
293+
include:
294+
- '**/*.css'
295+
296+
W3cHtmlValidator:
297+
enabled: false
298+
description: 'Analyzing with W3C HTML validation service'
299+
validator_uri: 'http://validator.w3.org/check'
300+
charset: 'utf-8'
301+
doctype: 'HTML5'
302+
include:
303+
- '**/*.html'
304+
286305
# Hooks that run after HEAD changes or a file is explicitly checked out.
287306
PostCheckout:
288307
ALL:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
module Overcommit::Hook::PreCommit
2+
# Runs `w3c_validators` against any modified CSS files.
3+
class W3cCssValidator < Base
4+
def run
5+
begin
6+
require 'w3c_validators'
7+
rescue LoadError
8+
return :fail, 'w3c_validators not installed -- run `gem install w3c_validators`'
9+
end
10+
11+
result_messages =
12+
begin
13+
applicable_files.collect do |path|
14+
results = validator.validate_file(path)
15+
messages = results.errors + results.warnings
16+
messages.collect do |msg|
17+
# Some warnings are not per-line, so use 0 as a default
18+
line = Integer(msg.line || 0)
19+
20+
# Build message by hand to reduce noise from the validator response
21+
text = "#{msg.type.to_s.upcase}; URI: #{path}; line #{line}: #{msg.message.strip}"
22+
Overcommit::Hook::Message.new(msg.type, path, line, text)
23+
end
24+
end
25+
rescue W3CValidators::ValidatorUnavailable => e
26+
return :fail, e.message
27+
rescue W3CValidators::ParsingError => e
28+
return :fail, e.message
29+
end
30+
31+
result_messages.flatten!
32+
return :pass if result_messages.empty?
33+
34+
result_messages
35+
end
36+
37+
private
38+
39+
def validator
40+
unless @validator
41+
@validator = W3CValidators::CSSValidator.new(opts)
42+
@validator.set_language!(language) unless language.nil?
43+
@validator.set_profile!(profile) unless profile.nil?
44+
@validator.set_warn_level!(warn_level) unless warn_level.nil?
45+
end
46+
@validator
47+
end
48+
49+
def opts
50+
@opts ||= {
51+
validator_uri: config['validator_uri'],
52+
proxy_server: config['proxy_server'],
53+
proxy_port: config['proxy_port'],
54+
proxy_user: config['proxy_user'],
55+
proxy_pass: config['proxy_pass']
56+
}
57+
end
58+
59+
def language
60+
@language ||= config['language']
61+
end
62+
63+
# Values specified at
64+
# http://www.rubydoc.info/gems/w3c_validators/1.2/W3CValidators#CSS_PROFILES
65+
def profile
66+
@profile ||= config['profile']
67+
end
68+
69+
# One of 0, 1, 2, 'no'
70+
def warn_level
71+
@warn_level ||= config['warn_level']
72+
end
73+
end
74+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
module Overcommit::Hook::PreCommit
2+
# Runs `w3c_validators` against any modified HTML files.
3+
class W3cHtmlValidator < Base
4+
def run
5+
begin
6+
require 'w3c_validators'
7+
rescue LoadError
8+
return :fail, 'w3c_validators not installed -- run `gem install w3c_validators`'
9+
end
10+
11+
result_messages =
12+
begin
13+
applicable_files.collect do |path|
14+
results = validator.validate_file(path)
15+
messages = results.errors + results.warnings
16+
messages.collect do |msg|
17+
# Some warnings are not per-line, so use 0 as a default
18+
line = Integer(msg.line || 0)
19+
20+
# Build message by hand to reduce noise from the validator response
21+
text = "#{msg.type.to_s.upcase}; URI: #{path}; line #{line}: #{msg.message.strip}"
22+
Overcommit::Hook::Message.new(msg.type, path, line, text)
23+
end
24+
end
25+
rescue W3CValidators::ValidatorUnavailable => e
26+
return :fail, e.message
27+
rescue W3CValidators::ParsingError => e
28+
return :fail, e.message
29+
end
30+
31+
result_messages.flatten!
32+
return :pass if result_messages.empty?
33+
34+
result_messages
35+
end
36+
37+
private
38+
39+
def validator
40+
unless @validator
41+
@validator = W3CValidators::MarkupValidator.new(opts)
42+
@validator.set_charset!(charset, only_as_fallback = true) unless charset.nil?
43+
@validator.set_doctype!(doctype, only_as_fallback = true) unless doctype.nil?
44+
@validator.set_debug!
45+
end
46+
@validator
47+
end
48+
49+
def opts
50+
@opts ||= {
51+
validator_uri: config['validator_uri'],
52+
proxy_server: config['proxy_server'],
53+
proxy_port: config['proxy_port'],
54+
proxy_user: config['proxy_user'],
55+
proxy_pass: config['proxy_pass']
56+
}
57+
end
58+
59+
# Values specified at
60+
# http://www.rubydoc.info/gems/w3c_validators/1.2/W3CValidators#CHARSETS
61+
def charset
62+
@charset ||= config['charset']
63+
end
64+
65+
# Values specified at
66+
# http://www.rubydoc.info/gems/w3c_validators/1.2/W3CValidators#DOCTYPES
67+
def doctype
68+
@doctype ||= config['doctype']
69+
end
70+
end
71+
end

overcommit.gemspec

+1
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,5 @@ Gem::Specification.new do |s|
3131
s.add_development_dependency 'image_optim', '~> 0.20.0'
3232
s.add_development_dependency 'rspec', '~> 3.0'
3333
s.add_development_dependency 'travis', '~> 1.7'
34+
s.add_development_dependency 'w3c_validators', '~> 1.2'
3435
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
require 'spec_helper'
2+
require 'w3c_validators'
3+
4+
describe Overcommit::Hook::PreCommit::W3cCssValidator do
5+
let(:config) { Overcommit::ConfigurationLoader.default_configuration }
6+
let(:context) { double('context') }
7+
subject { described_class.new(config, context) }
8+
9+
before do
10+
subject.stub(:applicable_files).and_return(%w[file1.css file2.css])
11+
end
12+
13+
context 'when w3c_validators exits with an exception' do
14+
let(:validator) { double('validator') }
15+
16+
before do
17+
subject.stub(:validator).and_return(validator)
18+
end
19+
20+
context 'when the validator is not available' do
21+
before do
22+
validator.stub(:validate_file).and_raise(W3CValidators::ValidatorUnavailable)
23+
end
24+
25+
it { should fail_hook }
26+
end
27+
28+
context 'when the validator response cannot be parsed' do
29+
before do
30+
validator.stub(:validate_file).and_raise(W3CValidators::ParsingError)
31+
end
32+
33+
it { should fail_hook }
34+
end
35+
end
36+
37+
context 'when w3c_validators exits without an exception' do
38+
let(:validator) { double('validator') }
39+
let(:results) { double('results') }
40+
let(:message) { double('message') }
41+
42+
before do
43+
validator.stub(:validate_file).and_return(results)
44+
subject.stub(:validator).and_return(validator)
45+
end
46+
47+
context 'with no errors or warnings' do
48+
before do
49+
results.stub(:errors => [], :warnings => [])
50+
end
51+
52+
it { should pass }
53+
end
54+
55+
context 'with a warning' do
56+
before do
57+
message.stub(:type => :warning, :line => '1', :message => '')
58+
results.stub(:errors => [], :warnings => [message])
59+
subject.stub(:modified_lines_in_file).and_return([2, 3])
60+
end
61+
62+
it { should warn }
63+
end
64+
65+
context 'with an error' do
66+
before do
67+
message.stub(:type => :error, :line => '1', :message => '')
68+
results.stub(:errors => [message], :warnings => [])
69+
subject.stub(:modified_lines_in_file).and_return([1, 2])
70+
end
71+
72+
it { should fail_hook }
73+
end
74+
end
75+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
require 'spec_helper'
2+
require 'w3c_validators'
3+
4+
describe Overcommit::Hook::PreCommit::W3cHtmlValidator do
5+
let(:config) { Overcommit::ConfigurationLoader.default_configuration }
6+
let(:context) { double('context') }
7+
subject { described_class.new(config, context) }
8+
9+
before do
10+
subject.stub(:applicable_files).and_return(%w[file1.html file2.html])
11+
end
12+
13+
context 'when w3c_validators exits with an exception' do
14+
let(:validator) { double('validator') }
15+
16+
before do
17+
subject.stub(:validator).and_return(validator)
18+
end
19+
20+
context 'when the validator is not available' do
21+
before do
22+
validator.stub(:validate_file).and_raise(W3CValidators::ValidatorUnavailable)
23+
end
24+
25+
it { should fail_hook }
26+
end
27+
28+
context 'when the validator response cannot be parsed' do
29+
before do
30+
validator.stub(:validate_file).and_raise(W3CValidators::ParsingError)
31+
end
32+
33+
it { should fail_hook }
34+
end
35+
end
36+
37+
context 'when w3c_validators exits without an exception' do
38+
let(:validator) { double('validator') }
39+
let(:results) { double('results') }
40+
let(:message) { double('message') }
41+
42+
before do
43+
validator.stub(:validate_file).and_return(results)
44+
subject.stub(:validator).and_return(validator)
45+
end
46+
47+
context 'with no errors or warnings' do
48+
before do
49+
results.stub(:errors => [], :warnings => [])
50+
end
51+
52+
it { should pass }
53+
end
54+
55+
context 'with a warning' do
56+
before do
57+
message.stub(:type => :warning, :line => '1', :message => '')
58+
results.stub(:errors => [], :warnings => [message])
59+
subject.stub(:modified_lines_in_file).and_return([2, 3])
60+
end
61+
62+
it { should warn }
63+
end
64+
65+
context 'with an error' do
66+
before do
67+
message.stub(:type => :error, :line => '1', :message => '')
68+
results.stub(:errors => [message], :warnings => [])
69+
subject.stub(:modified_lines_in_file).and_return([1, 2])
70+
end
71+
72+
it { should fail_hook }
73+
end
74+
end
75+
end

0 commit comments

Comments
 (0)