Add cabal check to ci, build strictly (once)

This commit is contained in:
Robert Hensing 2019-10-04 19:09:29 +02:00
parent 41d4fefd64
commit 7749eb2ef9
11 changed files with 49 additions and 73 deletions

View file

@ -1,9 +1,9 @@
cabal-version: 2.4 cabal-version: 2.4
name: arion-compose name: arion-compose
version: 0.1.0.0 version: 0.1.0.0
synopsis: Run docker-compose with help from Nix/NixOS synopsis: Run docker-compose with help from Nix/NixOS
-- description: description: Arion is a tool for building and running applications that consist of multiple docker containers using NixOS modules. It has special support for docker images that are built with Nix, for a smooth development experience and improved performance.
homepage: https://github.com/hercules-ci/arion#readme homepage: https://github.com/hercules-ci/arion#readme
-- bug-reports: -- bug-reports:
license: Apache-2.0 license: Apache-2.0
@ -11,10 +11,10 @@ license-file: LICENSE
author: Robert Hensing author: Robert Hensing
maintainer: robert@hercules-ci.com maintainer: robert@hercules-ci.com
-- copyright: -- copyright:
-- category: category: Distribution, Network, Cloud, Distributed Computing
extra-source-files: CHANGELOG.md, README.asciidoc extra-source-files: CHANGELOG.md, README.asciidoc,
write-ghc-enviroment-files: src/haskell/testdata/**/*.nix
never src/haskell/testdata/**/*.json
data-files: nix/*.nix data-files: nix/*.nix
, nix/modules/composition/*.nix , nix/modules/composition/*.nix
, nix/modules/nixos/*.nix , nix/modules/nixos/*.nix
@ -24,7 +24,7 @@ data-files: nix/*.nix
-- all data is verbatim from some sources -- all data is verbatim from some sources
data-dir: src data-dir: src
common deps common common
build-depends: base ^>=4.12.0.0 build-depends: base ^>=4.12.0.0
, aeson , aeson
, aeson-pretty , aeson-pretty
@ -38,25 +38,27 @@ common deps
, text , text
, protolude , protolude
, unix , unix
ghc-options: -Wall
flag ghci flag ghci
default: False default: False
manual: True manual: True
library library
import: deps import: common
exposed-modules: Arion.Nix exposed-modules: Arion.Nix
Arion.Aeson Arion.Aeson
Arion.DockerCompose Arion.DockerCompose
Arion.Images Arion.Images
Arion.Services Arion.Services
other-modules: Paths_arion_compose other-modules: Paths_arion_compose
autogen-modules: Paths_arion_compose
-- other-extensions: -- other-extensions:
hs-source-dirs: src/haskell/lib hs-source-dirs: src/haskell/lib
default-language: Haskell2010 default-language: Haskell2010
executable arion executable arion
import: deps import: common
main-is: Main.hs main-is: Main.hs
-- other-modules: -- other-modules:
-- other-extensions: -- other-extensions:
@ -66,7 +68,7 @@ executable arion
default-language: Haskell2010 default-language: Haskell2010
test-suite arion-unit-tests test-suite arion-unit-tests
import: deps import: common
if flag(ghci) if flag(ghci)
hs-source-dirs: src/haskell/lib hs-source-dirs: src/haskell/lib
ghc-options: -Wno-missing-home-modules ghc-options: -Wno-missing-home-modules

View file

@ -7,6 +7,7 @@ in
dimension "Nixpkgs version" { dimension "Nixpkgs version" {
"nixos-19_03" = { "nixos-19_03" = {
nixpkgsSource = "nixpkgs"; nixpkgsSource = "nixpkgs";
isReferenceNixpkgs = true;
}; };
"nixos-unstable" = { "nixos-unstable" = {
nixpkgsSource = "nixos-unstable"; nixpkgsSource = "nixos-unstable";
@ -16,15 +17,15 @@ dimension "Nixpkgs version" {
enableDoc = false; enableDoc = false;
}; };
} ( } (
_name: { nixpkgsSource, enableDoc ? true }: _name: { nixpkgsSource, isReferenceNixpkgs ? false, enableDoc ? true }:
dimension "System" { dimension "System" {
"x86_64-linux" = {}; "x86_64-linux" = { isReferenceTarget = isReferenceNixpkgs; };
# TODO: darwin # TODO: darwin
# "x86_64-darwin" = { enableNixOSTests = false; }; # "x86_64-darwin" = { enableNixOSTests = false; };
} ( } (
system: {}: system: { isReferenceTarget ? false }:
let let
pkgs = import ./. { inherit system; nixpkgsSrc = sources.${nixpkgsSource}; }; pkgs = import ./. { inherit system; nixpkgsSrc = sources.${nixpkgsSource}; };
in in
@ -32,6 +33,8 @@ dimension "Nixpkgs version" {
inherit (pkgs) arion tests; inherit (pkgs) arion tests;
} // lib.optionalAttrs enableDoc { } // lib.optionalAttrs enableDoc {
doc = pkgs.recurseIntoAttrs (import ../doc { inherit pkgs; }); doc = pkgs.recurseIntoAttrs (import ../doc { inherit pkgs; });
} // lib.optionalAttrs isReferenceTarget {
inherit (pkgs.arion-project.haskellPkgs) arion-compose-checked;
} }
) )
) )

View file

@ -1,4 +1,16 @@
self: super: hself: hsuper: self: super: hself: hsuper:
{ {
arion-compose = import ./haskell-arion-compose.nix { pkgs = self; haskellPackages = hself; }; arion-compose = import ./haskell-arion-compose.nix { pkgs = self; haskellPackages = hself; };
arion-compose-checked =
let pkg = super.haskell.lib.buildStrictly hself.arion-compose;
checked = super.haskell.lib.overrideCabal pkg (o: {
postConfigure = ''${o.postConfigure or ""}
if ! ${hsuper.cabal-install}/bin/cabal check;
then
echo 1>&2 ERROR: cabal file is invalid. Above warnings were errors.
exit 1
fi
'';
});
in checked;
} }

View file

@ -12,20 +12,13 @@ import qualified Arion.DockerCompose as DockerCompose
import Arion.Services (getDefaultExec) import Arion.Services (getDefaultExec)
import Options.Applicative import Options.Applicative
import Control.Applicative
import Control.Monad.Fail import Control.Monad.Fail
import qualified Data.Aeson.Encode.Pretty
import qualified Data.Text as T import qualified Data.Text as T
import qualified Data.Text.IO as T import qualified Data.Text.IO as T
import qualified Data.Text.Lazy as TL
import qualified Data.Text.Lazy.Builder as TB
import qualified Data.List.NonEmpty as NE
import Data.List.NonEmpty (NonEmpty(..)) import Data.List.NonEmpty (NonEmpty(..))
import Control.Arrow ((>>>))
import System.Posix.User (getRealUserID) import System.Posix.User (getRealUserID)
data CommonOptions = data CommonOptions =
@ -69,6 +62,7 @@ parseOptions = do
let nixArgs = userNixArgs <|> "--show-trace" <$ guard showTrace let nixArgs = userNixArgs <|> "--show-trace" <$ guard showTrace
in CommonOptions{..} in CommonOptions{..}
textArgument :: Mod ArgumentFields [Char] -> Parser Text
textArgument = fmap T.pack . strArgument textArgument = fmap T.pack . strArgument
parseCommand :: Parser (CommonOptions -> IO ()) parseCommand :: Parser (CommonOptions -> IO ())
@ -124,18 +118,18 @@ commandDC
-> Text -> Text
-> Text -> Text
-> Mod CommandFields (CommonOptions -> IO ()) -> Mod CommandFields (CommonOptions -> IO ())
commandDC run cmdStr help = commandDC run cmdStr helpText =
command command
(T.unpack cmdStr) (T.unpack cmdStr)
(info (info
(run cmdStr <$> parseDockerComposeArgs) (run cmdStr <$> parseDockerComposeArgs)
(progDesc (T.unpack help) <> fullDesc <> forwardOptions)) (progDesc (T.unpack helpText) <> fullDesc <> forwardOptions))
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
runDC :: Text -> DockerComposeArgs -> CommonOptions -> IO () runDC :: Text -> DockerComposeArgs -> CommonOptions -> IO ()
runDC cmd (DockerComposeArgs args) opts = do runDC cmd (DockerComposeArgs args) _opts = do
DockerCompose.run DockerCompose.Args DockerCompose.run DockerCompose.Args
{ files = [] { files = []
, otherArgs = [cmd] ++ args , otherArgs = [cmd] ++ args
@ -265,7 +259,7 @@ runExec detach privileged user noTTY index envs workDir service commandAndArgs o
main :: IO () main :: IO ()
main = main =
(join . execParser) (info (parseAll <**> helper) fullDesc) (join . arionExecParser) (info (parseAll <**> helper) fullDesc)
where where
execParser = customExecParser (prefs showHelpOnEmpty) arionExecParser = customExecParser (prefs showHelpOnEmpty)

View file

@ -4,11 +4,9 @@ import Prelude ()
import Data.Aeson import Data.Aeson
import qualified Data.ByteString.Lazy as BL import qualified Data.ByteString.Lazy as BL
import qualified Data.Text.Lazy as TL import qualified Data.Text.Lazy as TL
import qualified Data.Text.Lazy.IO as TL
import qualified Data.Text.Lazy.Builder as TB import qualified Data.Text.Lazy.Builder as TB
import qualified Data.Aeson.Encode.Pretty import qualified Data.Aeson.Encode.Pretty
import Data.Aeson.Encode.Pretty ( defConfig import Data.Aeson.Encode.Pretty ( defConfig
, keyOrder
, confCompare , confCompare
, confTrailingNewline , confTrailingNewline
) )

View file

@ -3,24 +3,7 @@ module Arion.DockerCompose where
import Prelude ( ) import Prelude ( )
import Protolude import Protolude
import Arion.Aeson ( pretty )
import Data.Aeson
import qualified Data.String
import System.Process import System.Process
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BL
import Paths_arion_compose
import Control.Applicative
import qualified Data.Text as T
import qualified Data.Text.IO as T
import qualified Data.List.NonEmpty as NE
import Data.List.NonEmpty ( NonEmpty(..) )
import Control.Arrow ( (>>>) )
import System.IO.Temp ( withTempFile )
import System.IO ( hClose )
data Args = Args data Args = Args
{ files :: [FilePath] { files :: [FilePath]
@ -43,6 +26,5 @@ run args = do
case exitCode of case exitCode of
ExitSuccess -> pass ExitSuccess -> pass
ExitFailure 1 -> exitFailure ExitFailure 1 -> exitFailure
e@ExitFailure {} -> do ExitFailure {} -> do
throwIO $ FatalError $ "docker-compose failed with " <> show exitCode throwIO $ FatalError $ "docker-compose failed with " <> show exitCode
exitWith e

View file

@ -10,7 +10,6 @@ import Protolude hiding (to)
import qualified Data.Aeson as Aeson import qualified Data.Aeson as Aeson
import Arion.Aeson (decodeFile) import Arion.Aeson (decodeFile)
import qualified Data.ByteString as BS
import qualified System.Process as Process import qualified System.Process as Process
import Control.Lens import Control.Lens

View file

@ -16,12 +16,9 @@ import Data.Aeson
import qualified Data.String import qualified Data.String
import qualified System.Directory as Directory import qualified System.Directory as Directory
import System.Process import System.Process
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BL import qualified Data.ByteString.Lazy as BL
import Paths_arion_compose import Paths_arion_compose
import Control.Applicative
import qualified Data.Text as T
import qualified Data.Text.IO as T import qualified Data.Text.IO as T
import qualified Data.List.NonEmpty as NE import qualified Data.List.NonEmpty as NE
@ -76,21 +73,20 @@ evaluateComposition ea = do
case exitCode of case exitCode of
ExitSuccess -> pass ExitSuccess -> pass
ExitFailure 1 -> exitFailure ExitFailure 1 -> exitFailure
e@ExitFailure {} -> do ExitFailure {} -> do
throwIO $ FatalError $ "evaluation failed with " <> show exitCode throwIO $ FatalError $ "evaluation failed with " <> show exitCode
exitWith e
case v of case v of
Right r -> pure r Right r -> pure r
Left e -> throwIO $ FatalError "Couldn't parse nix-instantiate output" Left e -> throwIO $ FatalError ("Couldn't parse nix-instantiate output" <> show e)
-- | Run with docker-compose.yaml tmpfile -- | Run with docker-compose.yaml tmpfile
withEvaluatedComposition :: EvaluationArgs -> (FilePath -> IO r) -> IO r withEvaluatedComposition :: EvaluationArgs -> (FilePath -> IO r) -> IO r
withEvaluatedComposition ea f = do withEvaluatedComposition ea f = do
v <- evaluateComposition ea v <- evaluateComposition ea
withTempFile "." ".tmp-arion-docker-compose.yaml" $ \path handle -> do withTempFile "." ".tmp-arion-docker-compose.yaml" $ \path yamlHandle -> do
T.hPutStrLn handle (pretty v) T.hPutStrLn yamlHandle (pretty v)
hClose handle hClose yamlHandle
f path f path
@ -117,15 +113,14 @@ buildComposition outLink ea = do
case exitCode of case exitCode of
ExitSuccess -> pass ExitSuccess -> pass
ExitFailure 1 -> exitFailure ExitFailure 1 -> exitFailure
e@ExitFailure {} -> do ExitFailure {} -> do
throwIO $ FatalError $ "nix-build failed with " <> show exitCode throwIO $ FatalError $ "nix-build failed with " <> show exitCode
exitWith e
-- | Do something with a docker-compose.yaml. -- | Do something with a docker-compose.yaml.
withBuiltComposition :: EvaluationArgs -> (FilePath -> IO r) -> IO r withBuiltComposition :: EvaluationArgs -> (FilePath -> IO r) -> IO r
withBuiltComposition ea f = do withBuiltComposition ea f = do
withTempFile "." ".tmp-arion-docker-compose.yaml" $ \path handle -> do withTempFile "." ".tmp-arion-docker-compose.yaml" $ \path emptyYamlHandle -> do
hClose handle hClose emptyYamlHandle
-- Known problem: kills atomicity of withTempFile; won't fix because we should manage gc roots, -- Known problem: kills atomicity of withTempFile; won't fix because we should manage gc roots,
-- impl of which will probably avoid this "problem". It seems unlikely to cause issues. -- impl of which will probably avoid this "problem". It seems unlikely to cause issues.
Directory.removeFile path Directory.removeFile path
@ -149,9 +144,8 @@ replForComposition ea = do
case exitCode of case exitCode of
ExitSuccess -> pass ExitSuccess -> pass
ExitFailure 1 -> exitFailure ExitFailure 1 -> exitFailure
e@ExitFailure {} -> do ExitFailure {} -> do
throwIO $ FatalError $ "nix repl failed with " <> show exitCode throwIO $ FatalError $ "nix repl failed with " <> show exitCode
exitWith e
argArgs :: EvaluationArgs -> [[Char]] argArgs :: EvaluationArgs -> [[Char]]
argArgs ea = argArgs ea =

View file

@ -10,13 +10,9 @@ import Protolude hiding (to)
import qualified Data.Aeson as Aeson import qualified Data.Aeson as Aeson
import Arion.Aeson (decodeFile) import Arion.Aeson (decodeFile)
import qualified Data.ByteString as BS
import qualified System.Process as Process
import Control.Lens import Control.Lens
import Data.Aeson.Lens import Data.Aeson.Lens
import Data.String
import System.IO (withFile, IOMode(ReadMode))
-- | Subject to change -- | Subject to change
getDefaultExec :: FilePath -> Text -> IO [Text] getDefaultExec :: FilePath -> Text -> IO [Text]

View file

@ -6,16 +6,11 @@ where
import Protolude import Protolude
import Test.Hspec import Test.Hspec
import Test.QuickCheck
import qualified Data.List.NonEmpty as NEL import qualified Data.List.NonEmpty as NEL
import Arion.Aeson import Arion.Aeson
import Arion.Nix import Arion.Nix
import qualified Data.Text as T import qualified Data.Text as T
import qualified Data.Text.IO as T import qualified Data.Text.IO as T
import qualified Data.Text.Lazy.IO as TL
import qualified Data.Text.Lazy.Builder as TB
import qualified Data.Aeson.Encode.Pretty
import Data.Char (isSpace)
spec :: Spec spec :: Spec
spec = describe "evaluateComposition" $ it "matches an example" $ do spec = describe "evaluateComposition" $ it "matches an example" $ do
@ -32,8 +27,8 @@ spec = describe "evaluateComposition" $ it "matches an example" $ do
expected <- T.readFile "src/haskell/testdata/Arion/NixSpec/arion-compose.json" expected <- T.readFile "src/haskell/testdata/Arion/NixSpec/arion-compose.json"
censorPaths actual `shouldBe` censorPaths expected censorPaths actual `shouldBe` censorPaths expected
censorPaths :: Text -> Text
censorPaths = censorImages . censorStorePaths censorPaths = censorImages . censorStorePaths
--censorPaths = censorStorePaths
censorStorePaths :: Text -> Text censorStorePaths :: Text -> Text
censorStorePaths x = case T.breakOn "/nix/store/" x of censorStorePaths x = case T.breakOn "/nix/store/" x of
@ -61,4 +56,4 @@ isNixNameChar c | c >= 'A' && c <= 'Z' = True
isNixNameChar c | c == '-' = True isNixNameChar c | c == '-' = True
isNixNameChar c | c == '.' = True isNixNameChar c | c == '.' = True
isNixNameChar c | c == '_' = True -- WRONG? isNixNameChar c | c == '_' = True -- WRONG?
isNixNameChar c = False -- WRONG? isNixNameChar _ = False -- WRONG?

View file

@ -1,5 +1,6 @@
module Main where module Main where
import Prelude()
import Protolude import Protolude
import Test.Hspec.Runner import Test.Hspec.Runner
import qualified Spec import qualified Spec