Skip to content

Commit e2c6de5

Browse files
authored
Merge pull request #10 from haskell-actions/haskell
Rewrite as a Docker container action written in Haskell.
2 parents 808e8cc + 8b0663f commit e2c6de5

File tree

17 files changed

+677
-30
lines changed

17 files changed

+677
-30
lines changed

.github/workflows/experiment.yaml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
name: Testing Action
2+
concurrency: build
3+
permissions: read-all
4+
5+
on: [workflow_dispatch]
6+
7+
jobs:
8+
scan:
9+
name: Scan code with HLint
10+
runs-on: ubuntu-latest
11+
permissions:
12+
# Needed to upload results to GitHub code scanning.
13+
security-events: write
14+
steps:
15+
- uses: actions/checkout@v3
16+
- uses: haskell-actions/hlint-scan@haskell

.github/workflows/release.yaml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: Publish Docker Image
2+
concurrency: build
3+
permissions: read-all
4+
5+
on: [workflow_dispatch]
6+
7+
env:
8+
REGISTRY: ghcr.io
9+
IMAGE_NAME: ${{ github.repository }}
10+
11+
jobs:
12+
build-and-push-image:
13+
runs-on: ubuntu-latest
14+
permissions:
15+
contents: read
16+
packages: write
17+
18+
steps:
19+
- name: Checkout repository
20+
uses: actions/checkout@v3
21+
22+
- name: Log in to the Container registry
23+
uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9
24+
with:
25+
registry: ${{ env.REGISTRY }}
26+
username: ${{ github.actor }}
27+
password: ${{ secrets.GITHUB_TOKEN }}
28+
29+
- name: Extract metadata (tags, labels) for Docker
30+
id: meta
31+
uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
32+
with:
33+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
34+
35+
- name: Build and push Docker image
36+
uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc
37+
with:
38+
context: .
39+
push: true
40+
tags: ${{ steps.meta.outputs.tags }}
41+
labels: ${{ steps.meta.outputs.labels }}

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
*~
2+
*.cabal
3+
.stack-work/
4+
.vscode/
5+
stack.yaml.lock

Dockerfile

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# syntax=docker/dockerfile:1
2+
3+
# We fetch and build a specific unreleased version of HLint as well,
4+
# since a version of HLint with SARIF support has not been released yet.
5+
#
6+
# Once one has been, we may either continue to bundle the hlint binary
7+
# together but at a more stable and official set of versions.
8+
# Alternatively, we could have the action retrieve an hlint release
9+
# automatically if one is not already available locally in the action.
10+
11+
FROM haskell:9.4.4 AS build
12+
RUN mkdir -p /src
13+
WORKDIR /src
14+
RUN git clone https://github.com/haskell-actions/hlint-scan.git
15+
WORKDIR /src/hlint-scan
16+
RUN stack install hlint hlint-scan:exe:hlint-scan
17+
RUN cp $(stack path --local-bin)/hlint /
18+
RUN cp $(stack path --local-bin)/hlint-scan /
19+
20+
FROM haskell:9.4.4-slim
21+
COPY --from=build /hlint /hlint-scan /
22+
ENTRYPOINT ["/hlint-scan"]

README.md

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,6 @@
33
This is a GitHub action which scans Haskell code using [HLint]
44
and uploads its suggested improvements to [GitHub code scanning].
55

