Skip to content

Commit 023676e

Browse files
committed
Add pre-commit hook for hlint
1 parent 2c92b44 commit 023676e

File tree

3 files changed

+97
-0
lines changed

3 files changed

+97
-0
lines changed

config/default.yml

+7
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,13 @@ PreCommit:
225225
required_executable: 'grep'
226226
flags: ['-IHn', "\t"]
227227

228+
Hlint:
229+
enabled: false
230+
description: 'Analyzing with hlint'
231+
required_executable: 'hlint'
232+
install_command: 'cabal install hlint'
233+
include: '**/*.hs'
234+
228235
HtmlHint:
229236
enabled: false
230237
description: 'Analyzing with HTMLHint'
+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
module Overcommit::Hook::PreCommit
2+
# Runs `hlint` against any modified Haskell files.
3+
#
4+
# @see https://github.com/ndmitchell/hlint
5+
class Hlint < Base
6+
MESSAGE_REGEX = /
7+
^(?<file>(?:\w:)?[^:]+)
8+
:(?<line>\d+)
9+
:\d+
10+
:\s*(?<type>\w+)
11+
/x
12+
13+
MESSAGE_TYPE_CATEGORIZER = lambda do |type|
14+
type.include?('W') ? :warning : :error
15+
end
16+
17+
def run
18+
result = execute(command, args: applicable_files)
19+
return :pass if result.success?
20+
21+
raw_messages = result.stdout.split("\n").grep(MESSAGE_REGEX)
22+
23+
# example message:
24+
# path/to/file.hs:1:0: Error: message
25+
extract_messages(
26+
raw_messages,
27+
MESSAGE_REGEX,
28+
MESSAGE_TYPE_CATEGORIZER
29+
)
30+
end
31+
end
32+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
require 'spec_helper'
2+
3+
describe Overcommit::Hook::PreCommit::Hlint do
4+
let(:config) { Overcommit::ConfigurationLoader.default_configuration }
5+
let(:context) { double('context') }
6+
subject { described_class.new(config, context) }
7+
8+
let(:result) { double('result') }
9+
10+
before do
11+
subject.stub(:applicable_files).and_return(%w[file1.hs file2.hs])
12+
subject.stub(:execute).and_return(result)
13+
end
14+
15+
context 'when hlint exits successfully' do
16+
before do
17+
result.stub(success?: true, stdout: '')
18+
end
19+
20+
it { should pass }
21+
end
22+
23+
context 'when hlint exits unsucessfully' do
24+
let(:result) { double('result') }
25+
26+
before do
27+
result.stub(:success?).and_return(false)
28+
end
29+
30+
context 'and it reports a warning' do
31+
before do
32+
result.stub(:stdout).and_return(normalize_indent(<<-OUT))
33+
file1.hs:22:16: Warning: Use const
34+
Found:
35+
\\ _ -> False
36+
Why not:
37+
const False
38+
OUT
39+
end
40+
41+
it { should warn }
42+
end
43+
44+
context 'and it reports an error' do
45+
before do
46+
result.stub(:stdout).and_return(normalize_indent(<<-OUT))
47+
file1.hs:22:5: Error: Redundant lambda
48+
Found:
49+
nameHack = \\ _ -> Nothing
50+
Why not:
51+
nameHack _ = Nothing
52+
OUT
53+
end
54+
55+
it { should fail_hook }
56+
end
57+
end
58+
end

0 commit comments

Comments
 (0)