diff --git a/.github/workflows/cabal.yml b/.github/workflows/cabal.yml index 247a8a5..395d6dd 100644 --- a/.github/workflows/cabal.yml +++ b/.github/workflows/cabal.yml @@ -1,43 +1,53 @@ name: cabal - on: push: - branches: [ main ] + branches: [main] pull_request: - branches: [ '*' ] - + branches: ['*'] jobs: build: runs-on: ubuntu-20.04 strategy: fail-fast: false matrix: - ghc: ["8.6", "8.8", "8.10", "9.0", "9.2", "9.4"] - cabal: ["3.6"] - cache-version: ["2022-10-25"] - + ghc-version: ["8.6", "8.8", "8.10", "9.4", "9.6", "9.8", "9.12"] + cabal-version: ["3.12"] + cache-version: ["2025-01-01"] steps: - - uses: actions/checkout@v2 - - uses: haskell/actions/setup@v2 - with: - ghc-version: ${{ matrix.ghc }} - cabal-version: ${{ matrix.cabal }} - - - name: Cache ~/.cabal/store - uses: actions/cache@v3 - with: - path: | - ~/.cabal/store - dist-newstyle - key: ${{ runner.os }}-${{ matrix.ghc }}-${{ matrix.cache-version }}-cabal - - - name: Install dependencies - run: | - cabal update - cabal configure --disable-optimization --enable-tests --write-ghc-environment-files=always -j2 - cabal build --only-dependencies - - - name: Build & Test - run: | - cabal build --flag dev - cabal test --flag dev + - uses: actions/checkout@v4 + - name: Set up GHC ${{ matrix.ghc-version }} + uses: haskell-actions/setup@v2 + id: setup + with: + ghc-version: ${{ matrix.ghc-version }} + cabal-version: ${{ matrix.cabal-version }} + cabal-update: true + - name: Configure the build + run: | + cabal configure --enable-tests --disable-documentation --disable-optimization --write-ghc-environment-files=always -j2 + cabal build all --dry-run + - name: Restore cached dependencies + uses: actions/cache/restore@v4 + id: cache + env: + key: ${{ runner.os }}-ghc-${{ steps.setup.outputs.ghc-version }}-cabal-${{ steps.setup.outputs.cabal-version }}-${{ matrix.cache-version }} + with: + path: ${{ steps.setup.outputs.cabal-store }} + key: ${{ env.key }}-plan-${{ hashFiles('**/plan.json') }} + restore-keys: ${{ env.key }}- + - name: Install dependencies + # If we had an exact cache hit, the dependencies will be up to date. + if: steps.cache.outputs.cache-hit != 'true' + run: cabal build all --only-dependencies + # Cache dependencies already here, so that we do not have to rebuild them should the subsequent steps fail. + - name: Save cached dependencies + uses: actions/cache/save@v4 + # If we had an exact cache hit, trying to save the cache would error because of key clash. + if: steps.cache.outputs.cache-hit != 'true' + with: + path: ${{ steps.setup.outputs.cabal-store }} + key: ${{ steps.cache.outputs.cache-primary-key }} + - name: Build + run: cabal build all --flag dev + - name: Run tests + run: cabal test all --flag dev diff --git a/haskell-stack-trace-plugin.cabal b/haskell-stack-trace-plugin.cabal index 0e0e121..594902d 100644 --- a/haskell-stack-trace-plugin.cabal +++ b/haskell-stack-trace-plugin.cabal @@ -20,7 +20,7 @@ extra-source-files: CHANGELOG.md Readme.md -tested-with: GHC ==8.6.5 || ==8.8.4 || ==8.10.7 || ==9.0.2 || ==9.2.4 || ==9.4.8 || ==9.6.6 || ==9.8.4 || ==9.10.1 || ==9.12.1 +tested-with: GHC ==8.6.5 || ==8.8.4 || ==8.10.7 || ==9.4.8 || ==9.6.6 || ==9.8.4 || ==9.10.1 || ==9.12.1 source-repository head type: git @@ -38,7 +38,7 @@ common common-opts library import: common-opts hs-source-dirs: src - build-depends: ghc ^>=8.6 || ^>=8.8 || ^>=8.10 || ^>=9.0 || ^>=9.2 || ^>=9.4 || ^>=9.6 || ^>=9.8 || ^>=9.10 || ^>=9.12 + build-depends: ghc ^>=8.6 || ^>=8.8 || ^>=8.10 || ^>=9.4 || ^>=9.6 || ^>=9.8 || ^>=9.10 || ^>=9.12 exposed-modules: StackTrace.Plugin if flag(dev) @@ -55,8 +55,10 @@ test-suite test hs-source-dirs: test type: exitcode-stdio-1.0 build-depends: - , bytestring >=0.10 && <0.12 - , hspec ^>=2.8 + , bytestring >=0.10 + , hspec ^>=2.8 || ^>=2.11 + , raw-strings-qq ^>=1.1 + , regex-tdfa ^>=1.3 , typed-process ^>=0.2 build-tool-depends: hspec-discover:hspec-discover ^>=2.8 diff --git a/test/StackTrace/PluginSpec.hs b/test/StackTrace/PluginSpec.hs index 2cc6417..7571a79 100644 --- a/test/StackTrace/PluginSpec.hs +++ b/test/StackTrace/PluginSpec.hs @@ -1,17 +1,35 @@ {-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE QuasiQuotes #-} + module StackTrace.PluginSpec (spec) where import Data.ByteString.Lazy (ByteString) -import qualified Data.ByteString.Lazy as BL -import Test.Hspec +import qualified Data.ByteString.Lazy.Char8 as BS import System.Process.Typed +import Test.Hspec +import Text.RawString.QQ +import Text.Regex.TDFA ((=~)) + +-- | Extracts the function names of all functions that appear in a stack trace +extractStackTraceFunctions :: String -> [String] +extractStackTraceFunctions input = map extractFunctionName matches + where + regex = [r|[ ]*([A-Za-z0-9]+), called at example/Main.hs:[0-9]+:[0-9]+ in [^:]+:Main|] :: String + matches = (input =~ regex) :: [[String]] + extractFunctionName :: [String] -> String + extractFunctionName (_ : name : _) = name + extractFunctionName _ = error "Regex match failed" spec :: Spec spec = do output <- runIO exe - expected <- runIO $ BL.readFile "test/resource/ghc.output" - it "integration test" $ output `shouldBe` expected + let outputStr = BS.unpack output + let extractedFunctions = extractStackTraceFunctions outputStr + + -- each of these exceptions should appear in the stack trace + let expectedFunctions = ["error", "fError", "f10", "f9", "f8", "f7", "f6", "f5", "f4", "f3", "f2", "f1", "main"] :: [String] + it "integration test" $ extractedFunctions `shouldBe` expectedFunctions exe :: IO ByteString exe = do diff --git a/test/resource/ghc.output b/test/resource/ghc.output deleted file mode 100644 index c3953a0..0000000 --- a/test/resource/ghc.output +++ /dev/null @@ -1,15 +0,0 @@ -example: fError -CallStack (from HasCallStack): - error, called at example/Main.hs:47:10 in main:Main - fError, called at example/Main.hs:43:11 in main:Main - f10, called at example/Main.hs:40:6 in main:Main - f9, called at example/Main.hs:37:11 in main:Main - f8, called at example/Main.hs:33:16 in main:Main - f7, called at example/Main.hs:29:11 in main:Main - f6, called at example/Main.hs:25:15 in main:Main - f5, called at example/Main.hs:21:8 in main:Main - f4, called at example/Main.hs:17:6 in main:Main - f3, called at example/Main.hs:13:6 in main:Main - f2, called at example/Main.hs:10:6 in main:Main - f1, called at example/Main.hs:7:14 in main:Main - main, called at example/Main.hs:7:1 in main:Main