packages feed

jenkinsPlugins2nix (empty) → 0.1.0.0

raw patch · 10 files changed

+641/−0 lines, 10 filesdep +ansi-wl-pprintdep +attoparsecdep +basesetup-changed

Dependencies added: ansi-wl-pprint, attoparsec, base, bytestring, containers, cryptohash, data-fix, hnix, http-conduit, jenkinsPlugins2nix, mtl, tasty-hspec, text, zip-archive

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Mateusz Kowalczyk (c) 2017++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Mateusz Kowalczyk nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,18 @@+# jenkinsPlugins2nix++```+jenkinsPlugins2nix: PLUGIN_NAME{:PLUGIN_VERSION} [PLUGIN_NAME{:PLUGIN_VERSION} ...]+```++Along with recent nixpkgs, you can then do the following.++```+jenkinsPlugins2nix github-api > plugins.nix++```++and in your `configuration.nix`:++```+services.jenkins.plugins = pkgs.callPackage plugins.nix {};+```
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ app/Main.hs view
@@ -0,0 +1,53 @@+{-# LANGUAGE LambdaCase        #-}+{-# LANGUAGE OverloadedStrings #-}+-- |+-- Module    : Nix.JenkinsPlugins2Nix.Types+-- Copyright : (c) 2017 Mateusz Kowalczyk+-- License   : BSD3+--+-- @jenkinsPlugins2nix@ entry point.+module Main (main) where++import           Data.Monoid ((<>))+import qualified Data.Text as Text+import           Nix.JenkinsPlugins2Nix+import           Nix.JenkinsPlugins2Nix.Types+import           System.Environment+import           System.Exit+import           System.IO+import qualified Text.PrettyPrint.ANSI.Leijen as Pretty++usage :: Handle -> IO ()+usage h = do+  pName <- getProgName+  hPutStrLn h $+    pName <> ": PLUGIN_NAME{:PLUGIN_VERSION} [PLUGIN_NAME{:PLUGIN_VERSION} ...]"++main :: IO ()+main = do+  getArgs >>= \case+    [] -> do+      usage stderr+      exitFailure+    [v] | v == "-h" || v == "--help" -> do+      usage stdout+      exitSuccess+    plugins -> do+      mkExprsFor (map parseRequestedPlugin plugins) >>= \case+        Left err -> do+          hPutStrLn stderr err+          exitFailure+        Right p -> do+          Pretty.putDoc p+          exitSuccess+  where+    parseRequestedPlugin :: String -> RequestedPlugin+    parseRequestedPlugin p = case break (== ':') p of+      (n, ':' : ver) -> RequestedPlugin+        { requested_name = Text.pack n+        , requested_version = Just (Text.pack ver)+        }+      _ -> RequestedPlugin+        { requested_name = Text.pack p+        , requested_version = Nothing+        }
+ jenkinsPlugins2nix.cabal view
@@ -0,0 +1,61 @@+name:                jenkinsPlugins2nix+version:             0.1.0.0+synopsis:            Generate nix for Jenkins plugins.+description:         Generate nix for Jenkins plugins.+homepage:            https://github.com/Fuuzetsu/jenkinsPlugins2nix#readme+license:             BSD3+license-file:        LICENSE+author:              Mateusz Kowalczyk+maintainer:          fuuzetsu@fuuzetsu.com+copyright:           2017 Mateusz Kowalczyk+category:            Nix+build-type:          Simple+extra-source-files:  README.md+cabal-version:       >=1.10++library+  hs-source-dirs:      src+  exposed-modules:     Nix.JenkinsPlugins2Nix+                       Nix.JenkinsPlugins2Nix.Parser+                       Nix.JenkinsPlugins2Nix.Types+  build-depends:       base >= 4.7 && < 5+                     , ansi-wl-pprint+                     , attoparsec+                     , bytestring+                     , containers+                     , cryptohash+                     , data-fix+                     , hnix+                     , http-conduit+                     , mtl+                     , text+                     , zip-archive+  default-language:    Haskell2010+  ghc-options:        -Wall++executable jenkinsPlugins2nix+  hs-source-dirs:      app+  main-is:             Main.hs+  ghc-options:         -threaded -rtsopts -with-rtsopts=-N -Wall+  build-depends:       base+                     , ansi-wl-pprint+                     , jenkinsPlugins2nix+                     , text+  default-language:    Haskell2010++test-suite jenkinsPlugins2nix-test+  type:                exitcode-stdio-1.0+  hs-source-dirs:      test+  main-is:             Spec.hs+  other-modules:       Nix.JenkinsPlugins2Nix.Tests.Parser+  build-depends:       base+                     , containers+                     , jenkinsPlugins2nix+                     , tasty-hspec+                     , text+  ghc-options:         -threaded -rtsopts -with-rtsopts=-N -Wall+  default-language:    Haskell2010++source-repository head+  type:     git+  location: https://github.com/Fuuzetsu/jenkinsPlugins2nix
+ src/Nix/JenkinsPlugins2Nix.hs view
@@ -0,0 +1,131 @@+{-# LANGUAGE OverloadedStrings #-}+-- |+-- Module    : Nix.JenkinsPlugins2Nix.Types+-- Copyright : (c) 2017 Mateusz Kowalczyk+-- License   : BSD3+--+-- Main library entry point.+module Nix.JenkinsPlugins2Nix where++import qualified Codec.Archive.Zip as Zip+import           Control.Monad (foldM)+import qualified Control.Monad.Except as MTL+import qualified Crypto.Hash as Hash+import qualified Data.ByteString.Lazy as BSL+import           Data.Map.Strict (Map)+import qualified Data.Map.Strict as Map+import           Data.Monoid ((<>))+import           Data.Text (Text)+import qualified Data.Text as Text+import qualified Data.Text.Encoding as Text+import qualified Data.Text.IO as Text+import qualified Network.HTTP.Simple as HTTP+import qualified Nix.Expr as Nix+import qualified Nix.JenkinsPlugins2Nix.Parser as Parser+import           Nix.JenkinsPlugins2Nix.Types+import qualified Nix.Pretty as Nix+import           System.IO (stderr)+import qualified Text.PrettyPrint.ANSI.Leijen as Pretty+import           Text.Printf (printf)++-- | Get the download URL of the plugin we're looking for.+getPluginUrl :: RequestedPlugin -> Text+getPluginUrl (RequestedPlugin { requested_name = n, requested_version = Just v })+  = Text.pack+  $ printf "https://updates.jenkins-ci.org/download/plugins/%s/%s/%s.hpi"+           (Text.unpack n) (Text.unpack v) (Text.unpack n)+getPluginUrl (RequestedPlugin { requested_name = n, requested_version = Nothing })+  = Text.pack+  $ printf "https://updates.jenkins-ci.org/latest/%s.hpi"+           (Text.unpack n)++-- | Download a plugin from 'getPluginUrl'.+downloadPlugin :: RequestedPlugin -> IO (Either String Plugin)+downloadPlugin p = do+  let fullUrl = getPluginUrl p+  Text.hPutStrLn stderr $ "Downloading " <> fullUrl+  req <- HTTP.parseRequest $ Text.unpack fullUrl+  archiveLBS <- HTTP.getResponseBody <$> HTTP.httpLBS req+  let manifestFileText = fmap (Text.decodeUtf8 . BSL.toStrict . Zip.fromEntry)+                       $ Zip.findEntryByPath "META-INF/MANIFEST.MF"+                       $ Zip.toArchive archiveLBS+  case manifestFileText of+    Nothing -> return $ Left "Could not find manifest file in the archive."+    Just t -> return $! case Parser.runParseManifest t of+      Left err -> Left err+      Right manifest' -> Right $! Plugin+           -- We have to account for user not specifying the version.+           -- If they haven't, we downloaded the latest version and do+           -- not have a URL pointing at static resource. We do+           -- however have the version of the package now so we can+           -- reconstruct the URL.+        { download_url = getPluginUrl $+            p { requested_version = Just $! plugin_version manifest' }+        , sha256 = Hash.hashlazy archiveLBS+        , manifest = manifest'+        }++-- | Download the given plugin as well as recursively download its dependencies.+downloadPluginsRecursive :: Map Text Plugin -- ^ Already downloaded plugins.+                         -> RequestedPlugin -- ^ Plugins we're asked to download.+                         -> MTL.ExceptT String IO (Map Text Plugin)+downloadPluginsRecursive m p = if Map.member (requested_name p) m+  then return m+  else do+    plugin <- MTL.ExceptT $ downloadPlugin p+    foldM (\m' p' -> downloadPluginsRecursive m' $+              RequestedPlugin { requested_name = plugin_dependency_name p'+                              , requested_version = Just $ plugin_dependency_version p'+                              })+      (Map.insert (requested_name p) plugin m)+      (plugin_dependencies $ manifest plugin)++-- | Pretty-print nix expression for all the given plugins and their+-- dependencies that the user asked for.+mkExprsFor :: [RequestedPlugin]+           -> IO (Either String Pretty.Doc)+mkExprsFor ps = do+  eplugins <- MTL.runExceptT $ do+    plugins <- foldM downloadPluginsRecursive Map.empty ps+    return $ Map.elems plugins+  return $! case eplugins of+    Left err -> Left err+    Right plugins ->+      let args = Nix.mkParamset exprs+          res = Nix.mkNonRecSet $ map formatPlugin plugins+          mkJenkinsPlugin = Nix.bindTo "mkJenkinsPlugin" $+            Nix.mkFunction (Nix.mkParamset+                              [ ("name", Nothing)+                              , ("src", Nothing)+                              ]) $+              Nix.mkApp (Nix.mkSym "stdenv.mkDerivation") $ Nix.mkNonRecSet+                [ Nix.inherit [ Nix.StaticKey "name"+                              , Nix.StaticKey "src" ]+                , "phases" Nix.$= Nix.mkStr "installPhase"+                , "installPhase" Nix.$= Nix.mkStr "cp $src $out"+                ]+      in return $ Nix.prettyNix+                $ Nix.mkFunction args+                $ Nix.mkLets [mkJenkinsPlugin] res++  where+    fetchurl :: Plugin -> Nix.NExpr+    fetchurl p = Nix.mkApp (Nix.mkSym "fetchurl") $+      Nix.mkNonRecSet [ "url" Nix.$= Nix.mkUri (download_url p)+                      , "sha256" Nix.$= Nix.mkStr (Text.pack . show $ sha256 p)+                      ]++    mkBody :: Plugin -> Nix.NExpr+    mkBody p = Nix.mkApp (Nix.mkSym "mkJenkinsPlugin") $+      Nix.mkNonRecSet $ [ "name" Nix.$= Nix.mkStr (short_name $ manifest p)+                        , "src" Nix.$= fetchurl p+                        ]++    formatPlugin :: Plugin -> Nix.Binding Nix.NExpr+    formatPlugin p = short_name (manifest p) Nix.$= mkBody p++    exprs :: [(Text, Maybe Nix.NExpr)]+    exprs =+      [ ("stdenv", Nothing)+      , ("fetchurl", Nothing)+      ]
+ src/Nix/JenkinsPlugins2Nix/Parser.hs view
@@ -0,0 +1,145 @@+{-# LANGUAGE LambdaCase        #-}+{-# LANGUAGE OverloadedStrings #-}+-- |+-- Module    : Nix.JenkinsPlugins2Nix.Types+-- Copyright : (c) 2017 Mateusz Kowalczyk+-- License   : BSD3+--+-- Parsers.+module Nix.JenkinsPlugins2Nix.Parser+  ( parseManifest+  , runParseManifest+  ) where++import           Control.Applicative+import           Control.Monad (void)+import qualified Data.Attoparsec.Text as A+import           Data.Either (either)+import           Data.Map.Strict (Map)+import qualified Data.Map.Strict as Map+import           Data.Monoid ((<>))+import           Data.Set (Set)+import qualified Data.Set as Set+import           Data.Text (Text)+import qualified Data.Text as Text+import           Nix.JenkinsPlugins2Nix.Types++-- | Run parser on manifest file contents.+runParseManifest :: Text -> Either String Manifest+runParseManifest = A.parseOnly parseManifest++-- | 'Manifest' parser.+parseManifest :: A.Parser Manifest+parseManifest = do+  kvs <- kvMap+  let getKey :: Text -> Either String Text+      getKey k = case Map.lookup k kvs of+        Nothing -> Left $ "Could not find " <> Text.unpack k <> " in " <> show kvs+        Just v -> Right v++      getKeyParsing :: Text -> A.Parser a -> Either String a+      getKeyParsing k p = getKey k >>= A.parseOnly p++      eManifest :: Either String Manifest+      eManifest = do+        manifest_version' <- getKey "Manifest-Version"+        archiver_version' <- either (\_ -> Right Nothing) (return . Just) $+          getKey "Archiver-Version"+        created_by' <- either (\_ -> Right Nothing) (return . Just) $+          getKey "Created-By"+        built_by' <- either (\_ -> Right Nothing) (return . Just) $+          getKey "Built-By"+        build_jdk' <- either (\_ -> Right Nothing) (return . Just) $+          getKey "Build-Jdk"+        extension_name' <- either (\_ -> Right Nothing) (return . Just) $+          getKey "Extension-Name"+        specification_title' <- either (\_ -> Right Nothing) (return . Just) $+          getKey "Specification-Title"+        implementation_title' <- either (\_ -> Right Nothing) (return . Just) $+          getKey "Implementation-Title"+        implementation_version' <- either (\_ -> Right Nothing) (return . Just) $+          getKey "Implementation-Version"+        group_id' <- either (\_ -> Right Nothing) (return . Just) $+          getKey "Group-Id"+        short_name' <- getKey "Short-Name"+        long_name' <- getKey "Long-Name"+        url' <- getKey "Url"+        plugin_version' <- getKey "Plugin-Version"+        hudson_version' <- either (\_ -> Right Nothing) (return . Just) $+          getKey "Hudson-Version"+        jenkins_version' <- either (\_ -> Right Nothing) (return . Just) $+          getKey "Jenkins-Version"+        plugin_dependencies' <- either (\_ -> Right Set.empty) return $+          getKeyParsing "Plugin-Dependencies" parsePluginDependencies+        plugin_developers' <- either (\_ -> Right Set.empty) return $+          getKeyParsing "Plugin-Developers" parsePluginDevelopers+        return $! Manifest+          { manifest_version = manifest_version'+          , archiver_version = archiver_version'+          , created_by = created_by'+          , built_by = built_by'+          , build_jdk = build_jdk'+          , extension_name = extension_name'+          , specification_title = specification_title'+          , implementation_title = implementation_title'+          , implementation_version = implementation_version'+          , group_id = group_id'+          , short_name = short_name'+          , long_name = long_name'+          , url = url'+          , plugin_version = plugin_version'+          , hudson_version = hudson_version'+          , jenkins_version = jenkins_version'+          , plugin_dependencies = plugin_dependencies'+          , plugin_developers = plugin_developers'+          }+  case eManifest of+    Left err -> fail err+    Right m -> return m+  where+    parsePluginDevelopers :: A.Parser (Set Text)+    parsePluginDevelopers = Set.fromList . Text.splitOn "," <$> A.takeText++    parsePluginDependencies :: A.Parser (Set PluginDependency)+    parsePluginDependencies =+      let plugin = do+            name <- A.takeWhile1 (/= ':') <* A.char ':'+            version <- A.takeWhile1 (\c -> c /= ',' && c /= ';')+            resolution <- A.peekChar >>= \case+              -- end of input+              Nothing -> return Mandatory+              -- next dependency+              Just ',' -> A.char ',' *> return Mandatory+              -- specifier+              Just ';' -> do+                _ <- A.string ";resolution:="+                A.takeWhile1 (/= ',') >>= \case+                  "optional" -> return Optional+                  res' -> fail $ "Don't know how to parse resolution: " <> Text.unpack res'+              Just c -> fail $ "plugin: expected , or ; but got: " <> [c]++            -- Consume trailing comma if any+            void (A.char ',') <|> return ()+            return $! PluginDependency+              { plugin_dependency_name = name+              , plugin_dependency_version = version+              , plugin_dependency_resolution = resolution+              }+      in Set.fromList <$> many plugin++    -- Lines in manifest can span multiple file lines as long as they+    -- are indented with a space on next physical line.+    kvEntry :: A.Parser (Text, Text)+    kvEntry = do+      key <- A.takeWhile1 (/= ':')+      A.anyChar *> A.skipSpace+      let restOfLine = A.takeTill A.isEndOfLine <* (A.endOfLine <|> return ())+          indentedLine = A.peekChar' >>= \case+            ' ' -> A.skipSpace *> restOfLine+            _ -> fail "indentedLine doesn't start with a space"++      valueLines <- (:) <$> restOfLine <*> many indentedLine+      return $! (key, Text.concat valueLines)++    kvMap :: A.Parser (Map Text Text)+    kvMap = Map.fromList <$> many kvEntry
+ src/Nix/JenkinsPlugins2Nix/Types.hs view
@@ -0,0 +1,92 @@+{-# LANGUAGE StrictData #-}+-- |+-- Module    : Nix.JenkinsPlugins2Nix.Types+-- Copyright : (c) 2017 Mateusz Kowalczyk+-- License   : BSD3+--+-- Types used through-out jenkinsPlugins2nix+module Nix.JenkinsPlugins2Nix.Types+  ( Manifest(..)+  , Plugin(..)+  , PluginDependency(..)+  , PluginResolution(..)+  , RequestedPlugin(..)+  ) where++import qualified Crypto.Hash as Hash+import           Data.Set (Set)+import           Data.Text (Text)++-- | Plugin that user requested on the command line.+data RequestedPlugin = RequestedPlugin+  { -- | Name of the plugin.+    requested_name :: !Text+    -- | Possibly a specified version. If version not present, latest+    -- version is downloaded then pinned.+  , requested_version :: !(Maybe Text)+  } deriving (Show, Eq, Ord)++-- | Plugin resolution. Determines optional plugins.+data PluginResolution = Mandatory | Optional+  deriving (Show, Eq, Ord)++-- | A dependency on another plugin.+data PluginDependency = PluginDependency+  { -- | Is the dependency optional?+    plugin_dependency_resolution :: !PluginResolution+    -- | Name of the dependency.+  , plugin_dependency_name :: !Text+    -- | Version of the dependency.+  , plugin_dependency_version :: !Text+  } deriving (Show, Eq, Ord)++-- | All the information we need about the plugin to generate a nix+-- expression.+data Plugin = Plugin+  { -- | Download location of the plugin.+    download_url :: !Text+    -- | Checksum.+  , sha256 :: !(Hash.Digest Hash.SHA256)+    -- | Manifest information of the plugin.+  , manifest :: !Manifest+  } deriving (Show, Eq, Ord)++-- | Plugin meta-data.+data Manifest = Manifest+  { -- | @Manifest-Version@.+    manifest_version :: !Text+    -- | @Archiver-Version@.+  , archiver_version :: !(Maybe Text)+    -- | @Created-By@.+  , created_by :: !(Maybe Text)+    -- | @Built-By@.+  , built_by :: !(Maybe Text)+    -- | @Build-Jdk@.+  , build_jdk :: !(Maybe Text)+    -- | @Extension-Name@.+  , extension_name :: !(Maybe Text)+    -- | @Specification-Title@.+  , specification_title :: !(Maybe Text)+    -- | @Implementation-Title@.+  , implementation_title :: !(Maybe Text)+    -- | @Implementation-Version@.+  , implementation_version :: !(Maybe Text)+    -- | @Group-Id@.+  , group_id :: !(Maybe Text)+    -- | @Short-Name@.+  , short_name :: !Text+    -- | @Long-Name@.+  , long_name :: !Text+    -- | @Url@.+  , url :: !Text+    -- | @Plugin-Version@.+  , plugin_version :: !Text+    -- | @Hudson-Version@.+  , hudson_version :: !(Maybe Text)+    -- | @Jenkins-Version@.+  , jenkins_version :: !(Maybe Text)+    -- | @Plugin-Dependencies@.+  , plugin_dependencies :: !(Set PluginDependency)+    -- | @Plugin-Developers@.+  , plugin_developers :: !(Set Text)+  } deriving (Show, Eq, Ord)
+ test/Nix/JenkinsPlugins2Nix/Tests/Parser.hs view
@@ -0,0 +1,101 @@+{-# LANGUAGE OverloadedStrings #-}+-- |+-- Module    : Nix.JenkinsPlugins2Nix.Types+-- Copyright : (c) 2017 Mateusz Kowalczyk+-- License   : BSD3+--+-- Parser tests.+module Nix.JenkinsPlugins2Nix.Tests.Parser (spec) where++import qualified Data.Set as Set+import qualified Data.Text as Text+import           Nix.JenkinsPlugins2Nix.Parser (runParseManifest)+import           Nix.JenkinsPlugins2Nix.Types+import qualified Test.Tasty.Hspec as Hspec++spec :: Hspec.Spec+spec = Hspec.describe "parser spec" $ do+  Hspec.it "parser github-pullrequest manifest" githubPr++githubPr :: Hspec.Expectation+githubPr = Right expected `Hspec.shouldBe` runParseManifest githubPrManifestText+  where+    pluginDependencies :: Set.Set PluginDependency+    pluginDependencies = Set.fromList+      [ PluginDependency { plugin_dependency_resolution = Mandatory+                         , plugin_dependency_name = "github"+                         , plugin_dependency_version  = "1.22.1" }+      , PluginDependency { plugin_dependency_resolution = Mandatory+                         , plugin_dependency_name = "workflow-step-api"+                         , plugin_dependency_version = "1.14" }+      , PluginDependency { plugin_dependency_resolution = Optional+                         , plugin_dependency_name = "block-queued-job"+                         , plugin_dependency_version = "0.2.0" }+      , PluginDependency { plugin_dependency_resolution = Optional+                         , plugin_dependency_name = "email-ext"+                         , plugin_dependency_version = "2.38.2" }+      , PluginDependency { plugin_dependency_resolution = Mandatory+                         , plugin_dependency_name = "github-api"+                         , plugin_dependency_version = "1.80" }+      , PluginDependency { plugin_dependency_resolution = Optional+                         , plugin_dependency_name = "job-dsl"+                         , plugin_dependency_version = "1.38" }+      , PluginDependency { plugin_dependency_resolution = Optional+                         , plugin_dependency_name = "jucies"+                         , plugin_dependency_version = "0.2.1" }+      , PluginDependency { plugin_dependency_resolution = Mandatory+                         , plugin_dependency_name = "matrix-project"+                         , plugin_dependency_version = "1.6" }+      , PluginDependency { plugin_dependency_resolution = Optional+                         , plugin_dependency_name = "token-macro"+                         , plugin_dependency_version = "1.10" }+      ]++    expected :: Manifest+    expected = Manifest+      { manifest_version = "1.0"+      , archiver_version = Just "Plexus Archiver"+      , created_by = Just "Apache Maven"+      , built_by = Just "integer"+      , build_jdk = Just "1.8.0_112"+      , extension_name = Just "github-pullrequest"+      , specification_title = Just "GitHub Integration Plugin for Jenkins"+      , implementation_title = Just "github-pullrequest"+      , implementation_version = Just "0.1.0-rc24"+      , group_id = Just "org.jenkins-ci.plugins"+      , short_name = "github-pullrequest"+      , long_name = "GitHub Integration Plugin"+      , url = "https://wiki.jenkins-ci.org/display/JENKINS/GitHub+Integration+Plugin"+      , plugin_version = "0.1.0-rc24"+      , hudson_version = Just "1.625.3"+      , jenkins_version = Just "1.625.3"+      , plugin_dependencies = pluginDependencies+      , plugin_developers = Set.fromList ["Kanstantsin Shautsou:KostyaSha:"]+      }++githubPrManifestText :: Text.Text+githubPrManifestText = Text.intercalate "\r\n"+  [ "Manifest-Version: 1.0"+  , "Archiver-Version: Plexus Archiver"+  , "Created-By: Apache Maven"+  , "Built-By: integer"+  , "Build-Jdk: 1.8.0_112"+  , "Extension-Name: github-pullrequest"+  , "Specification-Title: GitHub Integration Plugin for Jenkins"+  , "Implementation-Title: github-pullrequest"+  , "Implementation-Version: 0.1.0-rc24"+  , "Group-Id: org.jenkins-ci.plugins"+  , "Short-Name: github-pullrequest"+  , "Long-Name: GitHub Integration Plugin"+  , "Url: https://wiki.jenkins-ci.org/display/JENKINS/GitHub+Integration+Pl"+  , " ugin"+  , "Plugin-Version: 0.1.0-rc24"+  , "Hudson-Version: 1.625.3"+  , "Jenkins-Version: 1.625.3"+  , "Plugin-Dependencies: github:1.22.1,workflow-step-api:1.14,block-queued"+  , " -job:0.2.0;resolution:=optional,email-ext:2.38.2;resolution:=optional"+  , " ,github-api:1.80,job-dsl:1.38;resolution:=optional,jucies:0.2.1;resol"+  , " ution:=optional,matrix-project:1.6,token-macro:1.10;resolution:=optio"+  , " nal"+  , "Plugin-Developers: Kanstantsin Shautsou:KostyaSha:"+  ]
+ test/Spec.hs view
@@ -0,0 +1,8 @@+module Main where++import qualified Nix.JenkinsPlugins2Nix.Tests.Parser as Parser+import qualified Test.Tasty.Hspec as Hspec++main :: IO ()+main = Hspec.hspec $ do+  Parser.spec