6-
This needs HLint to be set up.
7-
This can be taken care of by [haskell/actions/hlint-setup].
8-
9-
## Warning
10-
11-
This depends on unreleased versions of HLint.
12-
For an example as to how one could use this action at the current time,
13-
see [chungyc/site-personal/hlint.yaml](https://github.com/chungyc/site-personal/blob/main/.github/workflows/hlint.yaml).
14-
156
## Usage
167

178
A minimal example for setting up code scanning with HLint:

action.yaml

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -19,41 +19,31 @@ inputs:
1919
binary:
2020
description: Path to the hlint binary.
2121
required: false
22-
default: hlint
2322
path:
2423
description: Path of file or directory that HLint will be told to scan.
2524
required: false
2625
default: .
2726
category:
2827
description: String used by GitHub code scanning for matching the analyses.
2928
required: false
30-
default: null
29+
token:
30+
description: Access token to fetch the repository and write the code scanning results from HLint to GitHub code scanning.
31+
required: false
32+
default: ${{ github.token }}
3133

3234
outputs:
3335
sarif-id:
3436
description: The ID of the uploaded SARIF file.
3537
value: ${{ steps.upload-sarif.outputs.sarif-id }}
3638

3739
runs:
38-
using: 'composite'
39-
40-
steps:
41-
42-
- name: Run HLint
43-
run: |
44-
"$BINARY" --no-exit-code --sarif "$FILEPATH" >> "$TMPDIR/hlint.sarif"
45-
shell: bash
46-
env:
47-
BINARY: ${{ inputs.binary }}
48-
FILEPATH: ${{ inputs.path }}
49-
TMPDIR: ${{ runner.temp }}
50-
51-
- id: upload-sarif
52-
name: Upload SARIF file
53-
uses: github/codeql-action/upload-sarif@v2
54-
with:
55-
sarif_file: ${{ runner.temp }}/hlint.sarif
56-
category: ${{ inputs.category }}
40+
using: docker
41+
image: Dockerfile
42+
args:
43+
- binary=${{ inputs.binary }}
44+
- path=${{ inputs.path }}
45+
- category=${{ inputs.category }}
46+
- token=${{ inputs.token }}
5747

5848
branding:
5949
icon: 'alert-circle'

app/Main.hs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{-
2+
Copyright 2023 Google LLC
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
https://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
-}
16+
17+
module Main (main) where
18+
19+
import qualified Scan
20+
import System.Environment (getArgs)
21+
22+
main :: IO ()
23+
main = getArgs >>= Scan.main

docs/CHANGELOG.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Changelog for `hlint-scan`
2+
3+
All notable changes to this project will be documented in this file.
4+
5+
The format is based on [Keep a Changelog] and this project adheres to
6+
the [Haskell Package Versioning Policy].
7+
8+
[Haskell Package Versioning Policy]: https://pvp.haskell.org/
9+
[Keep a Changelog]: https://keepachangelog.com/en/1.0.0/
10+
11+
## Unreleased
12+
13+
* Rewrite using a Docker container action using Haskell.
14+
* It will no longer need HLint to be set up separately,
15+
although it can use one set up by the user if requested to do so.
16+
17+
## 0.1.0.0 - 2023-04-03
18+
19+
* Initial working implementation with GitHub composite action.

package.yaml

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
# Copyright 2023 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
name: hlint-scan
16+
version: 0.0.0.0
17+
github: "haskell-actions/hlint-scan"
18+
license: Apache-2.0
19+
author: "Yoo Chung"
20+
maintainer: "[email protected]"
21+
copyright: "Copyright 2023 Google LLC"
22+
23+
extra-source-files:
24+
- action.yaml
25+
- LICENSE
26+
- README.md
27+
- docs/**
28+
29+
synopsis: Code scanning GitHub action using HLint.
30+
category: GitHub, Development
31+
32+
description: |
33+
Scans code with HLint and uploads its analysis results to GitHub code scanning.
34+
See <https://github.com/haskell-actions/hlint-scan>.
35+
36+
dependencies:
37+
- base
38+
39+
language: GHC2021
40+
41+
default-extensions:
42+
- OverloadedStrings
43+
44+
ghc-options:
45+
- -Wall
46+
- -Werror
47+
48+
library:
49+
source-dirs: src
50+
dependencies:
51+
- aeson
52+
- base64
53+
- bytestring
54+
- filepath
55+
- github-rest
56+
- process
57+
- text
58+
- vector
59+
- zlib
60+
61+
executables:
62+
hlint-scan:
63+
main: Main.hs
64+
source-dirs: app
65+
66+
ghc-options:
67+
- -threaded
68+
- -rtsopts
69+
- -with-rtsopts=-N
70+
71+
dependencies:
72+
- hlint-scan
73+
74+
# Work around https://github.com/sol/hpack/issues/303.
75+
when:
76+
condition: false
77+
other-modules: Paths_hlint_scan
78+
79+
tests:
80+
spec:
81+
main: Spec.hs
82+
source-dirs: test
83+
84+
ghc-options:
85+
- -threaded
86+
- -rtsopts
87+
- -with-rtsopts=-N
88+
89+
dependencies:
90+
- hlint-scan
91+
- hspec
92+
93+
when:
94+
condition: false
95+
other-modules:
96+
- Examples # Don't include the doctest runner.
97+
- Paths_hlint_scan # Work around https://github.com/sol/hpack/issues/303.
98+
99+
examples:
100+
main: test/Examples.hs
101+
102+
ghc-options:
103+
- -threaded
104+
- -rtsopts
105+
- -with-rtsopts=-N
106+
107+
dependencies:
108+
- hlint-scan
109+
- doctest-parallel
110+
111+
# Work around https://github.com/sol/hpack/issues/303.
112+
when:
113+
condition: false
114+
other-modules: Paths_hlint_scan

src/Arguments.hs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
{-
2+
Copyright 2023 Google LLC
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
https://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
-}
16+
17+
module Arguments (validate, translate) where
18+
19+
import Data.List (group, sort)
20+
import Data.Maybe (mapMaybe)
21+
22+
validate :: [String] -> Maybe String
23+
validate args
24+
| [] <- errors = Nothing
25+
| otherwise = Just $ unlines errors
26+
where
27+
errors = mapMaybe forString args ++ map (\s -> "duplicate argument: \"" <> s <> "\"") duplicates
28+
forString s =
29+
if '=' `elem` s
30+
then Nothing
31+
else Just ("no '=' in \"" <> s <> "\"")
32+
keys = map (fst . toTuple) args
33+
duplicates = concatMap (take 1) $ filter ((<) 1 . length) $ group $ sort keys
34+
35+
translate :: [String] -> (FilePath, [String], Maybe String, Maybe String)
36+
translate args = (executable', path' : "-j" : "--sarif" : "--no-exit-code" : flags, category, token)
37+
where
38+
argsMap = map toTuple args
39+
executable = lookup "binary" argsMap
40+
executable'
41+
| Nothing <- executable = "/hlint"
42+
| Just "" <- executable = "/hlint"
43+
| Just s <- executable = s
44+
path = lookup "path" argsMap
45+
path'
46+
| Nothing <- path = "."
47+
| Just "" <- path = "."
48+
| Just s <- path = s
49+
category = lookup "category" argsMap
50+
token = lookup "token" argsMap
51+
flags =
52+
concatMap toFlag $
53+
filter (flip elem ["binary", "path", "category", "token"] . fst) argsMap
54+
55+
toTuple :: String -> (String, String)
56+
toTuple s = (key, drop 1 prefixedValue)
57+
where
58+
(key, prefixedValue) = break (== '=') s
59+
60+
toFlag :: (String, String) -> [String]
61+
toFlag _ = []

0 commit comments

Comments
 (0)