packages feed

libjenkins 0.8.1 → 0.8.2

raw patch · 14 files changed

+114/−99 lines, 14 filesdep ~http-clientdep ~http-conduitPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: http-client, http-conduit

API changes (from Hackage documentation)

Files

CHANGELOG.markdown view
@@ -1,3 +1,8 @@+0.8.2+=====++  * Stopped using the deprecated stuff in `http-client{,-tls}`.+ 0.8.1 ===== 
example/discover.hs view
@@ -2,7 +2,7 @@ -- | Discover Jenkins server on the network module Main (main) where -import           Data.Monoid ((<>), mempty) -- base+import           Data.Monoid ((<>))         -- base import           Data.Text (Text)           -- text import qualified Data.Text as Text          -- text import qualified Data.Text.IO as Text       -- text@@ -23,7 +23,7 @@ -- | Pretty print Jenkins discovery responses pretty :: Discover -> Text pretty x = Text.unwords $-  "Jenkins" : version x : maybe mempty (return . between "(" ")") (serverId x) ++ ["at", url x]+  "Jenkins" : version x : maybe [] (return . between "(" ")") (serverId x) ++ ["at", url x]  where   between l r t = l <> t <> r 
example/grep-jobs.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedStrings #-} -- | Grep Jenkins instance jobs with Perl regex module Main (main) where@@ -39,7 +38,7 @@ grep :: String -> Jenkins.Master -> IO [Text] grep regex conn = do   res <- Jenkins.run conn $-    Jenkins.get Jenkins.json ("/" -?- "tree" -=- "jobs[name]")+    Jenkins.get Jenkins.json ("" -?- "tree" -=- "jobs[name]")   filterM (match regex) (res ^.. _Right.key "jobs".values.key "name"._String)  -- | Match job name again Perl regex
example/rename-jobs.hs view
@@ -1,9 +1,12 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedStrings #-} -- | Rename jobs matching supplied pattern module Main (main) where +#if __GLASGOW_HASKELL__ < 710 import           Control.Applicative           -- base+#endif import           Control.Lens                  -- lens import           Control.Monad (when)          -- base import           Data.Aeson.Lens               -- lens-aeson@@ -47,7 +50,7 @@ rename :: Jenkins.Master -> Text -> Text -> IO (Either JenkinsException ()) rename conf old new = Jenkins.run conf $ do   -- get jobs names from jenkins "root" API-  res <- Jenkins.get Jenkins.json ("/" -?- "tree" -=- "jobs[name]")+  res <- Jenkins.get Jenkins.json ("" -?- "tree" -=- "jobs[name]")   let jobs = res ^.. key "jobs".values.key "name"._String   for_ jobs rename_job  where
example/running-jobs-count.hs view
@@ -27,7 +27,7 @@                  <*> var str "JENKINS_API_TOKEN" (help "Jenkins API token")  getJobs :: Jenkins ByteString-getJobs = Jenkins.get Jenkins.json ("/" -?- "tree" -=- "jobs[color]")+getJobs = Jenkins.get Jenkins.json ("" -?- "tree" -=- "jobs[color]")  running :: Fold ByteString () running = key "jobs".values.key "color"._String.only "blue_anime"
libjenkins.cabal view
@@ -1,5 +1,5 @@ name:                libjenkins-version:             0.8.1+version:             0.8.2 synopsis:            Jenkins API interface description:         Jenkins API interface. It supports REST and Discovery APIs license:             BSD2@@ -26,7 +26,7 @@ source-repository this   type:     git   location: https://github.com/supki/libjenkins-  tag:      0.8.1+  tag:      0.8.2  library   default-language:@@ -39,8 +39,8 @@     , conduit       >= 1.2     , containers     , free          >= 4.10-    , http-conduit  >= 2.1-    , http-client   >= 0.4+    , http-conduit  >= 2.1.8+    , http-client   >= 0.4.19     , http-types    >= 0.8     , monad-control >= 0.3     , profunctors   >= 4.2@@ -60,6 +60,8 @@     Jenkins.Rest.Method.Internal     Network.HTTP.Client.Lens     Network.HTTP.Client.Lens.Internal+  ghc-options:+    -Wall  test-suite doctest   default-language:@@ -75,6 +77,8 @@     test   main-is:     Doctest.hs+  ghc-options:+    -Wall  test-suite spec   default-language:@@ -116,5 +120,7 @@     Jenkins.RestSpec     Jenkins.Rest.InternalSpec     Jenkins.Rest.Method.InternalSpec+  ghc-options:+    -Wall   cpp-options:     -DTEST
src/Jenkins/Discover.hs view
@@ -43,7 +43,7 @@   -> IO [Discover] discover t = do   (b, addr) <- broadcastSocket-  ByteString.sendTo b (ByteString.pack [0, 0, 0, 0]) addr -- does not matter what to send+  _ <- ByteString.sendTo b (ByteString.pack [0, 0, 0, 0]) addr -- does not matter what to send    msgs <- while (timeout t (readAnswer b)) 
src/Jenkins/Rest.hs view
@@ -39,8 +39,8 @@   , Http.Request   ) where -import           Control.Applicative ((<$)) import qualified Control.Exception as Unlifted+import           Control.Monad (void) import           Control.Monad.IO.Class (MonadIO(..)) import           Control.Monad.Trans.Control (MonadBaseControl(..)) import           Control.Monad.Trans.Resource (MonadResource)@@ -49,7 +49,6 @@ import           Data.Conduit (ResumableSource) import           Data.Data (Data, Typeable) import qualified Data.Foldable as F-import           Data.Monoid (mempty) import           Data.Text (Text) import qualified Data.Text.Lazy as Text.Lazy import qualified Data.Text.Lazy.Encoding as Text.Lazy@@ -90,7 +89,7 @@ -- -- While the return type is /lazy/ @Bytestring@, the entire response -- sits in memory anyway: lazy I/O is not used at the least-get :: Formatter f -> (forall g. Method Complete g) -> JenkinsT m Lazy.ByteString+get :: Formatter f -> (forall g. Method 'Complete g) -> JenkinsT m Lazy.ByteString get (Formatter f) m = liftJ (Get (f m) id)  -- | Perform a streaming @GET@ request@@ -98,16 +97,16 @@ -- 'stream', unlike 'get', is constant-space stream   :: MonadResource m-  => Formatter f -> (forall g. Method Complete g) -> JenkinsT m (ResumableSource m Strict.ByteString)+  => Formatter f -> (forall g. Method 'Complete g) -> JenkinsT m (ResumableSource m Strict.ByteString) stream (Formatter f) m = liftJ (Stream (f m) id)  -- | Perform a @POST@ request-post :: (forall f. Method Complete f) -> Lazy.ByteString -> JenkinsT m Lazy.ByteString+post :: (forall f. Method 'Complete f) -> Lazy.ByteString -> JenkinsT m Lazy.ByteString post m body = liftJ (Post m body id)  -- | Perform a @POST@ request without a payload-post_ :: (forall f. Method Complete f) -> JenkinsT m Lazy.ByteString-post_ m = post m mempty+post_ :: (forall f. Method 'Complete f) -> JenkinsT m Lazy.ByteString+post_ m = post m Lazy.empty  -- | A simple exception handler. If an exception is raised while the action is -- executed the handler is executed with it as an argument@@ -147,14 +146,14 @@ -- -- @'traverse_' : 'Data.Foldable.traverse_' :: 'concurrently' : 'Control.Applicative.liftA2' (,)@ traverse_ :: F.Foldable f => (a -> JenkinsT m b) -> f a -> JenkinsT m ()-traverse_ f = F.foldr (\x xs -> () <$ concurrently (f x) xs) (return ())+traverse_ f = F.foldr (\x -> void . concurrently (f x)) (return ())   -- | Perform a @POST@ request to Jenkins with the XML document -- -- Sets up the correct @Content-Type@ header. Mostly useful for updating @config.xml@ -- files for jobs, views, etc-postXml :: (forall f. Method Complete f) -> Lazy.ByteString -> JenkinsT m Lazy.ByteString+postXml :: (forall f. Method 'Complete f) -> Lazy.ByteString -> JenkinsT m Lazy.ByteString postXml m = locally (\r -> r { Http.requestHeaders = xmlHeader : Http.requestHeaders r }) . post m  where   xmlHeader = ("Content-Type", "text/xml")@@ -174,7 +173,7 @@ -- -- Performs @/reload@ reload :: JenkinsT m ()-reload = () <$ post_ "reload"+reload = void (post_ "reload")  -- | Restart jenkins safely --@@ -182,7 +181,7 @@ -- -- @/safeRestart@ allows all running jobs to complete restart :: JenkinsT m ()-restart = () <$ post_ "safeRestart"+restart = void (post_ "safeRestart")  -- | Restart jenkins --@@ -191,4 +190,4 @@ -- @/restart@ restart Jenkins immediately, without waiting for the completion of -- the building and/or waiting jobs forceRestart :: JenkinsT m ()-forceRestart = () <$ post_ "restart"+forceRestart = void (post_ "restart")
src/Jenkins/Rest/Internal.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE DeriveDataTypeable #-}@@ -21,7 +22,9 @@   , iter   ) where +#if __GLASGOW_HASKELL__ < 710 import           Control.Applicative+#endif import           Control.Concurrent.Async (Async) import qualified Control.Concurrent.Async as Unlifted import           Control.Exception (Exception(..), SomeException, throwIO)@@ -91,9 +94,9 @@   data JF :: (* -> *) -> * -> * where-  Get    :: Method Complete f -> (ByteString -> a) -> JF m a-  Stream :: MonadResource m => Method Complete f -> (ResumableSource m Strict.ByteString -> a) -> JF m a-  Post   :: (forall f. Method Complete f) -> ByteString -> (ByteString -> a) -> JF m a+  Get    :: Method 'Complete f -> (ByteString -> a) -> JF m a+  Stream :: MonadResource m => Method 'Complete f -> (ResumableSource m Strict.ByteString -> a) -> JF m a+  Post   :: (forall f. Method 'Complete f) -> ByteString -> (ByteString -> a) -> JF m a   Conc   :: JenkinsT m a -> JenkinsT m b -> (a -> b -> c) -> JF m c   Or     :: JenkinsT m a -> (JenkinsException -> JenkinsT m a) -> JF m a   With   :: (Request -> Request) -> JenkinsT m b -> (b -> a) -> JF m a@@ -125,16 +128,9 @@   => String -> Text -> Text -> JenkinsT m a -> m a runInternal h user token jenk = do   url <- liftIO (wrapException (Http.parseUrl h))-  bracket (newManager Http.conduitManagerSettings) closeManager $ \m ->-    runInterpT (iterInterpT m jenk)-      . Http.applyBasicAuth (Text.encodeUtf8 user) (Text.encodeUtf8 token)-      $ url--newManager :: MonadIO m => Http.ManagerSettings -> m Http.Manager-newManager = liftIO . Http.newManager--closeManager :: MonadIO m => Http.Manager -> m ()-closeManager = liftIO . Http.closeManager+  man <- liftIO (Http.newManager Http.tlsManagerSettings)+  runInterpT (iterInterpT man jenk)+             (Http.applyBasicAuth (Text.encodeUtf8 user) (Text.encodeUtf8 token) url)  newtype InterpT m a = InterpT   { runInterpT :: Request -> m a@@ -202,13 +198,13 @@   -> InterpT m a intoM m f = InterpT $ \req -> f (\x -> runInterpT (iterInterpT m x) req) -prepareGet :: Method Complete f -> Request -> Request+prepareGet :: Method 'Complete f -> Request -> Request prepareGet m r = r   { Http.method = "GET"   , Http.path   = Http.path r `slash` render m   } -preparePost :: Method Complete f -> ByteString -> Request -> Request+preparePost :: Method 'Complete f -> ByteString -> Request -> Request preparePost m body r = r   { Http.checkStatus   = statusCheck   , Http.redirectCount = 0@@ -250,13 +246,6 @@ mask :: MonadBaseControl IO m => ((forall a. m a -> m a) -> m b) -> m b mask f = control $ \magic -> Unlifted.mask (\g -> magic (f (liftBaseOp_ g))) {-# INLINABLE mask #-}--bracket :: (MonadBaseControl IO m) => m a -> (a -> m b) -> (a -> m c) -> m c-bracket f g h = control $ \magic ->-  Unlifted.bracket (magic f)-                   (\b -> magic (restoreM b >>= g))-                   (\c -> magic (restoreM c >>= h))-{-# INLINABLE bracket #-}  catch :: (MonadBaseControl IO m, Exception e) => m a -> (e -> m a) -> m a catch m h = control (\magic -> Unlifted.catch (magic m) (magic . h))
src/Jenkins/Rest/Method.hs view
@@ -68,35 +68,35 @@ -- -- >>> pp' "foo/bar" -- "foo%2Fbar"-text :: Text -> Method Complete f+text :: Text -> Method 'Complete f text = Text  -- | Use an integer as an URI segment -- -- >>> pp (int 4) -- "4"-int :: Int -> Method Complete f+int :: Int -> Method 'Complete f int = fromIntegral  -- | Combine two paths -- -- >>> pp ("foo" -/- "bar" -/- "baz") -- "foo/bar/baz"-(-/-) :: Method Complete f -> Method Complete f -> Method Complete f+(-/-) :: Method 'Complete f -> Method 'Complete f -> Method 'Complete f (-/-) = (:/)  -- | Make a key-value pair -- -- >>> pp ("foo" -=- "bar") -- "foo=bar"-(-=-) :: Text -> Text -> Method Query f+(-=-) :: Text -> Text -> Method 'Query f x -=- y = x := Just y  -- | Create the union of two queries -- -- >>> pp ("foo" -=- "bar" -&- "baz") -- "foo=bar&baz"-(-&-) :: Method Query f -> Method Query f -> Method Query f+(-&-) :: Method 'Query f -> Method 'Query f -> Method 'Query f (-&-) = (:&)  -- | Take a list of key-value pairs and render them as a query@@ -106,21 +106,27 @@ -- -- >>> pp (query []) -- ""-query :: [(Text, Maybe Text)] -> Method Query f+query :: [(Text, Maybe Text)] -> Method 'Query f query = foldr ((:&) . uncurry (:=)) Empty  -- | Put path and query together -- -- >>> pp ("qux" -/- "quux" -?- "foo" -=- "bar" -&- "baz") -- "qux/quux?foo=bar&baz"-(-?-) :: Method Complete f -> Method Query f -> Method Complete f+--+-- >>> pp ("" -?- "foo" -=- "bar")+-- "foo=bar"+--+-- >>> pp ("/" -?- "foo" -=- "bar")+-- "%2F?foo=bar"+(-?-) :: Method 'Complete f -> Method 'Query f -> Method 'Complete f (-?-) = (:?)  -- | Append the JSON formatting request to the method URL -- -- >>> format json "foo" -- "foo/api/json"-json :: Formatter Json+json :: Formatter 'Json json = Formatter (\m -> m :@ SJson) {-# ANN json ("HLint: ignore Avoid lambda" :: String) #-} @@ -128,7 +134,7 @@ -- -- >>> format xml "foo" -- "foo/api/xml"-xml :: Formatter Xml+xml :: Formatter 'Xml xml = Formatter (\m -> m :@ SXml) {-# ANN xml ("HLint: ignore Avoid lambda" :: String) #-} @@ -136,7 +142,7 @@ -- -- >>> format python "foo" -- "foo/api/python"-python :: Formatter Python+python :: Formatter 'Python python = Formatter (\m -> m :@ SPython) {-# ANN python ("HLint: ignore Avoid lambda" :: String) #-} @@ -156,40 +162,40 @@ -- -- >>> pp (job "name" -/- "config.xml") -- "job/name/config.xml"-job :: Text -> Method Complete f+job :: Text -> Method 'Complete f job name = "job" -/- text name  -- | Job build data -- -- >>> format json (build "name" 4) -- "job/name/4/api/json"-build :: Text -> Int -> Method Complete f+build :: Text -> Int -> Method 'Complete f build name num = "job" -/- text name -/- int num  -- | View data -- -- >>> format xml (view "name") -- "view/name/api/xml"-view :: Text -> Method Complete f+view :: Text -> Method 'Complete f view name = "view" -/- text name  -- | Build queue data -- -- >>> format python queue -- "queue/api/python"-queue :: Method Complete f+queue :: Method 'Complete f queue = "queue"  -- | Server statistics -- -- >>> format xml overallLoad -- "overallLoad/api/xml"-overallLoad :: Method Complete f+overallLoad :: Method 'Complete f overallLoad = "overallLoad"  -- | Nodes data -- -- >>> format python computer -- "computer/api/python"-computer :: Method Complete f+computer :: Method 'Complete f computer = "computer"
src/Jenkins/Rest/Method/Internal.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE FlexibleContexts #-}@@ -14,7 +15,9 @@ import           Control.Applicative import           Data.ByteString (ByteString) import           Data.Data (Data, Typeable)-import           Data.Monoid (Monoid(..), (<>))+#if __GLASGOW_HASKELL__ < 710+import           Data.Monoid (Monoid(..))+#endif import           Data.String (IsString(..)) import qualified Data.Text as Text import qualified Data.Text.Encoding as Text@@ -32,18 +35,18 @@  -- | Jenkins RESTFul API method encoding data Method :: Type -> Format -> * where-  Empty :: Method Query f-  Text  :: Text -> Method Complete f-  (:/)  :: Method Complete f -> Method Complete f -> Method Complete f-  (:=)  :: Text -> Maybe Text -> Method Query f-  (:&)  :: Method Query f -> Method Query f -> Method Query f-  (:?)  :: Method Complete f -> Method Query f -> Method Complete f-  (:@)  :: Method Complete f -> SFormat f -> Method Complete f+  Empty :: Method 'Query f+  Text  :: Text -> Method 'Complete f+  (:/)  :: Method 'Complete f -> Method 'Complete f -> Method 'Complete f+  (:=)  :: Text -> Maybe Text -> Method 'Query f+  (:&)  :: Method 'Query f -> Method 'Query f -> Method 'Query f+  (:?)  :: Method 'Complete f -> Method 'Query f -> Method 'Complete f+  (:@)  :: Method 'Complete f -> SFormat f -> Method 'Complete f  deriving instance Show (SFormat f) => Show (Method t f)  -- | Only to support numeric literals-instance t ~ Complete => Num (Method t f) where+instance t ~ 'Complete => Num (Method t f) where   (+)         = error "Method.(+): not supposed to be used"   (-)         = error "Method.(-): not supposed to be used"   (*)         = error "Method.(*): not supposed to be used"@@ -51,10 +54,10 @@   signum      = error "Method.signum: not supposed to be used"   fromInteger = fromString . show -instance IsString (Method Complete f) where+instance IsString (Method 'Complete f) where   fromString = Text . fromString -instance IsString (Method Query f) where+instance IsString (Method 'Query f) where   fromString str = fromString str := Nothing  -- | Method types@@ -66,45 +69,45 @@   deriving (Show, Eq, Typeable, Data)  data SFormat :: Format -> * where-  SJson   :: SFormat Json-  SXml    :: SFormat Xml-  SPython :: SFormat Python+  SJson   :: SFormat 'Json+  SXml    :: SFormat 'Xml+  SPython :: SFormat 'Python   -- | 'Formatter's know how to append the \"api/$format\" string to the method URL newtype Formatter g = Formatter-  { unFormatter :: (forall f. Method Complete f) -> Method Complete g+  { unFormatter :: (forall f. Method 'Complete f) -> Method 'Complete g   } -format :: Formatter f -> (forall g. Method Complete g) -> ByteString+format :: Formatter f -> (forall g. Method 'Complete g) -> ByteString format f m = render (unFormatter f m)  -- | Render 'Method' to something that can be sent over the wire-render :: Method Complete f -> ByteString+render :: Method 'Complete f -> ByteString render m = maybe id (flip (insert "?")) (renderQ m) . maybe id (flip (insert "/")) (renderF m) . renderP $ m  -- | Render the method path-renderP :: Method Complete f -> ByteString+renderP :: Method 'Complete f -> ByteString renderP (Text s) = renderT s renderP (x :/ y) = renderP x `slash` renderP y renderP (x :? _) = renderP x renderP (x :@ _) = renderP x  -- | Render the query string-renderQ :: Method Complete f -> Maybe ByteString+renderQ :: Method 'Complete f -> Maybe ByteString renderQ (Text _)  = Nothing renderQ (q :/ q') = renderQ q <|> renderQ q' renderQ (q :@ _)  = renderQ q renderQ (_ :? q)  = Just (renderQ' q) -renderQ' :: Method Query f -> ByteString+renderQ' :: Method 'Query f -> ByteString renderQ' (x :& y)       = insert "&" (renderQ' x) (renderQ' y) renderQ' (x := Just y)  = insert "=" (renderT x)  (renderT y) renderQ' (x := Nothing) = renderT x renderQ' Empty          = renderT ""  -- | Render the response format string-renderF :: Method Complete f -> Maybe ByteString+renderF :: Method 'Complete f -> Maybe ByteString renderF (_ :@ SJson)   = Just "api/json" renderF (_ :@ SXml)    = Just "api/xml" renderF (_ :@ SPython) = Just "api/python"@@ -138,4 +141,4 @@ insert t x y   | x == mempty = y   | y == mempty = x-  | otherwise   = x <> t <> y+  | otherwise   = x `mappend` t `mappend` y
test/Doctest.hs view
@@ -1,6 +1,5 @@ module Main where -import Control.Applicative ((<$>)) import Control.Monad (forM, liftM) import Data.List (isSuffixOf) import System.Directory (getDirectoryContents, doesDirectoryExist)@@ -25,4 +24,4 @@   isSource path = any (`isSuffixOf` path) [".hs", ".lhs"]  contents :: FilePath -> IO [FilePath]-contents dir = filter (`notElem` [".", ".."]) <$> getDirectoryContents dir+contents = fmap (filter (`notElem` [".", ".."])) . getDirectoryContents
test/Jenkins/Rest/InternalSpec.hs view
@@ -41,7 +41,7 @@     it "can catch 'HttpException' exceptions related from the queries" $ do       r <- Jenkins.run master         (liftJ (Or (Jenkins.get Jenkins.plain "hi" >> return 4) (\_ -> return 7)))-      r `shouldPreview` 7 `through` _Right+      r `shouldPreview` (7 :: Integer) `through` _Right      it "does not catch (and wrap) 'HttpException's not from the queries" $       Jenkins.run master raiseHttp `shouldThrow` _TooManyRetries
test/Jenkins/RestSpec.hs view
@@ -1,14 +1,16 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RankNTypes #-} module Jenkins.RestSpec (spec) where +#if __GLASGOW_HASKELL__ < 710 import           Control.Applicative+#endif import           Control.Monad.Trans.State (State, evalState, get, put) import qualified Data.ByteString as Strict import qualified Data.ByteString.Lazy as Lazy import           Data.Functor.Identity (Identity)-import           Data.Monoid (mempty) import           Test.Hspec import qualified Jenkins.Rest as Jenkins import           Jenkins.Rest.Internal@@ -20,26 +22,29 @@   context "POST requests" $ do     it "post_ sends POST request with empty body" $ do       interpret $ do-        Jenkins.post_ "foo"-        Jenkins.post_ "bar"-        Jenkins.post_ "baz"+        _ <- Jenkins.post_ "foo"+        _ <- Jenkins.post_ "bar"+        _ <- Jenkins.post_ "baz"+        return ()      `shouldBe`       [QPost 0 "" "foo", QPost 1 "" "bar", QPost 2 "" "baz"]      it "post sends POST request with non-empty body" $ do       interpret $ do-        Jenkins.post "foo" "qux"-        Jenkins.post "bar" "quux"-        Jenkins.post "baz" "xyzzy"+        _ <- Jenkins.post "foo" "qux"+        _ <- Jenkins.post "bar" "quux"+        _ <- Jenkins.post "baz" "xyzzy"+        return ()      `shouldBe`       [QPost 0 "qux" "foo", QPost 1 "quux" "bar", QPost 2 "xyzzy" "baz"]    context "GET requests" $     it "get sends GET requests" $ do       interpret $ do-        Jenkins.get Jenkins.plain "foo"-        Jenkins.get Jenkins.plain "bar"-        Jenkins.get Jenkins.plain "baz"+        _ <- Jenkins.get Jenkins.plain "foo"+        _ <- Jenkins.get Jenkins.plain "bar"+        _ <- Jenkins.get Jenkins.plain "baz"+        return ()      `shouldBe`       [QGet 0 "foo", QGet 1 "bar", QGet 2 "baz"] @@ -57,12 +62,13 @@   go :: JF Identity (State (Requests Int) [Query]) -> State (Requests Int) [Query]   go (Get m n) = do     r <- render QGet m-    fmap (r :) (n mempty)+    fmap (r :) (n Lazy.empty)   go (Post m body n) = do     r <- render (\x y -> QPost x body y) m-    fmap (r :) (n mempty)+    fmap (r :) (n Lazy.empty)+  go _ = error "unexpected term" -render :: (a -> Strict.ByteString -> Query) -> Jenkins.Method Method.Complete f -> State (Requests a) Query+render :: (a -> Strict.ByteString -> Query) -> Jenkins.Method 'Method.Complete f -> State (Requests a) Query render f m = do   n <- next   return $ f n (Method.render m)