templatise (empty) → 0.1.0.1
raw patch · 28 files changed
+1527/−0 lines, 28 filesdep +Cabal-syntaxdep +basedep +bytestringsetup-changed
Dependencies added: Cabal-syntax, base, bytestring, directory, exceptions, extra, filepath, hspec, http-client, http-conduit, mtl, network-uri, optparse-applicative, parsec, process, tasty, tasty-golden, tasty-hspec, templatise, temporary, text, time
Files
- CHANGELOG.md +5/−0
- LICENSE +24/−0
- README.md +51/−0
- Setup.hs +3/−0
- bin/initialise/Main.hs +41/−0
- lib/initialise/Cabal.hs +147/−0
- lib/initialise/Configuration.hs +99/−0
- lib/initialise/Defaults.hs +47/−0
- lib/initialise/File.hs +28/−0
- lib/initialise/Git.hs +7/−0
- lib/initialise/Initialise.hs +13/−0
- lib/initialise/Licence.hs +25/−0
- templatise.cabal +122/−0
- test/initialise/CabalGolden.hs +46/−0
- test/initialise/ConfigurationSpec.hs +42/−0
- test/initialise/DefaultsSpec.hs +39/−0
- test/initialise/FileGolden.hs +56/−0
- test/initialise/GitSpec.hs +20/−0
- test/initialise/Hooks.hs +16/−0
- test/initialise/Main.hs +25/−0
- test/initialise/data/CHANGELOG-20230912.golden.md +5/−0
- test/initialise/data/CHANGELOG-20230912.md +5/−0
- test/initialise/data/devcontainer-20230912.golden.json +36/−0
- test/initialise/data/devcontainer-20230912.json +36/−0
- test/initialise/data/haskell-ci-20230912.golden.yml +199/−0
- test/initialise/data/haskell-ci-20230912.yml +199/−0
- test/initialise/data/templatise-20230829.cabal +116/−0
- test/initialise/data/templatise-20230829.golden.cabal +75/−0
+ CHANGELOG.md view
@@ -0,0 +1,5 @@+# Revision history for template-hs++## 0.1.0.0 -- YYYY-mm-dd++* First version. Released on an unsuspecting world.
+ LICENSE view
@@ -0,0 +1,24 @@+This is free and unencumbered software released into the public domain.++Anyone is free to copy, modify, publish, use, compile, sell, or+distribute this software, either in source code form or as a compiled+binary, for any purpose, commercial or non-commercial, and by any+means.++In jurisdictions that recognize copyright laws, the author or authors+of this software dedicate any and all copyright interest in the+software to the public domain. We make this dedication for the benefit+of the public at large and to the detriment of our heirs and+successors. We intend this dedication to be an overt act of+relinquishment in perpetuity of all present and future rights to this+software under copyright law.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR+OTHER DEALINGS IN THE SOFTWARE.++For more information, please refer to <https://unlicense.org>
+ README.md view
@@ -0,0 +1,51 @@+# template.hs++[Homepage][repository]++By Alex Brandt <alunduil@gmail.com>++## Description++You can use template.hs to create a new GitHub repository. The repository will+have Haskell, VS Code devcontainers, and various GitHub actions ready to use.++## Terms of use++You are free to use template.hs as a basis for your own projects without any+conditions. See the [LICENSE] file for details.++## Prerequisites++1. VS Code with "Remote Development" installed++## How to use this template++1. Visit [the repository][repository]+1. Click "Use this template"+1. Follow the GitHub Docs to [Create a repo][create a repo]+1. Open VS Code+1. Open the command prompt (ctrl+shift+p)+1. Type "clone repository in container" and hit return+1. Input the GitHub URL of your new repository+1. In the resulting terminal (ctrl+\`), run: `cabal run initialise`+1. Resolve the README update issue that is generated+1. Continue working on your awesome project++## Documentation++* [LICENSE]: The license governing use of template.hs++## Getting Help++* [GitHub Issues][issues]: Support requests, bug reports, and feature requests++## How to Help++* Submit [issues] for problems or questions+* Submit [pull requests] for proposed changes++[create a repo]: https://docs.github.com/en/get-started/quickstart/create-a-repo+[issues]: https://github.com/alunduil/template.hs/issues+[LICENSE]: ./LICENSE+[pull requests]: https://github.com/alunduil/template.hs/pulls+[repository]: https://github.com/alunduil/template.hs
+ Setup.hs view
@@ -0,0 +1,3 @@+import Distribution.Simple++main = defaultMain
+ bin/initialise/Main.hs view
@@ -0,0 +1,41 @@+module Main (main, main') where++import qualified Cabal (replace)+import qualified Configuration (parser)+import qualified Defaults (getDefaults)+import qualified File (replace)+import Initialise (Initialise, runInitialise)+import qualified Licence (replace)+import Options.Applicative (execParser, fullDesc, helper, info, progDesc, (<**>))+import System.FilePath ((</>))++main :: IO ()+main = do+ defaults <- Defaults.getDefaults++ let options =+ info+ (Configuration.parser defaults <**> helper)+ ( fullDesc+ <> progDesc+ ( unlines+ [ "Initialise a new project using the current checked out repository.",+ "WARNING: THIS WILL MODIFY THE CURRENT CONTENTS OF YOUR CHECKED OUT REPOSITORY!"+ ]+ )+ )++ execParser options >>= runInitialise main'++main' :: Initialise ()+main' = do+ mapM_+ File.replace+ [ ".devcontainer" </> "devcontainer.json",+ ".github" </> "workflows" </> "haskell-ci.yml",+ "CHANGELOG.md"+ ]+ Licence.replace "LICENSE"+ Cabal.replace "templatise.cabal"++-- TODO README
+ lib/initialise/Cabal.hs view
@@ -0,0 +1,147 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# OPTIONS_GHC -Wno-orphans #-}++module Cabal (replace, convert) where++import Configuration (Configuration (..))+import Control.Exception (Exception)+import Control.Monad.Catch (throwM)+import Control.Monad.Reader (asks, liftIO)+import Data.ByteString (ByteString, append, breakSubstring, concat, readFile, stripPrefix)+import Data.ByteString.Char8 (pack)+import Data.Text (Text, unpack)+import Data.Text.Encoding (encodeUtf8)+import Distribution.Fields+ ( CommentPosition (NoComment),+ Field (Field, Section),+ FieldLine (FieldLine),+ Name (Name),+ SectionArg (SecArgName, SecArgStr),+ fromParsecFields,+ readFields,+ showFields,+ )+import Distribution.Fields.Field (fieldLineAnn)+import Distribution.Parsec.Position (Position)+import Distribution.SPDX (licenseId)+import Initialise (Initialise)+import System.Directory.Extra (createDirectoryIfMissing, removeDirectoryRecursive, removeFile)+import System.FilePath (replaceBaseName, (</>))+import Text.Parsec.Error (ParseError)+import Prelude hiding (concat, readFile)++instance Exception ParseError++replace :: FilePath -> Initialise ()+replace path = do+ replaceCabal path+ "lib" `replaceDirectoryWith` replaceLib+ "test" `replaceDirectoryWith` replaceTest+ "bin" `replaceDirectoryWith` replaceBin++replaceCabal :: FilePath -> Initialise ()+replaceCabal path = do+ -- TODO handle in replaceWith+ path' <- asks (flip replaceBaseName path . unpack . name)+ -- TODO replaceWith convert+ contents <- liftIO $ readFile path+ contents' <- convert contents+ liftIO $ writeFile path' contents'+ -- TODO handle in replaceWith+ liftIO $ removeFile path++convert :: ByteString -> Initialise String+convert contents = do+ fs <- either throwM pure (readFields contents)+ showFields (const NoComment) . fromParsecFields <$> mapM convert' fs++convert' :: Field Position -> Initialise (Field Position)+convert' f@(Field n@(Name _ fName) ls) = do+ Configuration {..} <- asks id+ case fName of+ -- package+ "name" -> field (encodeUtf8 name)+ "version" -> field "0.1.0.0"+ "license" -> field (pack $ licenseId licence)+ "copyright" -> field (pack $ unwords ["(c)", show year, unpack author])+ "author" -> field (encodeUtf8 author)+ "maintainer" -> field (encodeUtf8 maintainer)+ "homepage" -> field $ pack $ show homepage+ "bug-reports" -> field $ pack (show homepage ++ "/issues")+ "synopsis" -> field "TODO"+ "description" -> field "TODO"+ -- common+ "import" -> field (encodeUtf8 name `append` "-common")+ "exposed-modules" -> field ""+ "other-modules" -> field ""+ "build-depends" -> pure $ Field n $ map (convertFieldLine name) ls+ "hs-source-dirs" -> pure $ Field n $ map (convertFieldLine name) ls+ -- source-repository+ "location" -> field $ pack $ show homepage+ _ -> pure f+ where+ field s = pure $ Field n [FieldLine annotation s]+ annotation = fieldLineAnn . head $ ls+convert' (Section n arguments fs) = do+ Configuration {..} <- asks id+ fs' <- mapM convert' fs+ pure $ Section n (map (convertSectionArgument name) arguments) fs'++convertSectionArgument :: Text -> SectionArg Position -> SectionArg Position+convertSectionArgument n s = case s of+ (SecArgName a o) -> SecArgName a $ convertString n o+ (SecArgStr a o) -> SecArgStr a $ convertString n o+ _ -> s++convertFieldLine :: Text -> FieldLine Position -> FieldLine Position+convertFieldLine r (FieldLine annotation s) = FieldLine annotation $ convertString r s++convertString :: Text -> ByteString -> ByteString+convertString r s = case token `stripPrefix` rest of+ Just suffix -> concat [prefix, encodeUtf8 r, suffix]+ Nothing -> s+ where+ (prefix, rest) = token `breakSubstring` s+ token = "initialise"++-- TODO Move to Initialise module?+replaceDirectoryWith :: FilePath -> (FilePath -> Initialise ()) -> Initialise ()+replaceDirectoryWith component r = do+ name' <- asks name+ path' <- asks ((</> component </> unpack name') . path)+ liftIO $ createDirectoryIfMissing True path'+ r path'+ liftIO $ removeDirectoryRecursive $ replaceBaseName "initialise" path'++replaceLib :: FilePath -> Initialise ()+replaceLib _path = pure ()++replaceTest :: FilePath -> Initialise ()+replaceTest path = do+ name' <- asks name+ -- TODO Template library.+ liftIO $+ writeFile (path </> "Main.hs") $+ unlines+ [ "module Main (main) where",+ "",+ "import Test.Tasty (defautMain, testGroup)",+ "",+ "main :: IO ()",+ "main = defaultMain $ testGroup \"" ++ unpack name' ++ "-library\" []"+ ]++replaceBin :: FilePath -> Initialise ()+replaceBin path = do+ name' <- asks name+ -- TODO Template library.(*)+ liftIO $+ writeFile (path </> "Main.hs") $+ unlines+ [ "module Main (main) where",+ "",+ "main :: IO ()",+ "main = putStrLn " ++ unpack name'+ ]
+ lib/initialise/Configuration.hs view
@@ -0,0 +1,99 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}++module Configuration+ ( Configuration (..),+ parser,+ )+where++import Data.Text (Text)+import Data.Time.Calendar (Year)+import Defaults (Defaults (..), dHomePage, dName)+import Distribution.SPDX.LicenseId (LicenseId (Unlicense))+import Network.URI (URI, parseURI)+import Options.Applicative+ ( Parser,+ auto,+ help,+ hidden,+ internal,+ long,+ metavar,+ option,+ showDefault,+ strOption,+ value,+ )+import Options.Applicative.Builder (maybeReader)++data Configuration = Configuration+ { name :: Text,+ homepage :: URI,+ author :: Text,+ maintainer :: Text,+ licence :: LicenseId,+ path :: FilePath,+ year :: Year+ }++parser :: Defaults -> Parser Configuration+parser ds@(Defaults {..}) =+ Configuration+ <$> strOption+ ( long "name"+ <> help "Name of the new project."+ <> metavar "NAME"+ <> value (dName ds)+ <> showDefault+ )+ <*> option+ (maybeReader parseURI)+ ( long "homepage"+ <> help "Homepage of the new project."+ <> metavar "URL"+ <> value (dHomePage ds)+ <> showDefault+ )+ <*> strOption+ ( long "author"+ <> help "Name of the author of the project."+ <> metavar "AUTHOR"+ <> value dAuthor+ <> showDefault+ )+ <*> strOption+ ( long "maintainer"+ <> help "Email of the maintainer of the project."+ <> metavar "MAINTAINER"+ <> value dMaintainer+ <> showDefault+ )+ <*> option+ auto+ ( long "licence"+ <> help "Licence of the project."+ <> value Unlicense+ <> showDefault+ <> metavar "LICENCE"+ )+ <*> option+ auto+ ( long "path"+ <> help "Project path. Only used for testing."+ <> value dPath+ <> showDefault+ <> metavar "PATH"+ <> hidden+ <> internal+ )+ <*> option+ auto+ ( long "year"+ <> help "Copyright year. Only used for testing."+ <> value dYear+ <> showDefault+ <> metavar "YEAR"+ <> hidden+ <> internal+ )
+ lib/initialise/Defaults.hs view
@@ -0,0 +1,47 @@+{-# LANGUAGE RecordWildCards #-}++module Defaults+ ( getDefaults,+ Defaults (..),+ dName,+ dHomePage,+ )+where++import Data.Maybe (fromJust)+import Data.Text (Text, pack, unpack)+import Data.Time (LocalTime (localDay), getCurrentTime, getCurrentTimeZone, utcToLocalTime)+import Data.Time.Calendar (Year)+import Data.Time.Calendar.OrdinalDate (toOrdinalDate)+import qualified Git (config)+import Network.URI (URI (uriPath), parseURI)+import System.Directory.Extra (getCurrentDirectory)+import System.FilePath (dropExtension, takeBaseName)++data Defaults = Defaults+ { dOrigin :: URI,+ dAuthor :: Text,+ dMaintainer :: Text,+ dPath :: FilePath,+ dYear :: Year+ }+ deriving (Show, Eq)++dName :: Defaults -> Text+dName Defaults {..} = pack . takeBaseName . uriPath $ dOrigin++dHomePage :: Defaults -> URI+dHomePage Defaults {..} =+ dOrigin+ { uriPath = dropExtension $ uriPath dOrigin+ }++getDefaults :: IO Defaults+getDefaults = do+ dOrigin <- fromJust . parseURI . unpack <$> Git.config "remote.origin.url"+ dAuthor <- Git.config "user.name"+ dMaintainer <- Git.config "user.email"+ dPath <- getCurrentDirectory+ timezone <- getCurrentTimeZone+ (dYear, _day) <- toOrdinalDate . localDay . utcToLocalTime timezone <$> getCurrentTime+ pure Defaults {..}
+ lib/initialise/File.hs view
@@ -0,0 +1,28 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}++module File (replace, convert) where++import Configuration (Configuration (..))+import Control.Monad.Reader (MonadIO (liftIO), MonadReader (ask))+import Data.Text (Text)+import qualified Data.Text as T (replace)+import Data.Text.IO (readFile, writeFile)+import Initialise (Initialise)+import Prelude hiding (readFile, writeFile)++replace :: FilePath -> Initialise ()+replace path = do+ -- TODO replaceWith convert+ contents <- liftIO $ readFile path+ contents' <- convert contents+ liftIO $ writeFile path contents'++convert :: Text -> Initialise Text+convert contents = do+ Configuration {..} <- ask+ pure+ . T.replace "templatise" name+ . T.replace "template-hs" name+ . T.replace "template.hs" name+ $ contents
+ lib/initialise/Git.hs view
@@ -0,0 +1,7 @@+module Git (config) where++import Data.Text (Text, pack)+import System.Process (readProcess)++config :: String -> IO Text+config key = pack . head . lines <$> readProcess "git" ["config", key] ""
+ lib/initialise/Initialise.hs view
@@ -0,0 +1,13 @@+module Initialise+ ( Initialise,+ runInitialise,+ )+where++import Configuration (Configuration)+import Control.Monad.Reader (ReaderT, runReaderT)++type Initialise = ReaderT Configuration IO++runInitialise :: Initialise a -> Configuration -> IO a+runInitialise = runReaderT
+ lib/initialise/Licence.hs view
@@ -0,0 +1,25 @@+{-# LANGUAGE RecordWildCards #-}++module Licence (replace) where++import Configuration (Configuration (..))+import Control.Monad (unless)+import Control.Monad.Reader (ask, liftIO)+import Data.ByteString.Lazy (ByteString, writeFile)+import Distribution.SPDX.LicenseId (LicenseId (Unlicense), licenseId)+import Initialise (Initialise)+import Network.HTTP.Client (responseBody)+import Network.HTTP.Simple (httpLBS, parseRequest)+import System.FilePath ((</>))+import Prelude hiding (writeFile)++replace :: FilePath -> Initialise ()+replace p = do+ Configuration {..} <- ask+ unless (licence == Unlicense) $+ liftIO (writeFile (p </> path) =<< contents licence)++contents :: LicenseId -> IO ByteString+contents l = do+ request <- parseRequest $ "https://spdx.org/licenses/" ++ licenseId l ++ ".txt"+ responseBody <$> httpLBS request
+ templatise.cabal view
@@ -0,0 +1,122 @@+cabal-version: 3.0+name: templatise+version: 0.1.0.1+license: Unlicense+license-file: LICENSE+copyright: (c) 2023 Alex Brandt+author: Alex Brandt+maintainer: alunduil@gmail.com+stability: alpha+homepage: https://github.com/alunduil/template.hs+bug-reports: https://github.com/alunduil/template.hs/issues+synopsis:+ You can use template.hs to create a new Haskell GitHub repository.++description:+ You can use template.hs to create a new GitHub repository. The repository will+ have Haskell, VS Code devcontainers, and various GitHub actions ready to use.++category: VSCode+tested-with: GHC ==9.2.8 || ==9.4.5 || ==9.4.6 || ==9.4.7 || ==9.6.2+extra-source-files:+ CHANGELOG.md+ README.md++data-files:+ test/**/*.cabal+ test/**/*.json+ test/**/*.md+ test/**/*.yml++source-repository head+ type: git+ location: https://github.com/alunduil/template.hs++common initialise-common+ build-depends:+ , base ^>=4.16.4.0 || ^>=4.17.0.0 || ^>=4.18.0.0+ , bytestring ^>=0.11.4.0 || ^>=0.12.0.2+ , Cabal-syntax ^>=3.8.1.0 || ^>=3.10.1.0+ , filepath ^>=1.4.2.2+ , mtl ^>=2.2.2 || ^>=2.3.1+ , network-uri ^>=2.6.4.1 || ^>=2.7.0.0+ , optparse-applicative ^>=0.18.1.0+ , process ^>=1.6.16.0+ , text ^>=1.2.5.0 || ^>=2.0.2++library initialise-library+ import: initialise-common+ exposed-modules:+ Cabal+ Configuration+ Defaults+ File+ Git+ Initialise+ Licence++ -- TODO Make Git private.+ --other-modules: Git+ build-depends:+ , exceptions ^>=0.10.4+ , extra ^>=1.7.14+ , http-client ^>=0.7.14+ , http-conduit ^>=2.3.8.3+ , parsec ^>=3.1.15.0+ , time ^>=1.11.1.1 || ^>=1.12.2++ hs-source-dirs: lib/initialise++ --default-extensions:+ --other-extensions:+ default-language: Haskell2010++ --build-tool-depends:+ ghc-options: -Wall++test-suite initialise-test+ import: initialise-common+ type: exitcode-stdio-1.0+ main-is: Main.hs+ build-depends:+ , directory ^>=1.3.6.2+ , hspec ^>=2.11.4+ , initialise-library+ , tasty ^>=1.4.3+ , tasty-golden ^>=2.3.5+ , tasty-hspec ^>=1.2.0.4+ , temporary ^>=1.3++ other-modules:+ CabalGolden+ ConfigurationSpec+ DefaultsSpec+ FileGolden+ GitSpec+ Hooks++ hs-source-dirs: test/initialise++ --default-extensions:+ -- other-extensions:+ default-language: Haskell2010++ -- build-tool-depends:+ ghc-options: -threaded -Wall++executable initialise+ main-is: Main.hs+ build-depends:+ , base ^>=4.16.4.0 || ^>=4.17.0.0 || ^>=4.18.0.0+ , filepath ^>=1.4.2.2+ , initialise-library+ , optparse-applicative ^>=0.18.1.0++ hs-source-dirs: bin/initialise++ -- default-extensions:+ -- other-extensions:+ default-language: Haskell2010++ -- build-tool-depends:+ ghc-options: -threaded -Wall
+ test/initialise/CabalGolden.hs view
@@ -0,0 +1,46 @@+{-# LANGUAGE OverloadedStrings #-}++module CabalGolden (golden) where++import qualified Cabal as SUT+import Configuration (Configuration (..))+import Control.Monad.Reader (liftIO)+import Data.ByteString (readFile)+import Data.ByteString.Lazy.Char8 (pack)+import Data.Maybe (fromJust)+import Distribution.SPDX.LicenseId (LicenseId (MIT))+import Initialise (runInitialise)+import Network.URI (parseURI)+import System.FilePath (isExtensionOf, normalise, replaceExtension, takeBaseName)+import Test.Tasty (TestTree, testGroup)+import Test.Tasty.Golden (findByExtension, goldenVsStringDiff)+import Prelude hiding (readFile)++golden :: IO TestTree+golden =+ testGroup "Cabal.convert"+ . map convertTest+ . filter (not . (".golden.cabal" `isExtensionOf`))+ <$> findByExtension [".cabal"] d+ where+ d = normalise "test/initialise/data"++convertTest :: FilePath -> TestTree+convertTest p = goldenVsStringDiff n diff gold action+ where+ n = takeBaseName p+ diff a b = ["diff", "-u", a, b]+ gold = p `replaceExtension` ".golden.cabal"+ action = do+ contents <- liftIO (readFile p)+ pack <$> runInitialise (SUT.convert contents) configuration+ configuration =+ Configuration+ { name = "sentinel",+ homepage = fromJust (parseURI "https://github.com/sentinel/sentinel.git"),+ author = "Sentinel",+ maintainer = "sentinel@example.com",+ licence = MIT,+ path = ".",+ year = 1970+ }
+ test/initialise/ConfigurationSpec.hs view
@@ -0,0 +1,42 @@+{-# LANGUAGE OverloadedStrings #-}++module ConfigurationSpec (spec) where++import qualified Configuration as SUT+import Data.Maybe (fromJust)+import Defaults (Defaults (..))+import Network.URI (parseURI)+import Options.Applicative (ParserResult (CompletionInvoked, Failure, Success), defaultPrefs, execParserPure, helper, info, renderFailure, (<**>))+import System.Exit (ExitCode (ExitFailure))+import Test.Hspec (Expectation, Spec, describe, expectationFailure, it, shouldBe)++spec :: Spec+spec =+ describe "Configuration" $ do+ describe "parser" $ do+ it "should error if homepage isn't a URI" $+ parse ["--homepage", "not-a-url"] `shouldFailWith` ("", ExitFailure 1)+ it "should error if licence isn't an SPDX licence ID" $ do+ parse ["--licence", "not-a-licence"] `shouldFailWith` ("", ExitFailure 1)++parse :: [String] -> ParserResult SUT.Configuration+parse =+ execParserPure+ defaultPrefs+ ( info (SUT.parser defaults <**> helper) mempty+ )++shouldFailWith :: ParserResult SUT.Configuration -> (String, ExitCode) -> Expectation+shouldFailWith (Success _) _ = expectationFailure "Expected Failure but got Success"+shouldFailWith (CompletionInvoked _) _ = expectationFailure "Expected Failure but got CompletionInvoked"+shouldFailWith (Failure f) rhs = renderFailure f "" `shouldBe` rhs++defaults :: Defaults+defaults =+ Defaults+ { dOrigin = fromJust (parseURI "http://github.com/username/repository.git"),+ dAuthor = "Forename Surname",+ dMaintainer = "username@example.com",+ dPath = ".",+ dYear = 1970+ }
+ test/initialise/DefaultsSpec.hs view
@@ -0,0 +1,39 @@+{-# LANGUAGE OverloadedStrings #-}++module DefaultsSpec (spec) where++import Data.Maybe (fromJust)+import qualified Defaults as SUT+import Hooks (withGitRepo)+import Network.URI (parseURI)+import Test.Hspec (Spec, around, describe, it, shouldBe)++spec :: Spec+spec = describe "Defaults" $ do+ describe "dName" $ do+ it "converts origin to project name" $+ SUT.dName defaults `shouldBe` "repository"+ describe "dHomePage" $ do+ it "converts origin to a home page" $+ SUT.dHomePage defaults `shouldBe` fromJust (parseURI "http://github.com/username/repository")+ describe "getDefaults" $ around withGitRepo $ do+ it "inspects the current repository" $ \p -> do+ ds <- SUT.getDefaults+ ds+ `shouldBe` SUT.Defaults+ { SUT.dOrigin = fromJust (parseURI "https://github.com/sentinel/sentinel.git"),+ SUT.dAuthor = "Sentinel",+ SUT.dMaintainer = "sentinel@example.com",+ SUT.dPath = p,+ SUT.dYear = 2023+ }++defaults :: SUT.Defaults+defaults =+ SUT.Defaults+ { SUT.dOrigin = fromJust (parseURI "http://github.com/username/repository.git"),+ SUT.dAuthor = "Forename Surname",+ SUT.dMaintainer = "username@example.com",+ SUT.dPath = ".",+ SUT.dYear = 1970+ }
+ test/initialise/FileGolden.hs view
@@ -0,0 +1,56 @@+{-# LANGUAGE OverloadedStrings #-}++module FileGolden (golden) where++import Configuration (Configuration (..))+import Control.Monad.Reader (liftIO)+import Data.Maybe (fromJust)+import Data.Text.IO (readFile)+import Data.Text.Lazy (fromStrict)+import Data.Text.Lazy.Encoding (encodeUtf8)+import Distribution.SPDX.LicenseId (LicenseId (MIT))+import qualified File as SUT+import Initialise (runInitialise)+import Network.URI (parseURI)+import System.FilePath (isExtensionOf, normalise, replaceExtension, takeBaseName, takeExtension)+import Test.Tasty (TestTree, testGroup)+import Test.Tasty.Golden (findByExtension, goldenVsStringDiff)+import Prelude hiding (readFile)++golden :: IO TestTree+golden = do+ testGroup "File.convert"+ <$> mapM+ g+ [ "devcontainer.json",+ "CHANGELOG.md",+ "haskell-ci.yml"+ ]+ where+ d = normalise "test/initialise/data"+ g n =+ let ext = takeExtension n+ in testGroup n+ . map convertTest+ . filter (not . ((".golden" ++ ext) `isExtensionOf`))+ <$> findByExtension [ext] d++convertTest :: FilePath -> TestTree+convertTest p = goldenVsStringDiff n diff gold action+ where+ n = takeBaseName p+ diff a b = ["diff", "-u", a, b]+ gold = p `replaceExtension` ".golden" ++ takeExtension p+ action = do+ contents <- liftIO (readFile p)+ encodeUtf8 . fromStrict <$> runInitialise (SUT.convert contents) configuration+ configuration =+ Configuration+ { name = "sentinel",+ homepage = fromJust (parseURI "https://github.com/sentinel/sentinel.git"),+ author = "Sentinel",+ maintainer = "sentinel@example.com",+ licence = MIT,+ path = ".",+ year = 1970+ }
+ test/initialise/GitSpec.hs view
@@ -0,0 +1,20 @@+module GitSpec (spec) where++import Data.Text (pack)+import qualified Git as SUT+import Hooks (withGitRepo)+import Test.Hspec (Spec, around, describe, it, shouldBe)++spec :: Spec+spec = around withGitRepo $+ describe "Git" $ do+ describe "config" $ do+ it "gets remote.origin.url" $ const $ do+ origin <- SUT.config "remote.origin.url"+ origin `shouldBe` pack "https://github.com/sentinel/sentinel.git"+ it "gets user.name" $ const $ do+ name <- SUT.config "user.name"+ name `shouldBe` pack "Sentinel"+ it "get user.email" $ const $ do+ email <- SUT.config "user.email"+ email `shouldBe` pack "sentinel@example.com"
+ test/initialise/Hooks.hs view
@@ -0,0 +1,16 @@+module Hooks (withGitRepo) where++import Control.Monad (void)+import System.Directory (withCurrentDirectory)+import System.IO.Temp (withSystemTempDirectory)+import System.Process (readProcess)++withGitRepo :: (FilePath -> IO ()) -> IO ()+withGitRepo action =+ withSystemTempDirectory "initialise" $ \p ->+ withCurrentDirectory p $ do+ void $ readProcess "git" ["init"] ""+ void $ readProcess "git" ["config", "user.name", "Sentinel"] ""+ void $ readProcess "git" ["config", "user.email", "sentinel@example.com"] ""+ void $ readProcess "git" ["remote", "add", "origin", "https://github.com/sentinel/sentinel.git"] ""+ action p
+ test/initialise/Main.hs view
@@ -0,0 +1,25 @@+module Main (main) where++import qualified CabalGolden (golden)+import qualified DefaultsSpec (spec)+import qualified FileGolden (golden)+import qualified GitSpec (spec)+import Test.Tasty (defaultMain, testGroup)+import Test.Tasty.Hspec (testSpecs)++main :: IO ()+main = do+ specs <-+ concat+ <$> mapM+ testSpecs+ [ DefaultsSpec.spec,+ GitSpec.spec+ ]+ goldens <- sequence [CabalGolden.golden, FileGolden.golden]+ defaultMain $+ testGroup+ "initialise-library"+ [ testGroup "Specs" specs,+ testGroup "Golden" goldens+ ]
+ test/initialise/data/CHANGELOG-20230912.golden.md view
@@ -0,0 +1,5 @@+# Revision history for sentinel++## 0.1.0.0 -- YYYY-mm-dd++* First version. Released on an unsuspecting world.
+ test/initialise/data/CHANGELOG-20230912.md view
@@ -0,0 +1,5 @@+# Revision history for template-hs++## 0.1.0.0 -- YYYY-mm-dd++* First version. Released on an unsuspecting world.
+ test/initialise/data/devcontainer-20230912.golden.json view
@@ -0,0 +1,36 @@+{+ "name": "sentinel",+ "image": "mcr.microsoft.com/devcontainers/base:ubuntu",+ // Features to add to the dev container. More info: https://containers.dev/features.+ "features": {+ "ghcr.io/devcontainers-contrib/features/haskell:2": {+ "globalPackages": "cabal-fmt haskell-ci hlint ormolu"+ },+ "ghcr.io/devcontainers-contrib/features/pre-commit:2": {},+ "ghcr.io/devcontainers/features/git:1": {},+ "ghcr.io/devcontainers/features/github-cli:1": {}+ },+ // Use 'forwardPorts' to make a list of ports inside the container available locally.+ // "forwardPorts": [],+ // Use 'postCreateCommand' to run commands after the container is created.+ // "postCreateCommand": "",+ // Configure tool-specific properties.+ "customizations": {+ "vscode": {+ "settings": {+ "haskell.manageHLS": "GHCup"+ },+ "extensions": [+ "berberman.vscode-cabal-fmt",+ "DavidAnson.vscode-markdownlint",+ "eamodio.gitlens",+ "github.vscode-github-actions",+ "GitHub.vscode-pull-request-github",+ "haskell.haskell",+ "ms-azuretools.vscode-docker"+ ]+ }+ },+ // Comment out to connect as root instead. To add a non-root user, see: https://aka.ms/vscode-remote/containers/non-root.+ "remoteUser": "vscode"+}
+ test/initialise/data/devcontainer-20230912.json view
@@ -0,0 +1,36 @@+{+ "name": "template.hs",+ "image": "mcr.microsoft.com/devcontainers/base:ubuntu",+ // Features to add to the dev container. More info: https://containers.dev/features.+ "features": {+ "ghcr.io/devcontainers-contrib/features/haskell:2": {+ "globalPackages": "cabal-fmt haskell-ci hlint ormolu"+ },+ "ghcr.io/devcontainers-contrib/features/pre-commit:2": {},+ "ghcr.io/devcontainers/features/git:1": {},+ "ghcr.io/devcontainers/features/github-cli:1": {}+ },+ // Use 'forwardPorts' to make a list of ports inside the container available locally.+ // "forwardPorts": [],+ // Use 'postCreateCommand' to run commands after the container is created.+ // "postCreateCommand": "",+ // Configure tool-specific properties.+ "customizations": {+ "vscode": {+ "settings": {+ "haskell.manageHLS": "GHCup"+ },+ "extensions": [+ "berberman.vscode-cabal-fmt",+ "DavidAnson.vscode-markdownlint",+ "eamodio.gitlens",+ "github.vscode-github-actions",+ "GitHub.vscode-pull-request-github",+ "haskell.haskell",+ "ms-azuretools.vscode-docker"+ ]+ }+ },+ // Comment out to connect as root instead. To add a non-root user, see: https://aka.ms/vscode-remote/containers/non-root.+ "remoteUser": "vscode"+}
+ test/initialise/data/haskell-ci-20230912.golden.yml view
@@ -0,0 +1,199 @@+# This GitHub workflow config has been generated by a script via+#+# haskell-ci 'github' '--haddock' 'sentinel.cabal'+#+# To regenerate the script (for example after adjusting tested-with) run+#+# haskell-ci regenerate+#+# For more information, see https://github.com/haskell-CI/haskell-ci+#+# version: 0.16.6+#+# REGENDATA ("0.16.6",["github","--haddock","sentinel.cabal"])+#+name: Haskell-CI+on:+ - push+ - pull_request+jobs:+ linux:+ name: Haskell-CI - Linux - ${{ matrix.compiler }}+ runs-on: ubuntu-20.04+ timeout-minutes:+ 60+ container:+ image: buildpack-deps:bionic+ continue-on-error: ${{ matrix.allow-failure }}+ strategy:+ matrix:+ include:+ - compiler: ghc-9.6.2+ compilerKind: ghc+ compilerVersion: 9.6.2+ setup-method: ghcup+ allow-failure: false+ - compiler: ghc-9.4.5+ compilerKind: ghc+ compilerVersion: 9.4.5+ setup-method: ghcup+ allow-failure: false+ - compiler: ghc-9.2.8+ compilerKind: ghc+ compilerVersion: 9.2.8+ setup-method: ghcup+ allow-failure: false+ fail-fast: false+ steps:+ - name: apt+ run: |+ apt-get update+ apt-get install -y --no-install-recommends gnupg ca-certificates dirmngr curl git software-properties-common libtinfo5+ mkdir -p "$HOME/.ghcup/bin"+ curl -sL https://downloads.haskell.org/ghcup/0.1.19.2/x86_64-linux-ghcup-0.1.19.2 > "$HOME/.ghcup/bin/ghcup"+ chmod a+x "$HOME/.ghcup/bin/ghcup"+ "$HOME/.ghcup/bin/ghcup" install ghc "$HCVER" || (cat "$HOME"/.ghcup/logs/*.* && false)+ "$HOME/.ghcup/bin/ghcup" install cabal 3.10.1.0 || (cat "$HOME"/.ghcup/logs/*.* && false)+ env:+ HCKIND: ${{ matrix.compilerKind }}+ HCNAME: ${{ matrix.compiler }}+ HCVER: ${{ matrix.compilerVersion }}+ - name: Set PATH and environment variables+ run: |+ echo "$HOME/.cabal/bin" >> $GITHUB_PATH+ echo "LANG=C.UTF-8" >> "$GITHUB_ENV"+ echo "CABAL_DIR=$HOME/.cabal" >> "$GITHUB_ENV"+ echo "CABAL_CONFIG=$HOME/.cabal/config" >> "$GITHUB_ENV"+ HCDIR=/opt/$HCKIND/$HCVER+ HC=$HOME/.ghcup/bin/$HCKIND-$HCVER+ echo "HC=$HC" >> "$GITHUB_ENV"+ echo "HCPKG=$HOME/.ghcup/bin/$HCKIND-pkg-$HCVER" >> "$GITHUB_ENV"+ echo "HADDOCK=$HOME/.ghcup/bin/haddock-$HCVER" >> "$GITHUB_ENV"+ echo "CABAL=$HOME/.ghcup/bin/cabal-3.10.1.0 -vnormal+nowrap" >> "$GITHUB_ENV"+ HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\d+)\.(\d+)\.(\d+)(\.(\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')+ echo "HCNUMVER=$HCNUMVER" >> "$GITHUB_ENV"+ echo "ARG_TESTS=--enable-tests" >> "$GITHUB_ENV"+ echo "ARG_BENCH=--enable-benchmarks" >> "$GITHUB_ENV"+ echo "HEADHACKAGE=false" >> "$GITHUB_ENV"+ echo "ARG_COMPILER=--$HCKIND --with-compiler=$HC" >> "$GITHUB_ENV"+ echo "GHCJSARITH=0" >> "$GITHUB_ENV"+ env:+ HCKIND: ${{ matrix.compilerKind }}+ HCNAME: ${{ matrix.compiler }}+ HCVER: ${{ matrix.compilerVersion }}+ - name: env+ run: |+ env+ - name: write cabal config+ run: |+ mkdir -p $CABAL_DIR+ cat >> $CABAL_CONFIG <<EOF+ remote-build-reporting: anonymous+ write-ghc-environment-files: never+ remote-repo-cache: $CABAL_DIR/packages+ logs-dir: $CABAL_DIR/logs+ world-file: $CABAL_DIR/world+ extra-prog-path: $CABAL_DIR/bin+ symlink-bindir: $CABAL_DIR/bin+ installdir: $CABAL_DIR/bin+ build-summary: $CABAL_DIR/logs/build.log+ store-dir: $CABAL_DIR/store+ install-dirs user+ prefix: $CABAL_DIR+ repository hackage.haskell.org+ url: http://hackage.haskell.org/+ EOF+ cat >> $CABAL_CONFIG <<EOF+ program-default-options+ ghc-options: $GHCJOBS +RTS -M3G -RTS+ EOF+ cat $CABAL_CONFIG+ - name: versions+ run: |+ $HC --version || true+ $HC --print-project-git-commit-id || true+ $CABAL --version || true+ - name: update cabal index+ run: |+ $CABAL v2-update -v+ - name: install cabal-plan+ run: |+ mkdir -p $HOME/.cabal/bin+ curl -sL https://github.com/haskell-hvr/cabal-plan/releases/download/v0.7.3.0/cabal-plan-0.7.3.0-x86_64-linux.xz > cabal-plan.xz+ echo 'f62ccb2971567a5f638f2005ad3173dba14693a45154c1508645c52289714cb2 cabal-plan.xz' | sha256sum -c -+ xz -d < cabal-plan.xz > $HOME/.cabal/bin/cabal-plan+ rm -f cabal-plan.xz+ chmod a+x $HOME/.cabal/bin/cabal-plan+ cabal-plan --version+ - name: checkout+ uses: actions/checkout@v3+ with:+ path: source+ - name: initial cabal.project for sdist+ run: |+ touch cabal.project+ echo "packages: $GITHUB_WORKSPACE/source/." >> cabal.project+ cat cabal.project+ - name: sdist+ run: |+ mkdir -p sdist+ $CABAL sdist all --output-dir $GITHUB_WORKSPACE/sdist+ - name: unpack+ run: |+ mkdir -p unpacked+ find sdist -maxdepth 1 -type f -name '*.tar.gz' -exec tar -C $GITHUB_WORKSPACE/unpacked -xzvf {} \;+ - name: generate cabal.project+ run: |+ PKGDIR_sentinel="$(find "$GITHUB_WORKSPACE/unpacked" -maxdepth 1 -type d -regex '.*/sentinel-[0-9.]*')"+ echo "PKGDIR_sentinel=${PKGDIR_sentinel}" >> "$GITHUB_ENV"+ rm -f cabal.project cabal.project.local+ touch cabal.project+ touch cabal.project.local+ echo "packages: ${PKGDIR_sentinel}" >> cabal.project+ echo "package sentinel" >> cabal.project+ echo " ghc-options: -Werror=missing-methods" >> cabal.project+ cat >> cabal.project <<EOF+ EOF+ $HCPKG list --simple-output --names-only | perl -ne 'for (split /\s+/) { print "constraints: $_ installed\n" unless /^(sentinel)$/; }' >> cabal.project.local+ cat cabal.project+ cat cabal.project.local+ - name: dump install plan+ run: |+ $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dry-run all+ cabal-plan+ - name: restore cache+ uses: actions/cache/restore@v3+ with:+ key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }}+ path: ~/.cabal/store+ restore-keys: ${{ runner.os }}-${{ matrix.compiler }}-+ - name: install dependencies+ run: |+ $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --dependencies-only -j2 all+ $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dependencies-only -j2 all+ - name: build w/o tests+ run: |+ $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all+ - name: build+ run: |+ $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --write-ghc-environment-files=always+ - name: tests+ run: |+ $CABAL v2-test $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --test-show-details=direct+ - name: cabal check+ run: |+ cd ${PKGDIR_sentinel} || false+ ${CABAL} -vnormal check+ - name: haddock+ run: |+ $CABAL v2-haddock --disable-documentation --haddock-all $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all+ - name: unconstrained build+ run: |+ rm -f cabal.project.local+ $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all+ - name: save cache+ uses: actions/cache/save@v3+ if: always()+ with:+ key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }}+ path: ~/.cabal/store
+ test/initialise/data/haskell-ci-20230912.yml view
@@ -0,0 +1,199 @@+# This GitHub workflow config has been generated by a script via+#+# haskell-ci 'github' '--haddock' 'templatise.cabal'+#+# To regenerate the script (for example after adjusting tested-with) run+#+# haskell-ci regenerate+#+# For more information, see https://github.com/haskell-CI/haskell-ci+#+# version: 0.16.6+#+# REGENDATA ("0.16.6",["github","--haddock","templatise.cabal"])+#+name: Haskell-CI+on:+ - push+ - pull_request+jobs:+ linux:+ name: Haskell-CI - Linux - ${{ matrix.compiler }}+ runs-on: ubuntu-20.04+ timeout-minutes:+ 60+ container:+ image: buildpack-deps:bionic+ continue-on-error: ${{ matrix.allow-failure }}+ strategy:+ matrix:+ include:+ - compiler: ghc-9.6.2+ compilerKind: ghc+ compilerVersion: 9.6.2+ setup-method: ghcup+ allow-failure: false+ - compiler: ghc-9.4.5+ compilerKind: ghc+ compilerVersion: 9.4.5+ setup-method: ghcup+ allow-failure: false+ - compiler: ghc-9.2.8+ compilerKind: ghc+ compilerVersion: 9.2.8+ setup-method: ghcup+ allow-failure: false+ fail-fast: false+ steps:+ - name: apt+ run: |+ apt-get update+ apt-get install -y --no-install-recommends gnupg ca-certificates dirmngr curl git software-properties-common libtinfo5+ mkdir -p "$HOME/.ghcup/bin"+ curl -sL https://downloads.haskell.org/ghcup/0.1.19.2/x86_64-linux-ghcup-0.1.19.2 > "$HOME/.ghcup/bin/ghcup"+ chmod a+x "$HOME/.ghcup/bin/ghcup"+ "$HOME/.ghcup/bin/ghcup" install ghc "$HCVER" || (cat "$HOME"/.ghcup/logs/*.* && false)+ "$HOME/.ghcup/bin/ghcup" install cabal 3.10.1.0 || (cat "$HOME"/.ghcup/logs/*.* && false)+ env:+ HCKIND: ${{ matrix.compilerKind }}+ HCNAME: ${{ matrix.compiler }}+ HCVER: ${{ matrix.compilerVersion }}+ - name: Set PATH and environment variables+ run: |+ echo "$HOME/.cabal/bin" >> $GITHUB_PATH+ echo "LANG=C.UTF-8" >> "$GITHUB_ENV"+ echo "CABAL_DIR=$HOME/.cabal" >> "$GITHUB_ENV"+ echo "CABAL_CONFIG=$HOME/.cabal/config" >> "$GITHUB_ENV"+ HCDIR=/opt/$HCKIND/$HCVER+ HC=$HOME/.ghcup/bin/$HCKIND-$HCVER+ echo "HC=$HC" >> "$GITHUB_ENV"+ echo "HCPKG=$HOME/.ghcup/bin/$HCKIND-pkg-$HCVER" >> "$GITHUB_ENV"+ echo "HADDOCK=$HOME/.ghcup/bin/haddock-$HCVER" >> "$GITHUB_ENV"+ echo "CABAL=$HOME/.ghcup/bin/cabal-3.10.1.0 -vnormal+nowrap" >> "$GITHUB_ENV"+ HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\d+)\.(\d+)\.(\d+)(\.(\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')+ echo "HCNUMVER=$HCNUMVER" >> "$GITHUB_ENV"+ echo "ARG_TESTS=--enable-tests" >> "$GITHUB_ENV"+ echo "ARG_BENCH=--enable-benchmarks" >> "$GITHUB_ENV"+ echo "HEADHACKAGE=false" >> "$GITHUB_ENV"+ echo "ARG_COMPILER=--$HCKIND --with-compiler=$HC" >> "$GITHUB_ENV"+ echo "GHCJSARITH=0" >> "$GITHUB_ENV"+ env:+ HCKIND: ${{ matrix.compilerKind }}+ HCNAME: ${{ matrix.compiler }}+ HCVER: ${{ matrix.compilerVersion }}+ - name: env+ run: |+ env+ - name: write cabal config+ run: |+ mkdir -p $CABAL_DIR+ cat >> $CABAL_CONFIG <<EOF+ remote-build-reporting: anonymous+ write-ghc-environment-files: never+ remote-repo-cache: $CABAL_DIR/packages+ logs-dir: $CABAL_DIR/logs+ world-file: $CABAL_DIR/world+ extra-prog-path: $CABAL_DIR/bin+ symlink-bindir: $CABAL_DIR/bin+ installdir: $CABAL_DIR/bin+ build-summary: $CABAL_DIR/logs/build.log+ store-dir: $CABAL_DIR/store+ install-dirs user+ prefix: $CABAL_DIR+ repository hackage.haskell.org+ url: http://hackage.haskell.org/+ EOF+ cat >> $CABAL_CONFIG <<EOF+ program-default-options+ ghc-options: $GHCJOBS +RTS -M3G -RTS+ EOF+ cat $CABAL_CONFIG+ - name: versions+ run: |+ $HC --version || true+ $HC --print-project-git-commit-id || true+ $CABAL --version || true+ - name: update cabal index+ run: |+ $CABAL v2-update -v+ - name: install cabal-plan+ run: |+ mkdir -p $HOME/.cabal/bin+ curl -sL https://github.com/haskell-hvr/cabal-plan/releases/download/v0.7.3.0/cabal-plan-0.7.3.0-x86_64-linux.xz > cabal-plan.xz+ echo 'f62ccb2971567a5f638f2005ad3173dba14693a45154c1508645c52289714cb2 cabal-plan.xz' | sha256sum -c -+ xz -d < cabal-plan.xz > $HOME/.cabal/bin/cabal-plan+ rm -f cabal-plan.xz+ chmod a+x $HOME/.cabal/bin/cabal-plan+ cabal-plan --version+ - name: checkout+ uses: actions/checkout@v3+ with:+ path: source+ - name: initial cabal.project for sdist+ run: |+ touch cabal.project+ echo "packages: $GITHUB_WORKSPACE/source/." >> cabal.project+ cat cabal.project+ - name: sdist+ run: |+ mkdir -p sdist+ $CABAL sdist all --output-dir $GITHUB_WORKSPACE/sdist+ - name: unpack+ run: |+ mkdir -p unpacked+ find sdist -maxdepth 1 -type f -name '*.tar.gz' -exec tar -C $GITHUB_WORKSPACE/unpacked -xzvf {} \;+ - name: generate cabal.project+ run: |+ PKGDIR_templatise="$(find "$GITHUB_WORKSPACE/unpacked" -maxdepth 1 -type d -regex '.*/templatise-[0-9.]*')"+ echo "PKGDIR_templatise=${PKGDIR_templatise}" >> "$GITHUB_ENV"+ rm -f cabal.project cabal.project.local+ touch cabal.project+ touch cabal.project.local+ echo "packages: ${PKGDIR_templatise}" >> cabal.project+ echo "package templatise" >> cabal.project+ echo " ghc-options: -Werror=missing-methods" >> cabal.project+ cat >> cabal.project <<EOF+ EOF+ $HCPKG list --simple-output --names-only | perl -ne 'for (split /\s+/) { print "constraints: $_ installed\n" unless /^(templatise)$/; }' >> cabal.project.local+ cat cabal.project+ cat cabal.project.local+ - name: dump install plan+ run: |+ $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dry-run all+ cabal-plan+ - name: restore cache+ uses: actions/cache/restore@v3+ with:+ key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }}+ path: ~/.cabal/store+ restore-keys: ${{ runner.os }}-${{ matrix.compiler }}-+ - name: install dependencies+ run: |+ $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --dependencies-only -j2 all+ $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dependencies-only -j2 all+ - name: build w/o tests+ run: |+ $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all+ - name: build+ run: |+ $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --write-ghc-environment-files=always+ - name: tests+ run: |+ $CABAL v2-test $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --test-show-details=direct+ - name: cabal check+ run: |+ cd ${PKGDIR_templatise} || false+ ${CABAL} -vnormal check+ - name: haddock+ run: |+ $CABAL v2-haddock --disable-documentation --haddock-all $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all+ - name: unconstrained build+ run: |+ rm -f cabal.project.local+ $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all+ - name: save cache+ uses: actions/cache/save@v3+ if: always()+ with:+ key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }}+ path: ~/.cabal/store
+ test/initialise/data/templatise-20230829.cabal view
@@ -0,0 +1,116 @@+cabal-version: 3.0+name: templatise+version: 0.1.0.0+license: Unlicense+license-file: LICENSE+copyright: (c) 2023 Alex Brandt+author: Alex Brandt+maintainer: alunduil@gmail.com+stability: alpha+homepage: https://github.com/alunduil/template.hs+bug-reports: https://github.com/alunduil/template.hs/issues+synopsis:+ You can use template.hs to create a new Haskell GitHub repository.++description:+ You can use template.hs to create a new GitHub repository. The repository will+ have Haskell, VS Code devcontainers, and various GitHub actions ready to use.++category: VSCode+tested-with: GHC ==9.2.8 || ==9.4.5 || ==9.6.2+extra-source-files:+ CHANGELOG.md+ README.md++source-repository head+ type: git+ location: https://github.com/alunduil/template.hs++common initialise-common+ build-depends:+ , base ^>=4.16.4.0 || ^>=4.17.0.0 || ^>=4.18.0.0+ , bytestring ^>=0.11.4.0 || ^>=0.12.0.2+ , Cabal-syntax ^>=3.10.1.0+ , filepath ^>=1.4.2.2+ , mtl ^>=2.2.2 || ^>=2.3.1+ , network-uri ^>=2.6.4.1 || ^>=2.7.0.0+ , optparse-applicative ^>=0.18.1.0+ , text ^>=2.0.2++library initialise-library+ import: initialise-common+ exposed-modules:+ Cabal+ Configuration+ Defaults+ Git+ Initialise++ -- TODO Make Git private.+ --other-modules: Git+ build-depends:+ , exceptions ^>=0.10.5+ , extra ^>=1.7.14+ , parsec ^>=3.1.16.1+ , process ^>=1.6.16.0+ , time ^>=1.11.1.1 || ^>=1.12.2++ hs-source-dirs: lib/initialise++ --default-extensions:+ --other-extensions:+ default-language: Haskell2010++ --build-tool-depends:+ ghc-options: -Wall++test-suite initialise-test+ import: initialise-common+ type: exitcode-stdio-1.0+ main-is: Main.hs+ build-depends:+ , hspec ^>=2.11.4+ , initialise-library+ , tasty ^>=1.4.3+ , tasty-golden ^>=2.3.5+ , tasty-hspec ^>=1.2.0.4++ other-modules:+ CabalGolden+ ConfigurationSpec+ DefaultsSpec+ GitSpec++ hs-source-dirs: test/initialise++ --default-extensions:+ -- other-extensions:+ default-language: Haskell2010++ -- build-tool-depends:+ ghc-options: -threaded -Wall++executable initialise+ main-is: Main.hs+ build-depends:+ , base ^>=4.16.4.0 || ^>=4.17.0.0 || ^>=4.18.0.0+ , http-client ^>=0.7.13.1+ , http-conduit ^>=2.3.8.3+ , initialise-library++ --other-modules:+ -- Cabal+ -- Configuration+ -- File+ -- Initialise+ -- Licence+ -- Replace++ hs-source-dirs: bin/initialise++ -- default-extensions:+ -- other-extensions:+ default-language: Haskell2010++ -- build-tool-depends:+ ghc-options: -threaded -Wall
+ test/initialise/data/templatise-20230829.golden.cabal view
@@ -0,0 +1,75 @@+cabal-version: 3.0+name: sentinel+version: 0.1.0.0+license: MIT+license-file: LICENSE+copyright: (c) 1970 Sentinel+author: Sentinel+maintainer: sentinel@example.com+stability: alpha+homepage: https://github.com/sentinel/sentinel.git+bug-reports: https://github.com/sentinel/sentinel.git/issues+synopsis: TODO+description: TODO+category: VSCode+tested-with: GHC ==9.2.8 || ==9.4.5 || ==9.6.2+extra-source-files:+ CHANGELOG.md+ README.md++source-repository head+ type: git+ location: https://github.com/sentinel/sentinel.git++common sentinel-common+ build-depends:+ , base ^>=4.16.4.0 || ^>=4.17.0.0 || ^>=4.18.0.0+ , bytestring ^>=0.11.4.0 || ^>=0.12.0.2+ , Cabal-syntax ^>=3.10.1.0+ , filepath ^>=1.4.2.2+ , mtl ^>=2.2.2 || ^>=2.3.1+ , network-uri ^>=2.6.4.1 || ^>=2.7.0.0+ , optparse-applicative ^>=0.18.1.0+ , text ^>=2.0.2++library sentinel-library+ import: sentinel-common+ exposed-modules:+ build-depends:+ , exceptions ^>=0.10.5+ , extra ^>=1.7.14+ , parsec ^>=3.1.16.1+ , process ^>=1.6.16.0+ , time ^>=1.11.1.1 || ^>=1.12.2++ hs-source-dirs: lib/sentinel+ default-language: Haskell2010+ ghc-options: -Wall++test-suite sentinel-test+ import: sentinel-common+ type: exitcode-stdio-1.0+ main-is: Main.hs+ build-depends:+ , hspec ^>=2.11.4+ , sentinel-library+ , tasty ^>=1.4.3+ , tasty-golden ^>=2.3.5+ , tasty-hspec ^>=1.2.0.4++ other-modules:+ hs-source-dirs: test/sentinel+ default-language: Haskell2010+ ghc-options: -threaded -Wall++executable sentinel+ main-is: Main.hs+ build-depends:+ , base ^>=4.16.4.0 || ^>=4.17.0.0 || ^>=4.18.0.0+ , http-client ^>=0.7.13.1+ , http-conduit ^>=2.3.8.3+ , sentinel-library++ hs-source-dirs: bin/sentinel+ default-language: Haskell2010+ ghc-options: -threaded -Wall