travis-meta-yaml (empty) → 0.0.1.0
raw patch · 10 files changed
+425/−0 lines, 10 filesdep +aesondep +basedep +bytestringsetup-changed
Dependencies added: aeson, base, bytestring, extra, file-embed, lens, lens-aeson, optparse-applicative, regex-applicative, tasty, tasty-quickcheck, text, travis-meta-yaml, yaml
Files
- LICENSE +30/−0
- README.md +64/−0
- Setup.hs +2/−0
- cli/Main.hs +30/−0
- fixtures/matrix-include.yml +4/−0
- fixtures/without-matrix-processed.yml +39/−0
- fixtures/without-matrix.yml +30/−0
- src/Travis/Meta.hs +105/−0
- tests/Tests.hs +37/−0
- travis-meta-yaml.cabal +84/−0
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2015, Oleg Grenrus++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 Oleg Grenrus 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,64 @@+# travis-meta-yaml++[](https://travis-ci.org/phadej/travis-meta-yaml)+[](http://hackage.haskell.org/package/travis-meta-yaml)++## Motivation++Turn++```yaml+env:+ - CABALVER=1.18 GHCVER=7.8.4+ - CABALVER=1.22 GHCVER=7.10.1+ - CABALVER=1.22 GHCVER=head++addons:+ apt:+ sources:+ - hvr-ghc+ packages:+ - cabal-install-$CABALVER+ - ghc-$GHCVER++matrix:+ allow_failures:+ - env: CABALVER=1.22 GHCVER=head+```++into++```yaml+matrix:+ include:+ - env: CABALVER=1.18 GHCVER=7.8.4+ addons:+ apt:+ sources:+ - hvr-ghc+ packages:+ - cabal-install-1.18+ - ghc-7.8.4+ - env: CABALVER=1.22 GHCVER=7.10.1+ addons:+ apt:+ sources:+ - hvr-ghc+ packages:+ - cabal-install-1.22+ - ghc-7.10.1+ - env: CABALVER=1.22 GHCVER=head+ addons:+ apt:+ sources:+ - hvr-ghc+ packages:+ - cabal-install-1.22+ - ghc-head+ allow_failures:+ - env: CABALVER=1.22 GHCVER=head+```++## Features++Currently only expanding of `addons.apt`. Any feature requests are welcome.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ cli/Main.hs view
@@ -0,0 +1,30 @@+module Main (main) where++import Travis.Meta+import Options.Applicative++data Opts = Opts+ { _source :: FilePath+ , _target :: FilePath+ }+ deriving (Eq, Show)++sample :: Parser Opts+sample = Opts+ <$> strArgument+ ( metavar "SOURCE"+ <> value ".travis.meta.yml"+ <> showDefault+ <> help "Source, travis meta file" )+ <*> strArgument+ ( metavar "TARGET"+ <> value ".travis.yml"+ <> showDefault+ <> help "Target, travis yaml" )++main :: IO ()+main = execParser opts >>= \(Opts source target) -> preprocessIO source target+ where+ opts = info (helper <*> sample)+ ( fullDesc+ <> header "travis-meta-yaml - .travis.yml preprocessor" )
+ fixtures/matrix-include.yml view
@@ -0,0 +1,4 @@+matrix:+ include:+ - env: FOO=foo+ - env: FOO=bar
+ fixtures/without-matrix-processed.yml view
@@ -0,0 +1,39 @@+script:+- cabal configure --enable-tests+- cabal test -j2+matrix:+ include:+ - env: CABALVER=1.18 GHCVER=7.8.4+ addons:+ apt:+ sources:+ - hvr-ghc+ packages:+ - cabal-1.18+ - ghc-7.8.4+ - env: CABALVER=1.22 GHCVER=7.10.1+ addons:+ apt:+ sources:+ - hvr-ghc+ packages:+ - cabal-1.22+ - ghc-7.10.1+ - env: CABALVER=1.22 GHCVER=head+ addons:+ apt:+ sources:+ - hvr-ghc+ packages:+ - cabal-1.22+ - ghc-head+install:+- cabal install -j2 --only-dependencies --enable-tests+before_install:+- export PATH=/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$PATH+- stack +RTS -N1 -RTS --version+- echo "$(ghc --version) [$(ghc --print-project-git-commit-id 2> /dev/null || echo+ '?')]"+- cabal --version+- cabal install -j2 --only-dependencies --enable-tests+sudo: false
+ fixtures/without-matrix.yml view
@@ -0,0 +1,30 @@+sudo: false++env:+ - CABALVER=1.18 GHCVER=7.8.4+ - CABALVER=1.22 GHCVER=7.10.1+ - CABALVER=1.22 GHCVER=head++addons:+ apt:+ sources:+ - hvr-ghc+ packages:+ - cabal-$CABALVER+ - ghc-$GHCVER++before_install:+ # ghc+ - export PATH=/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$PATH+ # versions+ - stack +RTS -N1 -RTS --version+ - echo "$(ghc --version) [$(ghc --print-project-git-commit-id 2> /dev/null || echo '?')]"+ - cabal --version+ - cabal install -j2 --only-dependencies --enable-tests++install:+ - cabal install -j2 --only-dependencies --enable-tests++script:+ - cabal configure --enable-tests+ - cabal test -j2
+ src/Travis/Meta.hs view
@@ -0,0 +1,105 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RankNTypes #-}+module Travis.Meta (+ -- * High level+ preprocessIO+ , preprocess+ , preprocessYaml+ -- * Internal+ , Env+ , parseEnv+ , interpolateEnv+ ) where++import Control.Lens+import Control.Monad hiding (sequence)+import Data.Aeson.Types+import Data.Aeson.Lens+import Data.ByteString as BS+import Data.Char+import Data.Maybe+import Data.Monoid+import Data.Text as T+import Data.Traversable+import Data.Yaml+import Prelude hiding (sequence)+import Text.Regex.Applicative++type Env = [(Text, Text)]++-- | Parse environment string.+--+-- > >>> parseEnv "CABALVER=1.18 GHCVER=7.8.4"+-- > Right [("CABALVER","1.18"),("GHCVER","7.8.4")]+parseEnv :: Text -> Either String Env+parseEnv = traverse (f . T.splitOn "=") . T.words+ where f [k, n] = Right (k, n)+ f _ = Left "Cannot parse"++-- > match (interpolationRe $ flip lookup [("foo", "bar")]) "$foo"+-- Just (Just "bar")+interpolationRe :: (String -> Maybe String) -> RE Char (Maybe String)+interpolationRe l = comb <$> many (interpolationChar l)+ where comb :: [Maybe [a]] -> Maybe [a]+ comb = fmap Prelude.concat . sequence++interpolationChar :: (String -> Maybe String) -> RE Char (Maybe String)+interpolationChar l = var <|> other+ where var = l <$ sym '$' <*> many (psym isAlpha)+ other = (\x -> Just [x]) <$> anySym++-- | Interpolate env. Substitute all @$VAR@ occurrences with values from 'Env'.+-- If variable is not in the environment, return 'Nothing'.+--+-- > >>> interpolateEnv [("FOO", "foo")] "res-$FOO-bar"+-- > Just "res-foo-bar"+--+-- > >>> interpolateEnv [("FOO","foo")] "yes-$FOOBAR-$FOO"+-- > Nothing+interpolateEnv :: Env -> Text -> Either String Text+interpolateEnv env = hoist . fmap T.pack . join . match (interpolationRe l) . T.unpack+ where l = fmap T.unpack . flip lookup env . T.pack++hoist :: Maybe a -> Either String a+hoist Nothing = Left "error in interpolation"+hoist (Just a) = Right a++preprocessYaml :: Value -> Either String Value+preprocessYaml v = do+ assertNoMatrixInclude v+ matrixInclude <- buildMatrixInclude v+ let v' = v & _Object . at "env" .~ Nothing+ & _Object . at "addons" .~ Nothing+ & _Object . at "matrix" ?~ (fromMaybe (Object mempty) (v ^? key "matrix"))+ & key "matrix" . _Object . at "include" ?~ matrixInclude+ return v'++buildMatrixInclude :: Value -> Either String Value+buildMatrixInclude v = toJSON <$> mk `traverse` envs+ where addons = v ^? key "addons"+ envs = v ^.. key "env" . values . _String+ mk env = do env' <- parseEnv env+ addons' <- traverseOf (deep _String) (interpolateEnv env') `traverse` addons+ case addons' of+ Just addons'' -> return $ object [ "env" Data.Yaml..= env, "addons" Data.Yaml..= addons'' ]+ Nothing -> return $ object [ "env" Data.Yaml..= env ]+ ++assertNoMatrixInclude :: Value -> Either String ()+assertNoMatrixInclude v =+ case v ^? key "matrix" . key "include" of+ Nothing -> Right ()+ Just v' -> Left $ "matrix.include specified: " ++ show v'++preprocess :: ByteString -> Either String ByteString+preprocess = fmap encode . preprocessYaml <=< decodeEither++preprocessIO :: FilePath -> FilePath -> IO ()+preprocessIO source target = do+ contents <- BS.readFile source+ case preprocess contents of+ Left err -> error err+ Right bs -> BS.writeFile target bs++-- Right v <- decodeEither <$> BS.readFile ".travis.meta.yml" :: IO (Either String Value)+-- BS.putStr $ encode $ preprocessYaml v
+ tests/Tests.hs view
@@ -0,0 +1,37 @@+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE RankNTypes #-}+module Main (main) where++import Data.Either.Extra+import Data.FileEmbed+import Data.Yaml+import Test.Tasty+import Test.Tasty.QuickCheck++import Travis.Meta++main :: IO ()+main = Test.Tasty.defaultMain tests++tests :: TestTree+tests = testGroup "Tests"+ [ selfTest+ , withoutMatrix+ , errorCases+ ]++selfTest :: TestTree+selfTest = testProperty "Self test" $ once $ actual === processed+ where actual = decodeEither $(embedFile ".travis.yml")+ processed = preprocessYaml =<< decodeEither $(embedFile ".travis.meta.yml")++withoutMatrix :: TestTree+withoutMatrix = testProperty "Self test without matrix" $ once $ actual === processed+ where actual = decodeEither $(embedFile "fixtures/without-matrix-processed.yml")+ processed = preprocessYaml =<< decodeEither $(embedFile "fixtures/without-matrix.yml")++errorCases :: TestTree+errorCases = testGroup "Error cases"+ [ c "matrix.include specified" $(embedFile "fixtures/matrix-include.yml")+ ]+ where c name bs = testProperty name $ once $ isLeft $ preprocess bs
+ travis-meta-yaml.cabal view
@@ -0,0 +1,84 @@+-- This file has been generated from package.yaml by hpack version 0.5.2.+--+-- see: https://github.com/sol/hpack++name: travis-meta-yaml+version: 0.0.1.0+synopsis: .travis.yml preprocessor+description: .travis.yml preprocessor+category: Development+homepage: https://github.com/phadej/travis-meta-yaml#readme+bug-reports: https://github.com/phadej/travis-meta-yaml/issues+author: Oleg Grenrus <oleg.grenrus@iki.fi>+maintainer: Oleg Grenrus <oleg.grenrus@iki.fi>+license: BSD3+license-file: LICENSE+build-type: Simple+cabal-version: >= 1.10++extra-source-files:+ fixtures/matrix-include.yml+ fixtures/without-matrix-processed.yml+ fixtures/without-matrix.yml+ README.md++source-repository head+ type: git+ location: https://github.com/phadej/travis-meta-yaml++library+ hs-source-dirs:+ src+ ghc-options: -Wall+ build-depends:+ base >=4.7 && <4.9+ , aeson+ , bytestring+ , lens-aeson+ , lens+ , text+ , regex-applicative+ , yaml+ exposed-modules:+ Travis.Meta+ default-language: Haskell2010++executable travis-meta-yaml+ main-is: Main.hs+ hs-source-dirs:+ cli+ ghc-options: -Wall+ build-depends:+ base >=4.7 && <4.9+ , aeson+ , bytestring+ , lens-aeson+ , lens+ , text+ , regex-applicative+ , yaml+ , travis-meta-yaml+ , optparse-applicative+ default-language: Haskell2010++test-suite tests+ type: exitcode-stdio-1.0+ main-is: Tests.hs+ hs-source-dirs:+ tests+ ghc-options: -Wall+ build-depends:+ base >=4.7 && <4.9+ , aeson+ , bytestring+ , lens-aeson+ , lens+ , text+ , regex-applicative+ , yaml+ , extra+ , file-embed+ , travis-meta-yaml+ , tasty+ , tasty-quickcheck+ default-language: Haskell2010