diff --git a/.github/workflows/haskell-ci.yml b/.github/workflows/haskell-ci.yml index a3255a33..8c29fb22 100644 --- a/.github/workflows/haskell-ci.yml +++ b/.github/workflows/haskell-ci.yml @@ -1,6 +1,6 @@ # This GitHub workflow config has been generated by a script via # -# haskell-ci 'github' 'hedis.cabal' +# haskell-ci 'github' '--config=cabal.haskell-ci' 'cabal.project' # # To regenerate the script (for example after adjusting tested-with) run # @@ -8,34 +8,48 @@ # # For more information, see https://github.com/haskell-CI/haskell-ci # -# version: 0.18.1 +# version: 0.19.20260331 # -# REGENDATA ("0.18.1",["github","hedis.cabal"]) +# REGENDATA ("0.19.20260331",["github","--config=cabal.haskell-ci","cabal.project"]) # name: Haskell-CI on: - - push - - pull_request + push: + branches: + - master + pull_request: + branches: + - master + merge_group: + branches: + - master + workflow_dispatch: + {} jobs: linux: name: Haskell-CI - Linux - ${{ matrix.compiler }} - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 timeout-minutes: 60 container: - image: buildpack-deps:bionic + image: buildpack-deps:jammy continue-on-error: ${{ matrix.allow-failure }} strategy: matrix: include: - - compiler: ghc-9.4.8 + - compiler: ghc-9.14.1 compilerKind: ghc - compilerVersion: 9.4.8 + compilerVersion: 9.14.1 setup-method: ghcup - allow-failure: true - - compiler: ghc-9.6.7 + allow-failure: false + - compiler: ghc-9.12.4 compilerKind: ghc - compilerVersion: 9.6.7 + compilerVersion: 9.12.4 + setup-method: ghcup + allow-failure: false + - compiler: ghc-9.10.3 + compilerKind: ghc + compilerVersion: 9.10.3 setup-method: ghcup allow-failure: false - compiler: ghc-9.8.4 @@ -43,22 +57,36 @@ jobs: compilerVersion: 9.8.4 setup-method: ghcup allow-failure: false - - compiler: ghc-9.10.2 + - compiler: ghc-9.6.7 compilerKind: ghc - compilerVersion: 9.10.2 + compilerVersion: 9.6.7 setup-method: ghcup allow-failure: false fail-fast: false steps: - - name: apt + - name: apt-get install run: | apt-get update apt-get install -y --no-install-recommends gnupg ca-certificates dirmngr curl git software-properties-common libtinfo5 + - name: Install GHCup + run: | mkdir -p "$HOME/.ghcup/bin" - curl -sL https://downloads.haskell.org/ghcup/0.1.20.0/x86_64-linux-ghcup-0.1.20.0 > "$HOME/.ghcup/bin/ghcup" + curl -sL https://downloads.haskell.org/ghcup/0.1.50.1/x86_64-linux-ghcup-0.1.50.1 > "$HOME/.ghcup/bin/ghcup" chmod a+x "$HOME/.ghcup/bin/ghcup" + - name: Install cabal-install + run: | + "$HOME/.ghcup/bin/ghcup" install cabal 3.16.0.0 || (cat "$HOME"/.ghcup/logs/*.* && false) + echo "CABAL=$HOME/.ghcup/bin/cabal-3.16.0.0 -vnormal+nowrap" >> "$GITHUB_ENV" + - name: Install GHC (GHCup) + if: matrix.setup-method == 'ghcup' + run: | "$HOME/.ghcup/bin/ghcup" install ghc "$HCVER" || (cat "$HOME"/.ghcup/logs/*.* && false) - "$HOME/.ghcup/bin/ghcup" install cabal 3.10.2.0 || (cat "$HOME"/.ghcup/logs/*.* && false) + HC=$("$HOME/.ghcup/bin/ghcup" whereis ghc "$HCVER") + HCPKG=$(echo "$HC" | sed 's#ghc$#ghc-pkg#') + HADDOCK=$(echo "$HC" | sed 's#ghc$#haddock#') + echo "HC=$HC" >> "$GITHUB_ENV" + echo "HCPKG=$HCPKG" >> "$GITHUB_ENV" + echo "HADDOCK=$HADDOCK" >> "$GITHUB_ENV" env: HCKIND: ${{ matrix.compilerKind }} HCNAME: ${{ matrix.compiler }} @@ -69,21 +97,12 @@ jobs: echo "LANG=C.UTF-8" >> "$GITHUB_ENV" echo "CABAL_DIR=$HOME/.cabal" >> "$GITHUB_ENV" echo "CABAL_CONFIG=$HOME/.cabal/config" >> "$GITHUB_ENV" - HCDIR=/opt/$HCKIND/$HCVER - HC=$("$HOME/.ghcup/bin/ghcup" whereis ghc "$HCVER") - HCPKG=$(echo "$HC" | sed 's#ghc$#ghc-pkg#') - HADDOCK=$(echo "$HC" | sed 's#ghc$#haddock#') - echo "HC=$HC" >> "$GITHUB_ENV" - echo "HCPKG=$HCPKG" >> "$GITHUB_ENV" - echo "HADDOCK=$HADDOCK" >> "$GITHUB_ENV" - echo "CABAL=$HOME/.ghcup/bin/cabal-3.10.2.0 -vnormal+nowrap" >> "$GITHUB_ENV" HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\d+)\.(\d+)\.(\d+)(\.(\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))') echo "HCNUMVER=$HCNUMVER" >> "$GITHUB_ENV" echo "ARG_TESTS=--enable-tests" >> "$GITHUB_ENV" echo "ARG_BENCH=--enable-benchmarks" >> "$GITHUB_ENV" echo "HEADHACKAGE=false" >> "$GITHUB_ENV" echo "ARG_COMPILER=--$HCKIND --with-compiler=$HC" >> "$GITHUB_ENV" - echo "GHCJSARITH=0" >> "$GITHUB_ENV" env: HCKIND: ${{ matrix.compilerKind }} HCNAME: ${{ matrix.compiler }} @@ -123,6 +142,11 @@ jobs: - name: update cabal index run: | $CABAL v2-update -v + - name: cache (tools) + uses: actions/cache/restore@v4 + with: + key: ${{ runner.os }}-${{ matrix.compiler }}-tools-2ae1f11d + path: ~/.haskell-ci-tools - name: install cabal-plan run: | mkdir -p $HOME/.cabal/bin @@ -132,8 +156,18 @@ jobs: rm -f cabal-plan.xz chmod a+x $HOME/.cabal/bin/cabal-plan cabal-plan --version + - name: install doctest + run: | + $CABAL --store-dir=$HOME/.haskell-ci-tools/store v2-install $ARG_COMPILER --ignore-project -j2 doctest --constraint='doctest ^>=0.24' + doctest --version + - name: save cache (tools) + if: always() + uses: actions/cache/save@v4 + with: + key: ${{ runner.os }}-${{ matrix.compiler }}-tools-2ae1f11d + path: ~/.haskell-ci-tools - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v5 with: path: source - name: initial cabal.project for sdist @@ -158,10 +192,15 @@ jobs: touch cabal.project.local echo "packages: ${PKGDIR_hedis}" >> cabal.project echo "package hedis" >> cabal.project - echo " ghc-options: -Werror=missing-methods" >> cabal.project + echo " ghc-options: -Werror=missing-methods -Werror=missing-fields" >> cabal.project + echo "package hedis" >> cabal.project + echo " ghc-options: -Werror=unused-packages" >> cabal.project + echo "package hedis" >> cabal.project + echo " ghc-options: -Werror=incomplete-patterns -Werror=incomplete-uni-patterns" >> cabal.project cat >> cabal.project <> cabal.project.local + $HCPKG list --simple-output --names-only | perl -ne 'for (split /\s+/) { print "constraints: any.$_ installed\n" unless /^(hedis)$/; }' >> cabal.project.local cat cabal.project cat cabal.project.local - name: dump install plan @@ -169,7 +208,7 @@ jobs: $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dry-run all cabal-plan - name: restore cache - uses: actions/cache/restore@v3 + uses: actions/cache/restore@v4 with: key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }} path: ~/.cabal/store @@ -184,9 +223,10 @@ jobs: - name: build run: | $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --write-ghc-environment-files=always - - name: tests + - name: doctest run: | - $CABAL v2-test $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --test-show-details=direct + cd ${PKGDIR_hedis} || false + doctest -XHaskell2010 src - name: cabal check run: | cd ${PKGDIR_hedis} || false @@ -199,8 +239,8 @@ jobs: rm -f cabal.project.local $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all - name: save cache - uses: actions/cache/save@v3 if: always() + uses: actions/cache/save@v4 with: key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }} path: ~/.cabal/store diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index 60e9df32..00000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,36 +0,0 @@ -on: [push] -name: build -jobs: - build: - runs-on: ${{ matrix.os }} - strategy: - matrix: - ghc: ['8.10.5', '9.2.1', '9.6.2'] - cabal: ['3.10.1.0'] - os: [ubuntu-latest] - redis-version: [6, 7] - services: - redis: - image: "redis:${{ matrix.redis-version }}" - options: >- - --health-cmd "redis-cli ping" - --health-interval 10s - --health-timeout 5s - --health-retries 5 - ports: - # Maps port 6379 on service container to the host - - 6379:6379 - name: GHC ${{ matrix.ghc }} / Cabal ${{ matrix.cabal }} / Redis ${{ matrix.redis-version}}/ ${{ matrix.os }} - steps: - - uses: actions/checkout@v3 - - name: Setup Haskell - uses: haskell/actions/setup@v2 - with: - ghc-version: ${{ matrix.ghc }} - cabal-version: ${{ matrix.cabal }} - - run: cabal build --enable-tests --enable-benchmarks - - run: cabal install doctest - - run: cabal repl --with-ghc=doctest - - run: cabal test test:hedis-test - - run: cabal test test:redis7 - if: ${{ matrix.redis-version == 7}} diff --git a/cabal.haskell-ci b/cabal.haskell-ci new file mode 100644 index 00000000..b7f51720 --- /dev/null +++ b/cabal.haskell-ci @@ -0,0 +1,11 @@ +branches: master + +doctest: True +doctest-version: ^>=0.24 + +tests: True + +benchmarks: True + +-- Some tests don't pass. +run-tests: False diff --git a/cabal.project b/cabal.project index 63d50fe1..a2726932 100644 --- a/cabal.project +++ b/cabal.project @@ -1,7 +1,5 @@ packages: ./ -source-repository-package - type: git - location: https://github.com/scrive/pool - tag: eeabc8746d4fa68063551d81bf9fa330c3396845 +-- GHC 9.14 +allow-newer: *:base diff --git a/hedis.cabal b/hedis.cabal index debd9326..5880d612 100644 --- a/hedis.cabal +++ b/hedis.cabal @@ -1,3 +1,5 @@ +cabal-version: 3.0 +build-type: Simple name: hedis version: 7.1.0 synopsis: @@ -36,24 +38,17 @@ Description: . For detailed documentation, see the "Database.Redis" module. . -license: BSD3 +license: BSD-3-Clause license-file: LICENSE author: Falko Peters maintainer: Kostiantyn Rybnikov copyright: Copyright (c) 2011 Falko Peters category: Database -build-type: Simple -cabal-version: >=1.10 homepage: https://github.com/informatikr/hedis bug-reports: https://github.com/informatikr/hedis/issues extra-source-files: CHANGELOG -tested-with: - GHC ==9.12.2 - || ==9.10.2 - || ==9.8.4 - || ==9.6.7 - || ==9.4.8 +tested-with: GHC == { 9.6.7, 9.8.4, 9.10.3, 9.12.4, 9.14.1 } source-repository head type: git @@ -67,9 +62,7 @@ flag dev library default-language: Haskell2010 hs-source-dirs: src - ghc-options: -Wall -fwarn-tabs - if impl(ghc >= 8.6.0) - ghc-options: -Wno-warnings-deprecations + ghc-options: -Wall -Wcompat if impl(ghc >= 9.8) ghc-options: -Wno-x-partial if flag(dev) @@ -96,7 +89,7 @@ library , Database.Redis.URL build-depends: scanner >= 0.2, async >= 2.1, - base >= 4.8 && < 5, + base >= 4.18 && < 5, bytestring >= 0.9, bytestring-lexing >= 0.5, exceptions, diff --git a/src/Database/Redis/Cluster.hs b/src/Database/Redis/Cluster.hs index d9664987..727e15c3 100644 --- a/src/Database/Redis/Cluster.hs +++ b/src/Database/Redis/Cluster.hs @@ -31,7 +31,6 @@ import Database.Redis.Cluster.HashSlot(HashSlot, keyToSlot) import qualified Database.Redis.ConnectionContext as CC import qualified Data.HashMap.Strict as HM import qualified Data.IntMap.Strict as IntMap -import Data.Typeable import qualified Scanner import System.IO.Unsafe(unsafeInterleaveIO) @@ -93,13 +92,13 @@ data Shard = Shard MasterNode [SlaveNode] deriving (Show, Eq, Ord) newtype ShardMap = ShardMap (IntMap.IntMap Shard) deriving (Show) -newtype MissingNodeException = MissingNodeException [B.ByteString] deriving (Show, Typeable) +newtype MissingNodeException = MissingNodeException [B.ByteString] deriving (Show) instance Exception MissingNodeException -newtype UnsupportedClusterCommandException = UnsupportedClusterCommandException [B.ByteString] deriving (Show, Typeable) +newtype UnsupportedClusterCommandException = UnsupportedClusterCommandException [B.ByteString] deriving (Show) instance Exception UnsupportedClusterCommandException -newtype CrossSlotException = CrossSlotException [[B.ByteString]] deriving (Show, Typeable) +newtype CrossSlotException = CrossSlotException [[B.ByteString]] deriving (Show) instance Exception CrossSlotException connect :: [CMD.CommandInfo] -> MVar ShardMap -> Maybe Int -> Hooks -> IO Connection diff --git a/src/Database/Redis/Connection.hs b/src/Database/Redis/Connection.hs index 6efe1155..7d768a30 100644 --- a/src/Database/Redis/Connection.hs +++ b/src/Database/Redis/Connection.hs @@ -13,7 +13,6 @@ import qualified Data.ByteString.Char8 as Char8 import Data.Functor(void) import qualified Data.IntMap.Strict as IntMap import Data.Pool -import Data.Typeable import qualified Data.Time as Time import Network.TLS (ClientParams) import qualified Network.Socket as NS @@ -97,7 +96,7 @@ data ConnectInfo = ConnInfo data ConnectError = ConnectAuthError Reply | ConnectSelectError Reply - deriving (Eq, Show, Typeable) + deriving (Eq, Show) instance Exception ConnectError @@ -203,7 +202,7 @@ runRedis (ClusteredConnection _ pool) redis = withResource pool $ \conn -> runRedisClusteredInternal conn (refreshShardMap conn) redis newtype ClusterConnectError = ClusterConnectError Reply - deriving (Eq, Show, Typeable) + deriving (Eq, Show) instance Exception ClusterConnectError diff --git a/src/Database/Redis/ConnectionContext.hs b/src/Database/Redis/ConnectionContext.hs index b3794553..d1ce93cd 100644 --- a/src/Database/Redis/ConnectionContext.hs +++ b/src/Database/Redis/ConnectionContext.hs @@ -23,7 +23,6 @@ import qualified Data.ByteString.Lazy as LB import qualified Data.IORef as IOR import Control.Concurrent.MVar(newMVar, readMVar, swapMVar) import Control.Exception(bracketOnError, Exception, throwIO, try) -import Data.Typeable import Data.Functor(void) import qualified Network.Socket as NS import qualified Network.TLS as TLS @@ -51,7 +50,7 @@ data ConnectPhase deriving (Show) newtype ConnectTimeout = ConnectTimeout ConnectPhase - deriving (Show, Typeable) + deriving (Show) instance Exception ConnectTimeout diff --git a/src/Database/Redis/PubSub.hs b/src/Database/Redis/PubSub.hs index df449f68..afc2e59c 100644 --- a/src/Database/Redis/PubSub.hs +++ b/src/Database/Redis/PubSub.hs @@ -31,7 +31,7 @@ import Control.Monad import Control.Monad.Reader (asks) import Control.Monad.State import Data.ByteString.Char8 (ByteString) -import Data.List (foldl') +import qualified Data.List as L import Data.Maybe (isJust) import Data.Pool #if __GLASGOW_HASKELL__ < 808 @@ -435,8 +435,8 @@ removeChannels ctrl remChans remPChans = liftIO $ atomically $ do ps = (if null remChans' then mempty else unsubscribe remChans') `mappend` (if null remPChans' then mempty else punsubscribe remPChans') writeTBQueue (sendChanges ctrl) ps - writeTVar (callbacks ctrl) (foldl' (flip HM.delete) cm remChans') - writeTVar (pcallbacks ctrl) (foldl' (flip HM.delete) pm remPChans') + writeTVar (callbacks ctrl) (L.foldl' (flip HM.delete) cm remChans') + writeTVar (pcallbacks ctrl) (L.foldl' (flip HM.delete) pm remPChans') modifyTVar (pendingCnt ctrl) (+ totalPendingChanges ps) -- | Internal function to unsubscribe only from those channels matching the given handle. @@ -463,8 +463,8 @@ unsubChannels ctrl chans pchans h = liftIO $ atomically $ do Just v -> HM.insert k v m -- maps after taking out channels matching the handle - let cm' = foldl' removeHandles cm remChans - pm' = foldl' removeHandles pm remPChans + let cm' = L.foldl' removeHandles cm remChans + pm' = L.foldl' removeHandles pm remPChans -- the channels to unsubscribe are those that no longer exist in cm' and pm' let remChans' = filter (\n -> not $ HM.member n cm') remChans diff --git a/src/Database/Redis/Sentinel.hs b/src/Database/Redis/Sentinel.hs index 8c15b3c5..087dceb1 100644 --- a/src/Database/Redis/Sentinel.hs +++ b/src/Database/Redis/Sentinel.hs @@ -53,7 +53,6 @@ import qualified Data.ByteString.Char8 as BS8 import Data.Foldable (toList) import Data.List (delete) import Data.List.NonEmpty (NonEmpty (..)) -import Data.Typeable (Typeable) import Data.Unique import Network.Socket (HostName) @@ -217,6 +216,6 @@ data SentinelConnectInfo data RedisSentinelException = NoSentinels (NonEmpty (HostName, PortID)) -- ^ Thrown if no sentinel can be reached. - deriving (Show, Typeable) + deriving (Show) deriving instance Exception RedisSentinelException diff --git a/src/Database/Redis/URL.hs b/src/Database/Redis/URL.hs index 12f0aede..b990fdf6 100644 --- a/src/Database/Redis/URL.hs +++ b/src/Database/Redis/URL.hs @@ -36,7 +36,7 @@ import qualified Data.ByteString.Char8 as C8 -- The scheme is validated, to prevent mixing up configurations: -- -- >>> parseConnectInfo "postgres://" --- Left "Wrong scheme" +-- Left "Wrong scheme postgres:" -- -- Beyond that, all values are optional. Omitted values are taken from -- @'defaultConnectInfo'@: