packages feed

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 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