Skip to content

Commit a233d7e

Browse files
Copilotyegor256
andcommitted
Implement HLint static code analysis integration
Co-authored-by: yegor256 <[email protected]>
1 parent 68c5a42 commit a233d7e

File tree

4 files changed

+103
-1
lines changed

4 files changed

+103
-1
lines changed

.github/workflows/hlint.yml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2025 Objectionary.com
2+
# SPDX-License-Identifier: MIT
3+
---
4+
# yamllint disable rule:line-length
5+
name: hlint
6+
'on':
7+
pull_request:
8+
branches:
9+
- master
10+
push:
11+
branches:
12+
- master
13+
jobs:
14+
hlint:
15+
runs-on: ubuntu-latest
16+
steps:
17+
- uses: actions/checkout@v4
18+
- name: Set up HLint
19+
uses: haskell-actions/hlint-setup@v2
20+
with:
21+
version: '3.5'
22+
- name: Run HLint
23+
uses: haskell-actions/hlint-run@v2
24+
with:
25+
path: '["src/", "app/", "test/"]'
26+
fail-on: warning

.hlint.yaml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# HLint configuration file for phino
2+
# SPDX-FileCopyrightText: Copyright (c) 2025 Objectionary.com
3+
# SPDX-License-Identifier: MIT
4+
5+
# Configuration for the phino Haskell project
6+
# See https://github.com/ndmitchell/hlint for documentation
7+
8+
# Enable some additional checks
9+
- group: {name: default, enabled: true}
10+
11+
# Disable some suggestions that might be too pedantic for this project
12+
- ignore: {name: "Use newtype instead of data"}
13+
- ignore: {name: "Use camelCase"}
14+
15+
# Enable warnings for redundant imports, spacing, etc.
16+
- warn: {name: "Redundant do"}
17+
- warn: {name: "Redundant bracket"}
18+
- warn: {name: "Redundant $"}
19+
- warn: {name: "Use concatMap"}
20+
- warn: {name: "Use map"}
21+
- warn: {name: "Use fmap"}
22+
23+
# Specify modules to check
24+
- modules:
25+
- {name: [Prelude], within: []}
26+
27+
# Custom rules for this project can be added here

phino.cabal

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ library
4545
Paths_phino
4646
build-depends:
4747
file-embed ^>=0.0.16.0,
48-
base >= 4.18.3.0,
48+
base ^>=4.18.3.0,
4949
containers,
5050
megaparsec >= 9.0,
5151
text,
@@ -93,6 +93,7 @@ test-suite spec
9393
YamlSpec,
9494
MiscSpec,
9595
XMIRSpec,
96+
HLintSpec,
9697
Paths_phino
9798
autogen-modules:
9899
Paths_phino
@@ -114,6 +115,7 @@ test-suite spec
114115
text,
115116
silently,
116117
directory,
118+
process,
117119
xml-conduit ^>=1.10
118120
build-tool-depends:
119121
hspec-discover:hspec-discover

test/HLintSpec.hs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{-# LANGUAGE ScopedTypeVariables #-}
2+
-- SPDX-FileCopyrightText: Copyright (c) 2025 Objectionary.com
3+
-- SPDX-License-Identifier: MIT
4+
5+
module HLintSpec (spec) where
6+
7+
import Control.Exception (try, IOException)
8+
import System.Exit (ExitCode(..))
9+
import System.Process (readProcessWithExitCode)
10+
import Test.Hspec
11+
12+
-- | Check if hlint is available on the system
13+
isHLintAvailable :: IO Bool
14+
isHLintAvailable = do
15+
result <- try (readProcessWithExitCode "hlint" ["--version"] "")
16+
case result of
17+
Left (_ :: IOException) -> return False
18+
Right (ExitSuccess, _, _) -> return True
19+
Right (ExitFailure _, _, _) -> return False
20+
21+
-- | Run hlint on a directory and check for success
22+
runHLintCheck :: String -> IO ()
23+
runHLintCheck dir = do
24+
available <- isHLintAvailable
25+
if not available
26+
then pendingWith "hlint is not available on this system"
27+
else do
28+
(exitCode, stdout, stderr) <- readProcessWithExitCode "hlint" [dir] ""
29+
case exitCode of
30+
ExitSuccess -> return ()
31+
ExitFailure _ -> do
32+
putStrLn $ "HLint warnings/errors in " ++ dir ++ ":"
33+
putStrLn stdout
34+
putStrLn stderr
35+
exitCode `shouldBe` ExitSuccess
36+
37+
spec :: Spec
38+
spec = do
39+
describe "HLint" $ do
40+
it "should pass hlint check for src/" $ do
41+
runHLintCheck "src/"
42+
43+
it "should pass hlint check for app/" $ do
44+
runHLintCheck "app/"
45+
46+
it "should pass hlint check for test/" $ do
47+
runHLintCheck "test/"

0 commit comments

Comments
 (0)