diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 00000000..1b12e875
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,81 @@
+# SPDX-FileCopyrightText: 2020 Kowainik
+# SPDX-FileCopyrightText: 2022 Serokell
+#
+# SPDX-License-Identifier: MPL-2.0
+
+# Sources:
+# • https://github.com/kowainik/validation-selective/blob/5b46cd4810bbaa09b704062ebbfa2bb47137425d/.github/workflows/ci.yml
+# • https://kodimensional.dev/github-actions
+# • https://github.com/serokell/tztime/blob/336f585c2c7125a8ba58ffbf3dbea4f36a7c40e7/.github/workflows/ci.yml
+
+name: CI
+
+on: [push]
+
+jobs:
+ xrefcheck-build-and-test:
+ runs-on: windows-latest
+ strategy:
+ matrix:
+ stack: ["2.7.5"]
+ ghc: ["9.0.2"]
+ include:
+ - ghc: "9.0.2"
+ stackyaml: stack.yaml
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ submodules: 'true'
+
+ - uses: haskell/actions/setup@v2.0.1
+ id: setup-haskell-stack
+ name: Setup Haskell Stack
+ with:
+ ghc-version: ${{ matrix.ghc }}
+ stack-version: ${{ matrix.stack }}
+
+ - uses: actions/cache@v3
+ name: Cache stack root
+ with:
+ path: ~/AppData/Roaming/stack
+ key: ${{ runner.os }}-${{ matrix.ghc }}-stack
+
+ - uses: actions/cache@v3
+ name: Cache AppData/Local/Programs/stack
+ with:
+ path: ~/AppData/Local/Programs/stack
+ key: ${{ runner.os }}-${{ matrix.ghc }}-appdata-stack
+
+
+# When editing this action, make sure it can run without using cached folders.
+# Yes, it tries to install mingw-w64-x86_64-pcre twice
+ - name: install pacman dependencies
+ run: |
+ stack --system-ghc exec -- pacman -S --needed --noconfirm pkgconf;
+ stack --system-ghc exec -- pacman -S --needed --noconfirm msys2-keyring;
+ stack --system-ghc exec -- pacman --noconfirm -Syuu;
+ stack --system-ghc exec -- pacman -S --needed --noconfirm mingw-w64-x86_64-pcre;
+ stack --system-ghc exec -- pacman --noconfirm -Syuu;
+ stack --system-ghc exec -- pacman -S --needed --noconfirm mingw-w64-x86_64-pcre;
+ stack --system-ghc exec -- pacman -S --needed --noconfirm pcre-devel;
+
+ - name: Build
+ run: |
+ stack build --system-ghc --stack-yaml ${{ matrix.stackyaml }} --test --bench --no-run-tests --no-run-benchmarks --ghc-options '-Werror'
+
+ - name: stack test xrefcheck:xrefcheck-tests
+ run: |
+ stack test --system-ghc --stack-yaml ${{ matrix.stackyaml }} xrefcheck:xrefcheck-tests
+
+ - name: install xrefcheck to use with golden tests
+ run: |
+ stack --system-ghc --stack-yaml ${{ matrix.stackyaml }} install;
+
+ - uses: mig4/setup-bats@v1
+ name: Setup bats
+
+ - name: Golden tests
+ run: |
+ export PATH=$PATH:/c/Users/runneradmin/AppData/Roaming/local/bin;
+ bats ./tests/golden/**
+ shell: bash
diff --git a/CHANGES.md b/CHANGES.md
index 173f7a9f..e45a1aee 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -26,6 +26,10 @@ Unreleased
+ Now we notify user when there are scannable files that were not added to Git
yet. Also added CLI option `--include-untracked` to scan such files and treat
as existing.
+* [#191](https://github.com/serokell/xrefcheck/pull/191)
+ + Now we consider slash `/` (and only it) as path separator in local links for all OS,
+ so xrefcheck's report is OS-independent
+ + Use utf-8 compatible codepage on Windows
0.2.2
==========
diff --git a/README.md b/README.md
index 8422dc7b..a5ec5422 100644
--- a/README.md
+++ b/README.md
@@ -98,6 +98,16 @@ This file should be committed to your repository.
Run `stack install` to build everything and install the executable.
If you wish to use `cabal`, you need to run [`stack2cabal`](https://hackage.haskell.org/package/stack2cabal) first!
+### Run on Windows [↑](#xrefcheck)
+On Windows, executable requires some dynamic libraries (DLLs).
+They are shipped together with executable in [releases page](https://github.com/serokell/xrefcheck/releases).
+If you have built executable from source using `stack install`,
+those DLLs are downloaded by stack to a location that is not on `%PATH%` by default.
+There are several ways to fix this:
+- Add `%LocalAppData%\Programs\stack\x86_64-windows\msys2-<...>\mingw64\bin` to your PATH
+- run `stack exec xrefcheck.exe -- ` instead of `xrefcheck.exe `
+- add DLLs from archive from releases page to a folder containing `xrefcheck.exe`
+
## FAQ [↑](#xrefcheck)
1. How do I ignore specific files?
@@ -138,7 +148,6 @@ If you wish to use `cabal`, you need to run [`stack2cabal`](https://hackage.hask
## Further work [↑](#xrefcheck)
-- [ ] Support for non-Unix systems.
- [ ] Support link detection in different languages, not only Markdown.
- [ ] Haskell Haddock is first in turn.
diff --git a/exec/Main.hs b/exec/Main.hs
index da6b9959..404dab35 100644
--- a/exec/Main.hs
+++ b/exec/Main.hs
@@ -8,13 +8,14 @@ module Main where
import Universum
import Main.Utf8 (withUtf8)
+import System.IO.CodePage (withCP65001)
import Xrefcheck.CLI (Command (..), getCommand)
import Xrefcheck.Command (defaultAction)
import Xrefcheck.Config (defConfigText)
main :: IO ()
-main = withUtf8 $ do
+main = withUtf8 $ withCP65001 $ do
command <- getCommand
case command of
DefaultCommand options ->
diff --git a/package.yaml b/package.yaml
index 1879a18d..60f30533 100644
--- a/package.yaml
+++ b/package.yaml
@@ -111,7 +111,6 @@ library:
- reflection
- nyan-interpolation
- safe-exceptions
- - code-page
executables:
xrefcheck:
@@ -128,6 +127,7 @@ executables:
- xrefcheck
- universum
- with-utf8
+ - code-page
tests:
xrefcheck-tests:
diff --git a/src/Xrefcheck/Command.hs b/src/Xrefcheck/Command.hs
index fbe687c6..16620a86 100644
--- a/src/Xrefcheck/Command.hs
+++ b/src/Xrefcheck/Command.hs
@@ -15,7 +15,6 @@ import Fmt (build, fmt, fmtLn)
import System.Console.Pretty (supportsPretty)
import System.Directory (doesFileExist)
import Text.Interpolation.Nyan
-import System.IO.CodePage (withCP65001)
import Xrefcheck.CLI (Options (..), addExclusionOptions, addNetworkingOptions, defaultConfigPaths)
import Xrefcheck.Config
@@ -49,7 +48,7 @@ findFirstExistingFile = \case
if exists then pure (Just file) else findFirstExistingFile files
defaultAction :: Options -> IO ()
-defaultAction Options{..} = withCP65001 $ do
+defaultAction Options{..} = do
coloringSupported <- supportsPretty
give (if coloringSupported then oColorMode else WithoutColors) $ do
config <- case oConfigPath of
diff --git a/src/Xrefcheck/System.hs b/src/Xrefcheck/System.hs
index 37b9fd58..20f340f6 100644
--- a/src/Xrefcheck/System.hs
+++ b/src/Xrefcheck/System.hs
@@ -22,8 +22,8 @@ import GHC.IO.Unsafe (unsafePerformIO)
import System.Directory (canonicalizePath)
import System.Environment (lookupEnv)
import System.FilePath.Glob qualified as Glob
-import Text.Interpolation.Nyan
import System.FilePath.Posix (isRelative, (>))
+import Text.Interpolation.Nyan
import Xrefcheck.Util (normaliseWithNoTrailing)
diff --git a/tests/golden/check-ignore/check-ignore.bats b/tests/golden/check-ignore/check-ignore.bats
index c04f19d3..4d48ca8e 100644
--- a/tests/golden/check-ignore/check-ignore.bats
+++ b/tests/golden/check-ignore/check-ignore.bats
@@ -102,8 +102,6 @@ EOF
run xrefcheck\
--ignore ""
assert_failure
- assert_output --partial "option --ignore: Glob pattern compilation failed.
-Error message is:
-compile :: bad <>, expected number followed by - in to-ignore
-"
+ assert_output --partial "option --ignore: Glob pattern compilation failed."
+ assert_output --partial "compile :: bad <>, expected number followed by - in to-ignore"
}
diff --git a/tests/golden/check-ignoreExternalRefsTo/check-ignoreExternalRefsTo.bats b/tests/golden/check-ignoreExternalRefsTo/check-ignoreExternalRefsTo.bats
index 2d5108dd..6417f3ce 100644
--- a/tests/golden/check-ignoreExternalRefsTo/check-ignoreExternalRefsTo.bats
+++ b/tests/golden/check-ignoreExternalRefsTo/check-ignoreExternalRefsTo.bats
@@ -22,7 +22,7 @@ load '../helpers'
-c config-check-enabled.yaml \
-r .
- assert_diff expected.gold
+ assert_diff expected_linux.gold || assert_diff expected_windows.gold
}
@test "Ignore localhost, no config specified" {
diff --git a/tests/golden/check-ignoreExternalRefsTo/expected.gold b/tests/golden/check-ignoreExternalRefsTo/expected_linux.gold
similarity index 100%
rename from tests/golden/check-ignoreExternalRefsTo/expected.gold
rename to tests/golden/check-ignoreExternalRefsTo/expected_linux.gold
diff --git a/tests/golden/check-ignoreExternalRefsTo/expected_windows.gold b/tests/golden/check-ignoreExternalRefsTo/expected_windows.gold
new file mode 100644
index 00000000..2f4c9d52
--- /dev/null
+++ b/tests/golden/check-ignoreExternalRefsTo/expected_windows.gold
@@ -0,0 +1,35 @@
+=== Invalid references found ===
+
+ ➥ In file check-ignoreExternalRefsTo.md
+ bad reference (external) at src:7:10-53:
+ - text: "web-site"
+ - link: https://localhost:20000/web-site
+ - anchor: -
+
+ ⛂ InternalException (HostCannotConnect "localhost" [Network.Socket.connect: : failed (Connection refused (WSAECONNREFUSED)),Network.Socket.connect: : failed (Connection refused (WSAECONNREFUSED))])
+
+ ➥ In file check-ignoreExternalRefsTo.md
+ bad reference (external) at src:9:10-45:
+ - text: "team"
+ - link: https://127.0.0.1:20000/team
+ - anchor: -
+
+ ⛂ InternalException (HostCannotConnect "127.0.0.1" [Network.Socket.connect: : failed (Connection refused (WSAECONNREFUSED))])
+
+ ➥ In file check-ignoreExternalRefsTo.md
+ bad reference (external) at src:11:10-44:
+ - text: "blog"
+ - link: http://localhost:20000/blog
+ - anchor: -
+
+ ⛂ ConnectionFailure Network.Socket.connect: : failed (Connection refused (WSAECONNREFUSED))
+
+ ➥ In file check-ignoreExternalRefsTo.md
+ bad reference (external) at src:13:10-44:
+ - text: "labs"
+ - link: http://127.0.0.1:20000/labs
+ - anchor: -
+
+ ⛂ ConnectionFailure Network.Socket.connect: : failed (Connection refused (WSAECONNREFUSED))
+
+Invalid references dumped, 4 in total.
diff --git a/tests/golden/helpers.bash b/tests/golden/helpers.bash
index 851afd44..bc7994ca 100644
--- a/tests/golden/helpers.bash
+++ b/tests/golden/helpers.bash
@@ -67,5 +67,6 @@ assert_diff() {
: "{output_file?}"
diff $output_file $1 \
- --ignore-tab-expansion
+ --ignore-tab-expansion \
+ --strip-trailing-cr
}