git.iko.soy/typeable/rollbar-hs
on master help sign in
20 files changed+361−285
since splitsnapshots
unifiedsplit
.circleci/config.yml+14−48 .gitignore+1−2 CHANGELOG.md+5 Makefile+31−43 default.nix+21 golden/Item () (': Symbol "Authorization" ('[] Symbol)).faulty.json+5−5 golden/Item () (': Symbol "Authorization" ('[] Symbol)).json+5−5 package.yaml−47 rollbar-hs.cabal+93 shell.nix+44 src/Rollbar/Aeson.hs+22 src/Rollbar/Item.hs+8 src/Rollbar/Item/Body.hs+10−4 src/Rollbar/Item/MissingHeaders.hs+8−3 src/Rollbar/Item/Request.hs+12−2 src/Rollbar/Item/Server.hs+5 stack.yaml+3−63 test/Rollbar/Item/Data/Test.hs+10−9 test/Rollbar/Item/MissingHeaders/Test.hs+38−33 test/Rollbar/Item/Request/Test.hs+26−21
.circleci/config.yml+14−48
@@ -1,40 +1,26 @@
11version: 2
22jobs:
3− compile:
3+ ghc-8.2.2:
44 docker:
5− - image: haskell:8.2.2
5+ - image: nixorg/nix@sha256:96c3f56563a3b9549ac1da12ff7567c39cb6e648afd6a17d4a1a41f0596ad8f6
66 steps:
77 - checkout
88 - restore_cache:
99 keys:
10− - v1-stack-{{ checksum "package.yaml" }}-{{ checksum "stack.yaml" }}
11− - v1-stack-{{ checksum "package.yaml" }}-
12− - v1-stack-
13− name: Restoring stack cache
10+ - v2-nix-{{ checksum "package.yaml" }}
11+ - v2-nix-
12+ name: Restoring cache
1413 - run:
1514 name: Compile
16− command: make build
17− - persist_to_workspace:
18− root: .
19− paths:
20− - dist
15+ command: nix-shell --run 'make sdist test --jobs=2'
16+ environment:
17+ CABAL_BUILD_FLAGS: --jobs=2
2118 - save_cache:
22− key: v1-stack-{{ checksum "package.yaml" }}-{{ checksum "stack.yaml" }}
23− name: Caching stack
19+ key: v2-nix-{{ checksum "package.yaml" }}
20+ name: Caching nix
2421 paths:
25− - .stack-work
26− - /root/.stack
27−
28− doc-test:
29− docker:
30− - image: haskell:8.2.2
31− steps:
32− - checkout
33− - attach_workspace:
34− at: .
35− - run:
36− name: Doc test
37− command: make test-doc-test
22+ - /nix
23+ - dist
3824
3925 for-github:
4026 docker:
@@ -44,31 +30,11 @@ jobs:
4430 name: Passed
4531 command: echo passed
4632
47− sdist:
48− docker:
49− - image: haskell:8.2.2
50− steps:
51− - checkout
52− - restore_cache:
53− keys:
54− - v1-stack-{{ checksum "package.yaml" }}-{{ checksum "stack.yaml" }}
55− - v1-stack-{{ checksum "package.yaml" }}-
56− - v1-stack-
57− name: Restoring stack cache
58− - run:
59− name: Build sdist
60− command: make sdist
61−
6233workflows:
6334 version: 2
6435 base:
6536 jobs:
66− - compile
6737 - for-github:
6838 requires:
69− - doc-test
70− - sdist
71− - sdist
72− - doc-test:
73− requires:
74− - compile
39+ - ghc-8.2.2
40+ - ghc-8.2.2
.gitignore+1−2
@@ -1,6 +1,5 @@
11### Project specific ###
22
3−*.cabal
43.make
54bin
65
@@ -186,4 +185,4 @@ $RECYCLE.BIN/
186185*.lnk
187186
188187
189−# End of https://www.gitignore.io/api/vim,osx,linux,macos,emacs,windows,haskell,visualstudiocode
188+# End of https://www.gitignore.io/api/vim,osx,linux,macos,emacs,windows,haskell,visualstudiocode
CHANGELOG.md+5
@@ -1,5 +1,10 @@
11# Changelog
22
3+## 0.3.1.0
4+
5+* [Drop some test dependencies](https://github.com/joneshf/rollbar-hs/pull/12)
6+* [Relax upper bound for `network` to 2.8](https://github.com/joneshf/rollbar-hs/pull/14)
7+
38## 0.3.0.1
49
510* [Add a changelog](https://github.com/joneshf/rollbar-hs/pull/10)
Makefile+31−43
@@ -1,64 +1,52 @@
1−BIN ?= bin
21CABAL ?= cabal
2+CABAL_FLAGS ?=
3+CABAL_BUILD_FLAGS ?=
34DIST ?= dist
4−EMPTY ?= .make
5−PROJECT_NAME ?= rollbar-hs
6−STACK ?= stack
7−STACK_WORK ?= .stack-work
8−VERBOSITY ?= warn
5+GHCID ?= ghcid
6+GHCID_FLAGS ?= --ghc-options=-fno-code
7+HPACK ?= hpack
8+NIX_SHELL ?= nix-shell
9+NIX_SHELL_FLAGS ?=
10+PROJECT_NAME := rollbar-hs
911
1012CABAL_FILE := $(PROJECT_NAME).cabal
13+CONFIGURE := $(DIST)/setup-config
1114DOC_TEST := $(DIST)/build/doc-test/doc-test
12−GHCID := $(BIN)/ghcid
13−STACK_FLAGS := --verbosity $(VERBOSITY)
1415
1516.DEFAULT_GOAL := build
1617
17−$(BIN) $(DIST) $(EMPTY):
18− mkdir -p $@
19−
2018$(CABAL_FILE): package.yaml
21− # `stack` has no way to run `hpack` directly.
22− # We can run `hpack` indirectly with little overhead.
23− $(STACK) $(STACK_FLAGS) build --dry-run
24−
25−$(DOC_TEST):
26− rm -f $(EMPTY)/build
27− $(MAKE) $(EMPTY)/build
28−
29−$(EMPTY)/build: $(EMPTY)/stack-setup README.md Setup.hs package.yaml stack.yaml src/**/*.hs test/**/*.hs | $(DIST)
30− $(STACK) $(STACK_FLAGS) build --no-run-tests --test
31− cp -R $$($(STACK) $(STACK_FLAGS) path --dist-dir)/build $(DIST)
32− touch $@
19+ $(HPACK)
3320
34−$(EMPTY)/stack-setup: | $(EMPTY)
35− $(STACK) $(STACK_FLAGS) setup
36− touch $@
21+$(CONFIGURE): $(CABAL_FILE)
22+ $(CABAL) $(CABAL_FLAGS) configure --enable-tests
3723
38−$(GHCID): $(EMPTY)/stack-setup | $(BIN)
39− $(STACK) $(STACK_FLAGS) install ghcid --local-bin-path $(BIN)
24+.PHONY: build
25+build $(DOC_TEST): $(CONFIGURE) default.nix
26+ $(CABAL) $(CABAL_FLAGS) build $(CABAL_BUILD_FLAGS)
4027
41−.PHONT: build
42−build: $(EMPTY)/build
43−
44−.PHONY: cabal-check
45−cabal-check: $(CABAL_FILE)
46− $(CABAL) check
28+.PHONY: check
29+check: $(CABAL_FILE)
30+ $(CABAL) $(CABAL_FLAGS) check
4731
4832.PHONY: clean
4933clean:
5034 rm -f $(CABAL_FILE)
51− rm -fr $(BIN)
5235 rm -fr $(DIST)
53− rm -fr $(EMPTY)
54− rm -fr $(STACK_WORK)
36+
37+default.nix: $(CABAL_FILE)
38+ cabal2nix . > $@
5539
5640.PHONY: sdist
57−sdist: cabal-check | $(DIST)
58− $(CABAL) sdist
41+sdist: check
42+ $(CABAL) $(CABAL_FLAGS) sdist
43+
44+.PHONY: shell
45+shell:
46+ $(NIX_SHELL) --pure $(NIX_SHELL_FLAGS)
5947
6048.PHONY: test
61−test: $(EMPTY)/build test-doc-test
49+test: test-doc-test
6250
6351.PHONY: test-doc-test
6452test-doc-test: $(DOC_TEST)
@@ -66,8 +54,8 @@ test-doc-test: $(DOC_TEST)
6654
6755.PHONY: upload-hackage
6856upload-hackage: sdist
69− @ $(CABAL) upload $(DIST)/$(PROJECT_NAME)-*.tar.gz
57+ @ $(CABAL) $(CABAL_FLAGS) upload $(DIST)/$(PROJECT_NAME)-*.tar.gz
7058
7159.PHONY: watch
72−watch: $(GHCID)
73− $(GHCID)
60+watch: $(CONFIGURE)
61+ $(GHCID) --command "cabal repl lib:$(PROJECT_NAME) $(GHCID_FLAGS)"
default.nixnew file+21
@@ -0,0 +1,21 @@
1+{ mkDerivation, aeson, base, bytestring, case-insensitive, hostname
2+, hspec, hspec-golden-aeson, http-client, http-conduit, http-types
3+, network, QuickCheck, stdenv, text, time, unordered-containers
4+, uuid
5+}:
6+mkDerivation {
7+ pname = "rollbar-hs";
8+ version = "0.3.1.0";
9+ src = ./.;
10+ libraryHaskellDepends = [
11+ aeson base bytestring case-insensitive hostname http-client
12+ http-conduit http-types network text time unordered-containers uuid
13+ ];
14+ testHaskellDepends = [
15+ aeson base bytestring case-insensitive hspec hspec-golden-aeson
16+ QuickCheck text unordered-containers
17+ ];
18+ homepage = "https://github.com/joneshf/rollbar-hs#readme";
19+ description = "Core Rollbar data types and APIs";
20+ license = stdenv.lib.licenses.bsd3;
21+}
golden/Item () (': Symbol "Authorization" ('[] Symbol)).faulty.json+5−5
@@ -5,7 +5,7 @@
55 "data": {
66 "notifier": {
77 "name": "rollbar-hs",
8− "version": "0.3.0.1"
8+ "version": "0.3.1.0"
99 },
1010 "platform": "linux",
1111 "environment": "HB\u0010BuQ\u0017\u00064d*HE\u000b9\u0019\u001b*\u000e\u0013",
@@ -24,7 +24,7 @@
2424 "data": {
2525 "notifier": {
2626 "name": "rollbar-hs",
27− "version": "0.3.0.1"
27+ "version": "0.3.1.0"
2828 },
2929 "platform": "linux",
3030 "environment": "\u001dGesd@(b)ppm/Z",
@@ -43,7 +43,7 @@
4343 "data": {
4444 "notifier": {
4545 "name": "rollbar-hs",
46− "version": "0.3.0.1"
46+ "version": "0.3.1.0"
4747 },
4848 "platform": "linux",
4949 "environment": "/dt",
@@ -62,7 +62,7 @@
6262 "data": {
6363 "notifier": {
6464 "name": "rollbar-hs",
65− "version": "0.3.0.1"
65+ "version": "0.3.1.0"
6666 },
6767 "platform": "linux",
6868 "environment": "\u0003+(up!I",
@@ -81,7 +81,7 @@
8181 "data": {
8282 "notifier": {
8383 "name": "rollbar-hs",
84− "version": "0.3.0.1"
84+ "version": "0.3.1.0"
8585 },
8686 "platform": "linux",
8787 "environment": "V\u001csj\u001edR`T4?\u000eJ\u000cf",
golden/Item () (': Symbol "Authorization" ('[] Symbol)).json+5−5
@@ -5,7 +5,7 @@
55 "data": {
66 "notifier": {
77 "name": "rollbar-hs",
8− "version": "0.3.0.1"
8+ "version": "0.3.1.0"
99 },
1010 "platform": "linux",
1111 "environment": "HB\u0010BuQ\u0017\u00064d*HE\u000b9\u0019\u001b*\u000e\u0013",
@@ -24,7 +24,7 @@
2424 "data": {
2525 "notifier": {
2626 "name": "rollbar-hs",
27− "version": "0.3.0.1"
27+ "version": "0.3.1.0"
2828 },
2929 "platform": "linux",
3030 "environment": "\u001dGesd@(b)ppm/Z",
@@ -43,7 +43,7 @@
4343 "data": {
4444 "notifier": {
4545 "name": "rollbar-hs",
46− "version": "0.3.0.1"
46+ "version": "0.3.1.0"
4747 },
4848 "platform": "linux",
4949 "environment": "/dt",
@@ -62,7 +62,7 @@
6262 "data": {
6363 "notifier": {
6464 "name": "rollbar-hs",
65− "version": "0.3.0.1"
65+ "version": "0.3.1.0"
6666 },
6767 "platform": "linux",
6868 "environment": "\u0003+(up!I",
@@ -81,7 +81,7 @@
8181 "data": {
8282 "notifier": {
8383 "name": "rollbar-hs",
84− "version": "0.3.0.1"
84+ "version": "0.3.1.0"
8585 },
8686 "platform": "linux",
8787 "environment": "V\u001csj\u001edR`T4?\u000eJ\u000cf",
package.yamldeleted−47
@@ -1,47 +0,0 @@
1−author: Hardy Jones
2−category: Web
3−copyright: 2018 Hardy Jones
4−description: |
5− Provides a type-safe encoding of the Rollbar API.
6− Also provides functions to communicate with the Rollbar API.
7−extra-source-files:
8− - CHANGELOG.md
9− - README.md
10−github: joneshf/rollbar-hs
11−library:
12− dependencies:
13− - aeson >= 1.0 && < 1.5
14− - base >= 4.9 && < 5
15− - bytestring >= 0.10 && < 0.11
16− - case-insensitive >= 1.2 && < 1.3
17− - hostname >= 1.0 && < 1.1
18− - http-client >= 0.5 && < 0.6
19− - http-conduit >= 2.2 && < 2.4
20− - http-types >= 0.9 && < 0.13
21− - network >= 2.6 && < 2.7
22− - text >= 1.2 && < 1.3
23− - time >= 1.6 && < 1.9
24− - unordered-containers >= 0.2 && < 0.3
25− - uuid >= 1.3 && < 1.4
26− source-dirs: src
27−license: BSD3
28−maintainer: jones3.hardy@gmail.com
29−name: rollbar-hs
30−synopsis: Core Rollbar data types and APIs.
31−tests:
32− doc-test:
33− dependencies:
34− - QuickCheck >= 2.9
35− - aeson >= 1.0
36− - base >= 4.9
37− - bytestring >= 0.10
38− - case-insensitive >= 1.2
39− - containers >= 0.5
40− - hspec >= 2.4
41− - hspec-golden-aeson >= 0.2
42− - rollbar-hs
43− - text >= 1.2
44− - unordered-containers >= 0.2
45− main: Main.hs
46− source-dirs: test
47−version: '0.3.0.1'
rollbar-hs.cabalnew file+93
@@ -0,0 +1,93 @@
1+cabal-version: 1.12
2+
3+-- This file has been generated from package.yaml by hpack version 0.31.2.
4+--
5+-- see: https://github.com/sol/hpack
6+--
7+-- hash: ac4c551193d60902c95f89512121ee67cb0cafb3a6662796e40323bd0cedff7c
8+
9+name: rollbar-hs
10+version: 0.3.1.0
11+synopsis: Core Rollbar data types and APIs.
12+description: Provides a type-safe encoding of the Rollbar API.
13+ Also provides functions to communicate with the Rollbar API.
14+category: Web
15+homepage: https://github.com/joneshf/rollbar-hs#readme
16+bug-reports: https://github.com/joneshf/rollbar-hs/issues
17+author: Hardy Jones
18+maintainer: jones3.hardy@gmail.com
19+copyright: 2018 Hardy Jones
20+license: BSD3
21+license-file: LICENSE
22+build-type: Simple
23+extra-source-files:
24+ CHANGELOG.md
25+ README.md
26+
27+source-repository head
28+ type: git
29+ location: https://github.com/joneshf/rollbar-hs
30+
31+library
32+ exposed-modules:
33+ Rollbar.AccessToken
34+ Rollbar.API
35+ Rollbar.Item
36+ Rollbar.Item.Body
37+ Rollbar.Item.CodeVersion
38+ Rollbar.Item.Data
39+ Rollbar.Item.Environment
40+ Rollbar.Item.Hardcoded
41+ Rollbar.Item.Internal.Notifier
42+ Rollbar.Item.Internal.Platform
43+ Rollbar.Item.Level
44+ Rollbar.Item.MissingHeaders
45+ Rollbar.Item.Person
46+ Rollbar.Item.Request
47+ Rollbar.Item.Server
48+ Rollbar.Aeson
49+ other-modules:
50+ Paths_rollbar_hs
51+ hs-source-dirs:
52+ src
53+ build-depends:
54+ aeson >=1.1
55+ , base >=4.9
56+ , bytestring >=0.10
57+ , case-insensitive >=1.2
58+ , hostname >=1.0
59+ , http-client >=0.5
60+ , http-conduit >=2.2
61+ , http-types >=0.8.6
62+ , network >=2.6.3
63+ , text >=1.2
64+ , time >=1.6
65+ , unordered-containers >=0.2
66+ , uuid >=1.3
67+ default-language: Haskell2010
68+
69+test-suite doc-test
70+ type: exitcode-stdio-1.0
71+ main-is: Main.hs
72+ other-modules:
73+ Rollbar.Golden
74+ Rollbar.Item.Data.Test
75+ Rollbar.Item.MissingHeaders.Test
76+ Rollbar.Item.Request.Test
77+ Rollbar.QuickCheck
78+ Paths_rollbar_hs
79+ hs-source-dirs:
80+ test
81+ build-depends:
82+ QuickCheck >=2.9
83+ , aeson
84+ , base
85+ , bytestring
86+ , case-insensitive
87+ , hashable
88+ , hspec >=2.4
89+ , hspec-golden-aeson >=0.2
90+ , rollbar-hs
91+ , text
92+ , unordered-containers
93+ default-language: Haskell2010
shell.nixnew file+44
@@ -0,0 +1,44 @@
1+{ compiler ? "ghc822" }:
2+
3+let
4+
5+ default = haskell-packages.callPackage (import ./default.nix) {};
6+
7+ derivation = nixpkgs.haskell.lib.addBuildTools default tools;
8+
9+ haskell-packages = nixpkgs.haskell.packages.${compiler};
10+
11+ nixpkgs = import nixpkgs-tarball {};
12+
13+ nixpkgs-revision = "120b013e0c082d58a5712cde0a7371ae8b25a601";
14+
15+ nixpkgs-sha256 = "0hk4y2vkgm1qadpsm4b0q1vxq889jhxzjx3ragybrlwwg54mzp4f";
16+
17+ nixpkgs-tarball = builtins.fetchTarball {
18+ sha256 = nixpkgs-sha256;
19+ url = "https://github.com/NixOS/nixpkgs/archive/${nixpkgs-revision}.tar.gz";
20+ };
21+
22+ # Tools affected by the compiler version.
23+ tools-compiler = [
24+ haskell-packages.cabal-install
25+ haskell-packages.ghc
26+ haskell-packages.ghcid
27+ haskell-packages.hpack
28+ ];
29+
30+ # Tools that deal with the basic project infrastructure.
31+ tools-infrastructure = [
32+ nixpkgs.cabal2nix
33+ nixpkgs.curl
34+ nixpkgs.which
35+ ];
36+
37+ # All of the tools.
38+ tools =
39+ tools-compiler ++
40+ tools-infrastructure;
41+
42+in
43+
44+ derivation.env
src/Rollbar/Aeson.hsnew file+22
@@ -0,0 +1,22 @@
1+{-# LANGUAGE CPP #-}
2+
3+module Rollbar.Aeson
4+ ( Key
5+ , textToKey
6+ ) where
7+
8+import Data.Text (Text)
9+#if MIN_VERSION_aeson(2,0,0)
10+import Data.Aeson.Key (Key)
11+import qualified Data.Aeson.Key as Key
12+#else
13+#endif
14+
15+#if MIN_VERSION_aeson(2,0,0)
16+textToKey :: Text -> Key
17+textToKey = Key.fromText
18+#else
19+type Key = Text
20+textToKey :: Text -> Key
21+textToKey = id
22+#endif
src/Rollbar/Item.hs+8
@@ -1,3 +1,4 @@
1+{-# LANGUAGE CPP #-}
12{-# LANGUAGE DataKinds #-}
23{-# LANGUAGE DeriveGeneric #-}
34{-# LANGUAGE NamedFieldPuns #-}
@@ -197,10 +198,17 @@ data Item a headers
197198 }
198199 deriving (Eq, Generic, Show)
199200
201+#if MIN_VERSION_aeson(2, 2, 0)
202+itemKVs
203+ :: (KeyValue e kv, RemoveHeaders headers, ToJSON v)
204+ => Item v headers
205+ -> [kv]
206+#else
200207itemKVs
201208 :: (KeyValue kv, RemoveHeaders headers, ToJSON v)
202209 => Item v headers
203210 -> [kv]
211+#endif
204212itemKVs Item{accessToken, itemData} =
205213 [ "access_token" .= accessToken
206214 , "data" .= itemData
src/Rollbar/Item/Body.hs+10−4
@@ -1,3 +1,4 @@
1+{-# LANGUAGE CPP #-}
12{-# LANGUAGE DeriveGeneric #-}
23{-# LANGUAGE GeneralizedNewtypeDeriving #-}
34{-# LANGUAGE NamedFieldPuns #-}
@@ -33,7 +34,7 @@ import Data.Aeson
3334 , (.=)
3435 )
3536import Data.Aeson.Encoding (pair)
36−import Data.Aeson.Types (typeMismatch)
37+import Data.Aeson.Types (explicitParseField, typeMismatch)
3738import Data.String (IsString)
3839
3940import GHC.Generics (Generic)
@@ -52,16 +53,21 @@ data Body arbitrary
5253 }
5354 deriving (Eq, Generic, Show)
5455
56+#if MIN_VERSION_aeson(2, 2, 0)
57+bodyKVs :: (KeyValue e kv, ToJSON v) => Body v -> [kv]
58+#else
5559bodyKVs :: (KeyValue kv, ToJSON v) => Body v -> [kv]
60+#endif
5661bodyKVs Message{messageBody, messageData} =
5762 [ "body" .= messageBody
5863 , "data" .= messageData
5964 ]
6065
6166instance FromJSON arbitrary => FromJSON (Body arbitrary) where
62− parseJSON (Object o') = do
63− o <- o' .: "message"
64− Message <$> o .: "body" <*> o .: "data"
67+ parseJSON (Object o') = explicitParseField parseMessage o' "message"
68+ where
69+ parseMessage (Object o) = Message <$> o .: "body" <*> o .: "data"
70+ parseMessage v = typeMismatch "Body arbitrary (message)" v
6571 parseJSON v = typeMismatch "Body arbitrary" v
6672
6773instance ToJSON arbitrary => ToJSON (Body arbitrary) where
src/Rollbar/Item/MissingHeaders.hs+8−3
@@ -3,6 +3,7 @@
33{-# LANGUAGE KindSignatures #-}
44{-# LANGUAGE ScopedTypeVariables #-}
55{-# LANGUAGE TypeOperators #-}
6+{-# LANGUAGE CPP #-}
67
78{-|
89 Module : Rollbar.Item.MissingHeaders
@@ -20,6 +21,7 @@ module Rollbar.Item.MissingHeaders
2021
2122import Data.Aeson
2223 (FromJSON, KeyValue, ToJSON, object, parseJSON, toJSON, (.=))
24+import Rollbar.Aeson
2325import Data.Bifunctor (bimap)
2426import Data.CaseInsensitive (mk, original)
2527import Data.Maybe (catMaybes)
@@ -31,7 +33,6 @@ import Network.HTTP.Types (Header, RequestHeaders)
3133
3234import qualified Data.ByteString as BS
3335import qualified Data.ByteString.Char8 as BSC8
34−import qualified Data.Text as T
3536import qualified Data.Text.Encoding as TE
3637
3738-- | The request headers with some missing
@@ -63,7 +64,11 @@ instance FromJSON (MissingHeaders headers) where
6364instance RemoveHeaders headers => ToJSON (MissingHeaders headers) where
6465 toJSON = object . catMaybes . requestHeadersKVs . removeHeaders
6566
67+#if MIN_VERSION_aeson(2, 2, 0)
68+requestHeadersKVs :: forall e kv. KeyValue e kv => RequestHeaders -> [Maybe kv]
69+#else
6670requestHeadersKVs :: forall kv. KeyValue kv => RequestHeaders -> [Maybe kv]
71+#endif
6772requestHeadersKVs = fmap go
6873 where
6974 go :: Header -> Maybe kv
@@ -72,5 +77,5 @@ requestHeadersKVs = fmap go
7277 val <- myDecodeUtf8 val'
7378 pure (key .= val)
7479
75−myDecodeUtf8 :: BS.ByteString -> Maybe T.Text
76−myDecodeUtf8 = either (const Nothing) Just . TE.decodeUtf8'
80+myDecodeUtf8 :: BS.ByteString -> Maybe Key
81+myDecodeUtf8 = either (const Nothing) (Just . textToKey) . TE.decodeUtf8'
src/Rollbar/Item/Request.hs+12−2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE CPP #-}
12{-# LANGUAGE DeriveGeneric #-}
23{-# LANGUAGE GeneralizedNewtypeDeriving #-}
34{-# LANGUAGE NamedFieldPuns #-}
@@ -48,6 +49,7 @@ import GHC.Generics (Generic)
4849import Network.HTTP.Types (Query)
4950import Network.Socket (SockAddr(SockAddrInet), tupleToHostAddress)
5051
52+import Rollbar.Aeson
5153import Rollbar.Item.MissingHeaders
5254
5355import Text.Read (readMaybe)
@@ -96,14 +98,18 @@ instance ToJSON Get where
9698 toJSON (Get q) = object . catMaybes . queryKVs $ q
9799 toEncoding (Get q) = pairs . mconcat . catMaybes . queryKVs $ q
98100
99−queryKVs :: forall kv. (KeyValue kv) => Query -> [Maybe kv]
101+#if MIN_VERSION_aeson(2, 2, 0)
102+queryKVs :: forall e kv. KeyValue e kv => Query -> [Maybe kv]
103+#else
104+queryKVs :: forall kv. KeyValue kv => Query -> [Maybe kv]
105+#endif
100106queryKVs = fmap go
101107 where
102108 go :: (BS.ByteString, Maybe BS.ByteString) -> Maybe kv
103109 go (key', val') = do
104110 key <- myDecodeUtf8 key'
105111 let val = val' >>= myDecodeUtf8
106− pure (key .= val)
112+ pure (textToKey key .= val)
107113
108114-- | The HTTP Verb
109115newtype Method
@@ -149,7 +155,11 @@ instance ToJSON IP where
149155 toJSON (IP ip) = toJSON (show ip)
150156 toEncoding (IP ip) = toEncoding (show ip)
151157
158+#if MIN_VERSION_aeson(2, 2, 0)
159+requestKVs :: (KeyValue e kv, RemoveHeaders headers) => Request headers -> [kv]
160+#else
152161requestKVs :: (KeyValue kv, RemoveHeaders headers) => Request headers -> [kv]
162+#endif
153163requestKVs Request{get, headers, method, queryString, rawBody, url, userIP} =
154164 [ "body" .= rawBody
155165 , "GET" .= get
src/Rollbar/Item/Server.hs+5
@@ -1,3 +1,4 @@
1+{-# LANGUAGE CPP #-}
12{-# LANGUAGE DeriveGeneric #-}
23{-# LANGUAGE GeneralizedNewtypeDeriving #-}
34{-# LANGUAGE NamedFieldPuns #-}
@@ -57,7 +58,11 @@ data Server
5758 }
5859 deriving (Eq, Generic, Show)
5960
61+#if MIN_VERSION_aeson(2, 2, 0)
62+serverKVs :: KeyValue e kv => Server -> [Maybe kv]
63+#else
6064serverKVs :: KeyValue kv => Server -> [Maybe kv]
65+#endif
6166serverKVs Server{branch, host, root, serverCodeVersion} =
6267 [ ("host" .=) <$> host
6368 , ("root" .=) <$> root
stack.yaml+3−63
@@ -1,66 +1,6 @@
1−# This file was automatically generated by 'stack init'
2−#
3−# Some commonly used options have been documented as comments in this file.
4−# For advanced use and comprehensive documentation of the format, please see:
5−# https://docs.haskellstack.org/en/stable/yaml_configuration/
6−
7−# Resolver to choose a 'specific' stackage snapshot or a compiler version.
8−# A snapshot resolver dictates the compiler version and the set of packages
9−# to be used for project dependencies. For example:
10−#
11−# resolver: lts-3.5
12−# resolver: nightly-2015-09-21
13−# resolver: ghc-7.10.2
14−# resolver: ghcjs-0.1.0_ghc-7.10.2
15−# resolver:
16−# name: custom-snapshot
17−# location: "./custom-snapshot.yaml"
18−resolver: lts-10.5
19−
20−# User packages to be built.
21−# Various formats can be used as shown in the example below.
22−#
23−# packages:
24−# - some-directory
25−# - https://example.com/foo/bar/baz-0.0.2.tar.gz
26−# - location:
27−# git: https://github.com/commercialhaskell/stack.git
28−# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a
29−# - location: https://github.com/commercialhaskell/stack/commit/e7b331f14bcffb8367cd58fbfc8b40ec7642100a
30−# extra-dep: true
31−# subdirs:
32−# - auto-update
33−# - wai
34−#
35−# A package marked 'extra-dep: true' will only be built if demanded by a
36−# non-dependency (i.e. a user package), and its test suites and benchmarks
37−# will not be run. This is useful for tweaking upstream packages.
1+resolver: lts-23.7
382packages:
393- .
40−# Dependency packages to be pulled from upstream that are not in the resolver
41−# (e.g., acme-missiles-0.3)
42−# extra-deps: []
43−
44−# Override default flag values for local packages and extra-deps
45−# flags: {}
46−
47−# Extra package databases containing global packages
48−# extra-package-dbs: []
494
50−# Control whether we use the GHC we find on the path
51−# system-ghc: true
52−#
53−# Require a specific version of stack, using version ranges
54−# require-stack-version: -any # Default
55−# require-stack-version: ">=1.6"
56−#
57−# Override the architecture used by stack, especially useful on Windows
58−# arch: i386
59−# arch: x86_64
60−#
61−# Extra directories used by stack for building
62−# extra-include-dirs: [/path/to/dir]
63−# extra-lib-dirs: [/path/to/dir]
64−#
65−# Allow a newer minor version of GHC than the snapshot specifies
66−# compiler-check: newer-minor
5+nix:
6+ packages: [ zlib ]
test/Rollbar/Item/Data/Test.hs+10−9
@@ -1,15 +1,16 @@
1−{-# LANGUAGE DataKinds #-}
2−{-# LANGUAGE LambdaCase #-}
1+{-# LANGUAGE DataKinds #-}
2+{-# LANGUAGE LambdaCase #-}
33{-# LANGUAGE OverloadedStrings #-}
44module Rollbar.Item.Data.Test where
55
6−import Data.Aeson (Value(Null, Object), decode', encode, toJSON)
7−import Data.Text (Text)
6+import Data.Aeson (Value (Null, Object), decode', encode,
7+ toJSON)
8+import Data.Text (Text)
89
9−import Rollbar.Item
10−import Rollbar.QuickCheck ()
10+import Rollbar.Item
11+import Rollbar.QuickCheck ()
1112
12−import Test.QuickCheck (conjoin, quickCheck)
13+import Test.QuickCheck (conjoin, quickCheck)
1314
1415import qualified Data.HashMap.Strict
1516
@@ -38,6 +39,6 @@ requiredBodyKeys = ["trace", "trace_chain", "message", "crash_report"]
3839key :: Text -> Value -> [(Text, Value)]
3940key k = \case
4041 Object o -> case Data.HashMap.Strict.lookupDefault Null k o of
41− Object o -> Data.HashMap.Strict.toList o
42− _ -> mempty
42+ Object o' -> Data.HashMap.Strict.toList o'
43+ _ -> mempty
4344 _ -> mempty
test/Rollbar/Item/MissingHeaders/Test.hs+38−33
@@ -1,24 +1,26 @@
1−{-# LANGUAGE DataKinds #-}
2−{-# LANGUAGE FlexibleContexts #-}
1+{-# LANGUAGE DataKinds #-}
2+{-# LANGUAGE FlexibleContexts #-}
33{-# LANGUAGE FlexibleInstances #-}
4−{-# LANGUAGE LambdaCase #-}
4+{-# LANGUAGE LambdaCase #-}
55{-# LANGUAGE OverloadedStrings #-}
6−{-# LANGUAGE TypeOperators #-}
6+{-# LANGUAGE TypeOperators #-}
77module Rollbar.Item.MissingHeaders.Test where
88
9−import Data.Aeson (Value(Object), decode', encode, toJSON)
10−import Data.Text (Text)
9+import Data.Aeson (Value (Object), decode', encode,
10+ toJSON)
11+import Data.Functor (void)
12+import Data.Hashable
13+import Data.HashSet (HashSet)
14+import Data.Text (Text)
1115
12−import Prelude hiding (error)
16+import Prelude hiding (error)
1317
14−import Rollbar.Item.MissingHeaders (MissingHeaders(..))
15−import Rollbar.QuickCheck ()
18+import Rollbar.Item.MissingHeaders (MissingHeaders (..))
19+import Rollbar.QuickCheck ()
1620
17−import Test.QuickCheck (conjoin, quickCheck)
21+import Test.QuickCheck (conjoin, quickCheck)
1822
19−import Data.Set as S
20−
21−import qualified Data.HashMap.Strict
23+import qualified Data.HashSet
2224
2325props :: IO ()
2426props = do
@@ -39,53 +41,56 @@ props = do
3941
4042prop_valueAuthorizationIsRemoved :: MissingHeaders '["Authorization"] -> Bool
4143prop_valueAuthorizationIsRemoved hs =
42− "Authorization" `S.notMember` actual
44+ "Authorization" `notMember` actual
4345 where
44− actual = S.fromList (keys $ toJSON hs)
46+ actual = keys (toJSON hs)
4547
4648prop_encodingAuthorizationIsRemoved :: MissingHeaders '["Authorization"] -> Bool
4749prop_encodingAuthorizationIsRemoved hs =
48− "Authorization" `S.notMember` actual
50+ "Authorization" `notMember` actual
4951 where
50− actual = S.fromList (foldMap keys $ decode' $ encode hs)
52+ actual = foldMap keys (decode' $ encode hs)
5153
5254prop_valueX_AccessTokenIsRemoved :: MissingHeaders '["X-AccessToken"] -> Bool
5355prop_valueX_AccessTokenIsRemoved hs =
54− "X-AccessToken" `S.notMember` actual
56+ "X-AccessToken" `notMember` actual
5557 where
56− actual = S.fromList (keys $ toJSON hs)
58+ actual = keys (toJSON hs)
5759
5860prop_encodingX_AccessTokenIsRemoved :: MissingHeaders '["X-AccessToken"] -> Bool
5961prop_encodingX_AccessTokenIsRemoved hs =
60− "X-AccessToken" `S.notMember` actual
62+ "X-AccessToken" `notMember` actual
6163 where
62− actual = S.fromList (foldMap keys $ decode' $ encode hs)
64+ actual = foldMap keys (decode' $ encode hs)
6365
6466prop_valueAllHeadersAreRemoved
6567 :: MissingHeaders
6668 '["Authorization", "this is made up", "Server", "X-AccessToken"]
6769 -> Bool
6870prop_valueAllHeadersAreRemoved hs =
69− "Authorization" `S.notMember` actual
70− && "this is made up" `S.notMember` actual
71− && "Server" `S.notMember` actual
72− && "X-AccessToken" `S.notMember` actual
71+ "Authorization" `notMember` actual
72+ && "this is made up" `notMember` actual
73+ && "Server" `notMember` actual
74+ && "X-AccessToken" `notMember` actual
7375 where
74− actual = S.fromList (keys $ toJSON hs)
76+ actual = keys (toJSON hs)
7577
7678prop_encodingAllHeadersAreRemoved
7779 :: MissingHeaders
7880 '["Authorization", "this is made up", "Server", "X-AccessToken"]
7981 -> Bool
8082prop_encodingAllHeadersAreRemoved hs =
81− "Authorization" `S.notMember` actual
82− && "this is made up" `S.notMember` actual
83− && "Server" `S.notMember` actual
84− && "X-AccessToken" `S.notMember` actual
83+ "Authorization" `notMember` actual
84+ && "this is made up" `notMember` actual
85+ && "Server" `notMember` actual
86+ && "X-AccessToken" `notMember` actual
8587 where
86− actual = S.fromList (foldMap keys $ decode' $ encode hs)
88+ actual = foldMap keys (decode' $ encode hs)
8789
88−keys :: Value -> [Text]
90+keys :: Value -> HashSet Text
8991keys = \case
90− Object o -> Data.HashMap.Strict.keys o
92+ Object o -> Data.HashSet.fromMap (void o)
9193 _ -> mempty
94+
95+notMember :: (Eq a, Hashable a) => a -> HashSet a -> Bool
96+notMember x = not . Data.HashSet.member x
test/Rollbar/Item/Request/Test.hs+26−21
@@ -1,25 +1,27 @@
1−{-# LANGUAGE DataKinds #-}
1+{-# LANGUAGE DataKinds #-}
22{-# LANGUAGE FlexibleInstances #-}
3−{-# LANGUAGE LambdaCase #-}
3+{-# LANGUAGE LambdaCase #-}
44{-# LANGUAGE OverloadedStrings #-}
5−{-# LANGUAGE TypeOperators #-}
5+{-# LANGUAGE TypeOperators #-}
66module Rollbar.Item.Request.Test where
77
8−import Data.Aeson (Value(Object), decode', encode, toJSON)
9−import Data.CaseInsensitive (original)
10−import Data.Text (Text)
8+import Data.Aeson (Value (Object), decode', encode, toJSON)
9+import Data.CaseInsensitive (original)
10+import Data.Foldable (fold)
11+import Data.Functor (void)
12+import Data.HashSet (HashSet)
13+import Data.Text (Text)
1114
12−import Prelude hiding (error)
15+import Prelude hiding (error)
1316
14−import Rollbar.Item.Request (MissingHeaders(..))
15−import Rollbar.QuickCheck ()
17+import Rollbar.Item.Request (MissingHeaders (..))
18+import Rollbar.QuickCheck ()
1619
17−import Test.QuickCheck (conjoin, quickCheck)
20+import Test.QuickCheck (conjoin, quickCheck)
1821
19−import Data.Set as S
20−import Data.Text.Encoding as TE
22+import qualified Data.Text.Encoding as TE
2123
22−import qualified Data.HashMap.Strict
24+import qualified Data.HashSet
2325
2426props :: IO ()
2527props =
@@ -30,19 +32,22 @@ props =
3032
3133prop_valueHeadersArentWrapped :: MissingHeaders '["Authorization"] -> Bool
3234prop_valueHeadersArentWrapped hs@(MissingHeaders rhs) =
33− actual `S.isSubsetOf` expected
35+ actual `isSubsetOf` expected
3436 where
35− actual = S.fromList (keys $ toJSON hs)
36− expected = S.fromList $ either (const "") id . TE.decodeUtf8' . original . fst <$> rhs
37+ actual = keys (toJSON hs)
38+ expected = Data.HashSet.fromList $ fold . TE.decodeUtf8' . original . fst <$> rhs
39+ isSubsetOf x y = Data.HashSet.difference x y == mempty
3740
3841prop_encodingHeadersArentWrapped :: MissingHeaders '["Authorization"] -> Bool
3942prop_encodingHeadersArentWrapped hs@(MissingHeaders rhs) =
40− actual `S.isSubsetOf` expected
43+ actual `isSubsetOf` expected
4144 where
42− actual = S.fromList (foldMap keys $ decode' $ encode hs)
43− expected = S.fromList $ either (const "") id . TE.decodeUtf8' . original . fst <$> rhs
45+ actual = foldMap keys (decode' $ encode hs)
46+ expected = Data.HashSet.fromList $ fold . TE.decodeUtf8' . original . fst <$> rhs
47+ isSubsetOf x y = Data.HashSet.difference x y == mempty
4448
45−keys :: Value -> [Text]
49+keys :: Value -> HashSet Text
4650keys = \case
47− Object o -> Data.HashMap.Strict.keys o
51+ Object o -> Data.HashSet.fromMap (void o)
4852 _ -> mempty
53+