mackerel-client 0.0.4 → 0.0.5
raw patch · 13 files changed
+251/−13 lines, 13 files
Files
- README.md +1/−1
- mackerel-client.cabal +9/−2
- src/Web/Mackerel/Api.hs +2/−0
- src/Web/Mackerel/Api/Invitation.hs +19/−0
- src/Web/Mackerel/Api/Metadata.hs +33/−0
- src/Web/Mackerel/Types.hs +2/−0
- src/Web/Mackerel/Types/Dashboard.hs +1/−3
- src/Web/Mackerel/Types/Invitation.hs +43/−0
- src/Web/Mackerel/Types/Metadata.hs +13/−0
- test/Types/DashboardSpec.hs +3/−7
- test/Types/GraphAnnotationSpec.hs +49/−0
- test/Types/InvitationSpec.hs +39/−0
- test/Types/MetadataSpec.hs +37/−0
README.md view
@@ -28,7 +28,7 @@ ``` ## Author-itchyny (https://github.com/itchyny)+itchyny <itchyny@hatena.ne.jp> ## License This software is released under the MIT License, see LICENSE.
mackerel-client.cabal view
@@ -1,7 +1,7 @@ name: mackerel-client-version: 0.0.4+version: 0.0.5 author: itchyny-maintainer: itchyny <https://github.com/itchyny>+maintainer: itchyny <itchyny@hatena.ne.jp> license: MIT license-file: LICENSE category: Web@@ -23,9 +23,11 @@ , Web.Mackerel.Types , Web.Mackerel.Types.Organization , Web.Mackerel.Types.User+ , Web.Mackerel.Types.Invitation , Web.Mackerel.Types.Service , Web.Mackerel.Types.Role , Web.Mackerel.Types.Host+ , Web.Mackerel.Types.Metadata , Web.Mackerel.Types.Monitor , Web.Mackerel.Types.Alert , Web.Mackerel.Types.Dashboard@@ -33,9 +35,11 @@ , Web.Mackerel.Api , Web.Mackerel.Api.Organization , Web.Mackerel.Api.User+ , Web.Mackerel.Api.Invitation , Web.Mackerel.Api.Service , Web.Mackerel.Api.Role , Web.Mackerel.Api.Host+ , Web.Mackerel.Api.Metadata , Web.Mackerel.Api.Monitor , Web.Mackerel.Api.Alert , Web.Mackerel.Api.Dashboard@@ -66,12 +70,15 @@ ghc-options: -Wall other-modules: Types.OrganizationSpec , Types.UserSpec+ , Types.InvitationSpec , Types.ServiceSpec , Types.RoleSpec , Types.HostSpec+ , Types.MetadataSpec , Types.MonitorSpec , Types.AlertSpec , Types.DashboardSpec+ , Types.GraphAnnotationSpec , ConfigSpec build-depends: base >= 4.9 && < 5.0 , mackerel-client
src/Web/Mackerel/Api.hs view
@@ -4,6 +4,8 @@ import Web.Mackerel.Api.Dashboard as Api import Web.Mackerel.Api.GraphAnnotation as Api import Web.Mackerel.Api.Host as Api+import Web.Mackerel.Api.Invitation as Api+import Web.Mackerel.Api.Metadata as Api import Web.Mackerel.Api.Monitor as Api import Web.Mackerel.Api.Organization as Api import Web.Mackerel.Api.Role as Api
+ src/Web/Mackerel/Api/Invitation.hs view
@@ -0,0 +1,19 @@+{-# LANGUAGE OverloadedStrings, TemplateHaskell #-}+-- | Invitation API.+module Web.Mackerel.Api.Invitation (createInvitation, revokeInvitation) where++import Data.Aeson (Value)+import qualified Data.HashMap.Lazy as HM+import Network.HTTP.Types (StdMethod(..))++import Web.Mackerel.Client+import Web.Mackerel.Internal.Api+import Web.Mackerel.Types.Invitation++createInvitation :: Client -> Invitation -> IO (Either ApiError Invitation)+createInvitation client invitation+ = request client POST "/api/v0/invitations" [] (Just invitation) (createHandler id)++revokeInvitation :: Client -> String -> IO (Either ApiError ())+revokeInvitation client email+ = request client POST "/api/v0/invitations/revoke" [] (Just (HM.singleton "email" email :: HM.HashMap String String)) (createHandler ((\_ -> ()) :: Value -> ()))
+ src/Web/Mackerel/Api/Metadata.hs view
@@ -0,0 +1,33 @@+{-# LANGUAGE OverloadedStrings, TemplateHaskell #-}+-- | Metadata API.+module Web.Mackerel.Api.Metadata (getMetadata, putMetadata, deleteMetadata, listMetadata) where++import Data.Aeson (Value)+import Data.Aeson.TH (deriveJSON)+import qualified Data.ByteString.Char8 as BS+import Data.Semigroup ((<>))+import Network.HTTP.Types (StdMethod(..))++import Web.Mackerel.Client+import Web.Mackerel.Internal.Api+import Web.Mackerel.Internal.TH+import Web.Mackerel.Types.Metadata++getMetadata :: Client -> String -> String -> IO (Either ApiError Value)+getMetadata client hostId namespace+ = request client GET ("/api/v0/hosts/" <> BS.pack hostId <> "/metadata/" <> BS.pack namespace) [] emptyBody (createHandler id)++putMetadata :: Client -> String -> String -> Value -> IO (Either ApiError ())+putMetadata client hostId namespace metadata+ = request client PUT ("/api/v0/hosts/" <> BS.pack hostId <> "/metadata/" <> BS.pack namespace) [] (Just metadata) (createHandler ((\_ -> ()) :: Value -> ()))++deleteMetadata :: Client -> String -> String -> IO (Either ApiError ())+deleteMetadata client hostId namespace+ = request client DELETE ("/api/v0/hosts/" <> BS.pack hostId <> "/metadata/" <> BS.pack namespace) [] emptyBody (createHandler ((\_ -> ()) :: Value -> ()))++data ListMetadataResponse = ListMetadataResponse { responseMetadata :: [Metadata] }+$(deriveJSON options ''ListMetadataResponse)++listMetadata :: Client -> String -> IO (Either ApiError [Metadata])+listMetadata client hostId+ = request client GET ("/api/v0/hosts/" <> BS.pack hostId <> "/metadata") [] emptyBody (createHandler responseMetadata)
src/Web/Mackerel/Types.hs view
@@ -4,6 +4,8 @@ import Web.Mackerel.Types.Dashboard as Types import Web.Mackerel.Types.GraphAnnotation as Types import Web.Mackerel.Types.Host as Types+import Web.Mackerel.Types.Invitation as Types+import Web.Mackerel.Types.Metadata as Types import Web.Mackerel.Types.Monitor as Types import Web.Mackerel.Types.Organization as Types import Web.Mackerel.Types.Role as Types
src/Web/Mackerel/Types/Dashboard.hs view
@@ -34,9 +34,7 @@ dashboardId :: DashboardId, dashboardTitle :: String, dashboardBodyMarkdown :: String,- dashboardUrlPath :: String,- dashboardCreatedAt :: Integer,- dashboardUpdatedAt :: Integer+ dashboardUrlPath :: String } deriving (Eq, Show) $(deriveJSON options ''Dashboard)
+ src/Web/Mackerel/Types/Invitation.hs view
@@ -0,0 +1,43 @@+{-# LANGUAGE TemplateHaskell #-}+module Web.Mackerel.Types.Invitation where++import Data.Aeson+import qualified Data.Aeson as Aeson+import Data.Aeson.TH (deriveJSON)+import Data.Aeson.Types (typeMismatch)+import qualified Data.Text as Text++import Web.Mackerel.Internal.TH++data InvitationAuthority = InvitationAuthorityManager+ | InvitationAuthorityCollaborator+ | InvitationAuthorityViewer+ deriving Eq++instance Show InvitationAuthority where+ show InvitationAuthorityManager = "manager"+ show InvitationAuthorityCollaborator = "collaborator"+ show InvitationAuthorityViewer = "viewer"++instance Read InvitationAuthority where+ readsPrec _ xs = [ (hs, drop (length str) xs) | (hs, str) <- pairs', take (length str) xs == str ]+ where pairs' = [(InvitationAuthorityManager, "manager"), (InvitationAuthorityCollaborator, "collaborator"), (InvitationAuthorityViewer, "viewer")]++instance FromJSON InvitationAuthority where+ parseJSON (Aeson.String txt)+ | str == "manager" = return InvitationAuthorityManager+ | str == "collaborator" = return InvitationAuthorityCollaborator+ | str == "viewer" = return InvitationAuthorityViewer+ where str = Text.unpack txt+ parseJSON o = typeMismatch "InvitationAuthority" o++instance ToJSON InvitationAuthority where+ toJSON method = toJSON (show method)++data Invitation+ = Invitation {+ invitationEmail :: String,+ invitationAuthority :: InvitationAuthority+ } deriving (Eq, Show)++$(deriveJSON options ''Invitation)
+ src/Web/Mackerel/Types/Metadata.hs view
@@ -0,0 +1,13 @@+{-# LANGUAGE TemplateHaskell #-}+module Web.Mackerel.Types.Metadata where++import Data.Aeson.TH (deriveJSON)++import Web.Mackerel.Internal.TH++data Metadata+ = Metadata {+ metadataNamespace :: String+ } deriving (Eq, Show)++$(deriveJSON options ''Metadata)
test/Types/DashboardSpec.hs view
@@ -16,9 +16,7 @@ dashboardId = DashboardId "abcde", dashboardTitle = "This is a dashboard", dashboardBodyMarkdown = "# Example\n[example](https://example.com)",- dashboardUrlPath = "example",- dashboardCreatedAt = 1483196400,- dashboardUpdatedAt = 1483282800+ dashboardUrlPath = "example" } let json = [aesonQQ|@@ -26,9 +24,7 @@ "id": "abcde", "title": "This is a dashboard", "bodyMarkdown": "# Example\n[example](https://example.com)",- "urlPath": "example",- "createdAt": 1483196400,- "updatedAt": 1483282800+ "urlPath": "example" } |] @@ -53,7 +49,7 @@ it "should reject an invalid json" $ do decode "{}" `shouldBe` (Nothing :: Maybe Dashboard) let (Object hm) = json- forM_ ["id", "title", "bodyMarkdown", "urlPath", "createdAt", "updatedAt"] $ \key ->+ forM_ ["id", "title", "bodyMarkdown", "urlPath"] $ \key -> decode (encode (Object (HM.delete key hm))) `shouldBe` (Nothing :: Maybe Dashboard) describe "Dashboard ToJSON" $
+ test/Types/GraphAnnotationSpec.hs view
@@ -0,0 +1,49 @@+{-# LANGUAGE OverloadedStrings, QuasiQuotes #-}+module Types.GraphAnnotationSpec where++import Control.Monad (forM_)+import Data.Aeson (decode, encode, Value(..))+import Data.Aeson.QQ+import qualified Data.HashMap.Lazy as HM+import Test.Hspec++import Web.Mackerel.Types.GraphAnnotation++spec :: Spec+spec = do++ let graphAnnotation = GraphAnnotation {+ graphAnnotationId = Just $ GraphAnnotationId "abcde",+ graphAnnotationTitle = "Deploy application #123",+ graphAnnotationDescription = "Deploy link: https://example.com/123",+ graphAnnotationFrom = 1485000000,+ graphAnnotationTo = 1485000060,+ graphAnnotationService = "ExampleService",+ graphAnnotationRoles = Just [ "ExampleRole1", "ExampleRole2" ]+ }++ let json = [aesonQQ|+ {+ "id": "abcde",+ "title": "Deploy application #123",+ "description": "Deploy link: https://example.com/123",+ "from": 1485000000,+ "to": 1485000060,+ "service": "ExampleService",+ "roles": [ "ExampleRole1", "ExampleRole2" ]+ }+ |]++ describe "GraphAnnotation FromJSON" $ do+ it "should parse a json" $+ decode (encode json) `shouldBe` Just graphAnnotation++ it "should reject an invalid json" $ do+ decode "{}" `shouldBe` (Nothing :: Maybe GraphAnnotation)+ let (Object hm) = json+ forM_ ["title", "description", "from", "to", "service"] $ \key ->+ decode (encode (Object (HM.delete key hm))) `shouldBe` (Nothing :: Maybe GraphAnnotation)++ describe "GraphAnnotation ToJSON" $+ it "should encode into a json" $+ decode (encode graphAnnotation) `shouldBe` Just json
+ test/Types/InvitationSpec.hs view
@@ -0,0 +1,39 @@+{-# LANGUAGE OverloadedStrings, QuasiQuotes #-}+module Types.InvitationSpec where++import Control.Monad (forM_)+import Data.Aeson (decode, encode, Value(..))+import Data.Aeson.QQ+import qualified Data.HashMap.Lazy as HM+import Test.Hspec++import Web.Mackerel.Types.Invitation++spec :: Spec+spec = do++ let invitation' = Invitation {+ invitationEmail = "foobar@example.com",+ invitationAuthority = InvitationAuthorityManager+ }++ let json = [aesonQQ|+ {+ "email": "foobar@example.com",+ "authority": "manager"+ }+ |]++ describe "Invitation FromJSON" $ do+ it "should parse a json" $+ decode (encode json) `shouldBe` Just invitation'++ it "should reject an invalid json" $ do+ decode "{}" `shouldBe` (Nothing :: Maybe Invitation)+ let (Object hm) = json+ forM_ ["email", "authority"] $ \key ->+ decode (encode (Object (HM.delete key hm))) `shouldBe` (Nothing :: Maybe Invitation)++ describe "invitation ToJSON" $+ it "should encode into a json" $+ decode (encode invitation') `shouldBe` Just json
+ test/Types/MetadataSpec.hs view
@@ -0,0 +1,37 @@+{-# LANGUAGE OverloadedStrings, QuasiQuotes #-}+module Types.MetadataSpec where++import Control.Monad (forM_)+import Data.Aeson (decode, encode, Value(..))+import Data.Aeson.QQ+import qualified Data.HashMap.Lazy as HM+import Test.Hspec++import Web.Mackerel.Types.Metadata++spec :: Spec+spec = do++ let metadata' = Metadata {+ metadataNamespace = "foo-bar-namespace"+ }++ let json = [aesonQQ|+ {+ "namespace": "foo-bar-namespace"+ }+ |]++ describe "Metadata FromJSON" $ do+ it "should parse a json" $+ decode (encode json) `shouldBe` Just metadata'++ it "should reject an invalid json" $ do+ decode "{}" `shouldBe` (Nothing :: Maybe Metadata)+ let (Object hm) = json+ forM_ ["namespace"] $ \key ->+ decode (encode (Object (HM.delete key hm))) `shouldBe` (Nothing :: Maybe Metadata)++ describe "Metadata ToJSON" $+ it "should encode into a json" $+ decode (encode metadata') `shouldBe` Just json