stackctl 1.7.3.0 → 1.7.3.2
raw patch · 30 files changed
+228/−477 lines, 30 filesdep ~Blammodep ~QuickCheckdep ~aeson
Dependency ranges changed: Blammo, QuickCheck, aeson, aeson-pretty, bytestring, conduit, containers, envparse, exceptions, extra, filepath, hspec, http-types, lens, lens-aeson, monad-logger, mtl, optparse-applicative, resourcet, text, text-metrics, time, transformers, typed-process, unix, unordered-containers, uuid, yaml
Files
- CHANGELOG.md +1/−242
- app/Main.hs +5/−5
- src/Stackctl/AWS/CloudFormation.hs +28/−26
- src/Stackctl/AWS/Core.hs +4/−6
- src/Stackctl/AWS/Lambda.hs +5/−5
- src/Stackctl/AWS/Orphans.hs +3/−0
- src/Stackctl/AWS/Scope.hs +15/−19
- src/Stackctl/Action.hs +4/−4
- src/Stackctl/CLI.hs +26/−27
- src/Stackctl/Config.hs +4/−3
- src/Stackctl/Config/RequiredVersion.hs +3/−3
- src/Stackctl/FilterOption.hs +2/−2
- src/Stackctl/Options.hs +5/−5
- src/Stackctl/Prelude.hs +2/−0
- src/Stackctl/Spec/Capture.hs +2/−3
- src/Stackctl/Spec/Cat.hs +7/−7
- src/Stackctl/Spec/Changes/Format.hs +23/−22
- src/Stackctl/Spec/Deploy.hs +2/−4
- src/Stackctl/Spec/Discover.hs +11/−12
- src/Stackctl/Spec/List.hs +1/−1
- src/Stackctl/StackSpec.hs +2/−4
- src/Stackctl/StackSpecPath.hs +7/−7
- src/Stackctl/StackSpecYaml.hs +6/−8
- src/Stackctl/VerboseOption.hs +1/−0
- src/Stackctl/Version.hs +1/−1
- stackctl.cabal +47/−47
- test/Stackctl/AWS/EC2Spec.hs +1/−1
- test/Stackctl/AWS/LambdaSpec.hs +3/−5
- test/Stackctl/ConfigSpec.hs +5/−6
- test/Stackctl/Test/App.hs +2/−2
CHANGELOG.md view
@@ -1,242 +1,1 @@-## [_Unreleased_](https://github.com/freckle/stackctl/compare/v1.7.2.0...main)--## [v1.7.2.0](https://github.com/freckle/stackctl/compare/v1.7.1.0...v1.7.2.0)--- Automatically cancel any ongoing update-stack operations on `^C`--## [v1.7.1.0](https://github.com/freckle/stackctl/compare/v1.7.0.0...v1.7.1.0)--- Add `withAssumedRole`, deprecate `assumeRole`--## [v1.7.0.0](https://github.com/freckle/stackctl/compare/v1.6.1.2...v1.7.0.0)--- Retain numeric parameter types, and add boolean parameter handling, in our own- yaml generation-- This required changing the `Generate` to use `ParametersYaml` instead of- `[Parameter]`, and ultimately led us to removing it, hence the major version- bump.--## [v1.6.1.2](https://github.com/freckle/stackctl/compare/v1.6.1.1...v1.6.1.2)--- Require Blammo-1.2.2.3--## [v1.6.1.1](https://github.com/freckle/stackctl/compare/v1.6.1.0...v1.6.1.1)--- Fix: finding removed stacks now respects `STACKCTL_DIRECTORY`--## [v1.6.1.0](https://github.com/freckle/stackctl/compare/v1.6.0.0...v1.6.1.0)--- Add `Ord` instance on `RequiredVersion` and `RequiredVersionOp`--## [v1.6.0.0](https://github.com/freckle/stackctl/compare/v1.5.0.1...v1.6.0.0)--- Re-implement `Stackctl.AWS` with `amazonka-mtl`.--_No CLI or behavior changes._--## [v1.5.0.1](https://github.com/freckle/stackctl/compare/v1.5.0.0...v1.5.0.1)--- Handle missing-or-empty specs directory more explicitly-- Add warning for `Depends` pointing to non-existent spec-- Fix formatting of required version in warning message--## [v1.5.0.0](https://github.com/freckle/stackctl/compare/v1.4.4.0...v1.5.0.0)--Breaking changes:--- Don't require a name argument to the `awsSimple` function--New features:--- Add `Exec` and `Shell` features in `actions[].run`-- Support lists in `actions[].run` (single items still work)-- Add more granular status indicators in `stack-ls(1)` output, print a legend of- these indicators as a footer (disable with `--no-legend`)--Fixes:--- Fix for redundant change-set creation errors in logging output-- Fix globbing bug in auto-expansion of `--filter` arguments--## [v1.4.4.0](https://github.com/freckle/stackctl/compare/v1.4.3.0...v1.4.4.0)--- Add `awsSilently`--## [v1.4.3.0](https://github.com/freckle/stackctl/compare/v1.4.2.2...v1.4.3.0)--- Add `awsWithAuth`-- Add `forEachSpec_`--## [v1.4.2.2](https://github.com/freckle/stackctl/compare/v1.4.2.1...v1.4.2.2)--- Use `amazonka-2.0` :tada:-- Finalize update to `UnliftIO.Exception.Lens`-- Re-export upstreamed `Blammo.Logging.Colors`--## [v1.4.2.1](https://github.com/freckle/stackctl/compare/v1.4.2.0...v1.4.2.1)--No changes. Bumped to trigger release workflow.--## [v1.4.2.0](https://github.com/freckle/stackctl/compare/v1.4.0.1...v1.4.2.0)--- Add `stackctl-ls` for listing stacks and their deployed status-- Add `--auto-sso` option for automating `aws sso login` when required--## [v1.4.0.1](https://github.com/freckle/stackctl/compare/v1.4.0.0...v1.4.0.1)--- Document and read a consistently-named `STACKCTL_FILTER` for `--filter`. For- now, the old and incorrect `STACKCTL_FILTERS` will still work.--## [v1.4.0.0](https://github.com/freckle/stackctl/compare/v1.3.0.2...v1.4.0.0)--- Add `awsAssumeRole` for running an action as an assumed role-- Refactor `Generate` interface to better support generating stacks with- pre-existing templates--## [v1.3.0.2](https://github.com/freckle/stackctl/compare/v1.3.0.1...v1.3.0.2)--- Adjust timeout when invoking Lambdas to allow up to Lambda's own execution- timeout (15 minutes).--## [v1.3.0.1](https://github.com/freckle/stackctl/compare/v1.3.0.0...v1.3.0.1)--- Fix bug where `LOG_COLOR` was never respected-- Also accept `"required_version: == <version>"`-- Add `Eq`, `ToJSON` instance on `RequiredVersion`--## [v1.3.0.0](https://github.com/freckle/stackctl/compare/v1.2.0.1...v1.3.0.0)--- Fix it so commands like `version` don't need a valid AWS environment-- This changes the `Subcommand` interface and so is a major version update for- the purposes of those using Stackctl as a library.--## [v1.2.0.0](https://github.com/freckle/stackctl/compare/v1.1.3.1...v1.2.0.0)--- Use more specific types in `Has{Directory,Filter,Color}Option`-- Add environment variable configuration for `STACKCTL_{DIRECTORY,FILTERS}`--## [v1.1.4.0](https://github.com/freckle/stackctl/compare/v1.1.3.1...v1.1.4.0)--- Support matching Stacks by glob in `capture`-- Add `--tag` to `changes` and `deploy`--## [v1.1.3.1](https://github.com/freckle/stackctl/compare/v1.1.3.0...v1.1.3.1)--- Fix JSON formatting bugs in generating specification--## [v1.1.3.0](https://github.com/freckle/stackctl/compare/v1.1.2.2...v1.1.3.0)--- Repository-local configuration-- See https://github.com/freckle/stackctl/commit/564678203fe70b5c4c46c655dd3daeaafb6de9e0--- Don't duplicate re-used templates in `stackctl-cat`-- Improve `--filter`-- - Match against stack name and template, in addition to spec path.- - Automatically prepend `**/` (unless there is already a leading wildcard) and- append `{/*,.yaml,.json}` (unless there is already a trailing wildcard or- extension).-- In general, this aims to make `--filter` match more things more intuitively- for operators, but still match exactly in programmatic use-cases.--- Various documentation improvements-- Support more natural `{Key}: {Value}` syntax in `Parameters` and `Tags`-- Fix bug where we may generate an `{}` element in `Parameters`--## [v1.1.2.2](https://github.com/freckle/stackctl/compare/v1.1.2.1...v1.1.2.2)--- Add support for Stack descriptions--## [v1.1.2.1](https://github.com/freckle/stackctl/compare/v1.1.2.0...v1.1.2.1)--- Build with LTS-20.4 / GHC 9.2--## [v1.1.2.0](https://github.com/freckle/stackctl/compare/v1.1.1.1...v1.1.2.0)--- Fix incorrect ordering of log-messages by setting `LOG_CONCURRENCY=1`-- Fix potential coloring of changes being redirected to a file-- Make `PATH` optional (again) in `stackctl changes`-- Add `--no-flip` to `stackctl capture`--## [v1.1.1.1](https://github.com/freckle/stackctl/compare/v1.1.1.0...v1.1.1.1)--- Trigger release--## [v1.1.1.0](https://github.com/freckle/stackctl/compare/v1.1.0.5...v1.1.1.0)--- Add `--parameter` to `changes` and `deploy`-- Sort changes by causing-before-caused--## [v1.1.0.5](https://github.com/freckle/stackctl/compare/v1.1.0.4...v1.1.0.5)--- Trigger release workflow--## [v1.1.0.4](https://github.com/freckle/stackctl/compare/v1.1.0.3...v1.1.0.4)--- Fix bug where only the last spec in a multi-spec case had its changes present- in the output file generated by `changes`.--## [v1.1.0.3](https://github.com/freckle/stackctl/compare/v1.1.0.2...v1.1.0.3)--- Require Blammo-1.1.1.0--## [v1.1.0.2](https://github.com/freckle/stackctl/compare/v1.1.0.1...v1.1.0.2)--- Log responses from `awsLambdaInvoke` when running actions-- Clarify discovery logging-- Add install script--## [v1.1.0.1](https://github.com/freckle/stackctl/compare/v1.1.0.0...v1.1.0.1)--- Update to `cfn-flip-0.1.0.3`--## [v1.1.0.0](https://github.com/freckle/stackctl/compare/v1.0.2.0...v1.1.0.0)--- Fix interleaved or out-of-order output bugs by streaming deployment events- through the Logger instead of directly to `stdout`-- Logging goes to `stdout` by default (`LOG_DESTINATION` can still be used)-- The `changes` subcommand now requires a `PATH` argument--## [v1.0.2.0](https://github.com/freckle/stackctl/compare/v1.0.1.2...v1.0.2.0)--- Add `Stackctl.Action`-- Support for taking actions during Stack management, currently we support- invoking a lambda post-deployment. In the future, we can add more, such as- running local pre-deploy validation or preparation scripts.--- Add `awsCloudFormationDescribeStackOutputs`--## [v1.0.1.2](https://github.com/freckle/stackctl/compare/v1.0.1.1...v1.0.1.2)--- Always flush log messages before our own output--## [v1.0.1.1](https://github.com/freckle/stackctl/compare/v1.0.1.0...v1.0.1.1)--- Respect `LOG_DESTINATION` (the default remains `stderr`)--## [v1.0.1.0](https://github.com/freckle/stackctl/compare/v1.0.0.2...v1.0.1.0)--- Support reading CloudGenesis specifications-- - Accept account paths like `id.name` or `name.id`- - Read `Parameters` as `Parameter{Key,Value}` or `{Name,Value}`-- This allows us to work with specifications directories originally implemented- for, and potentially still used with, the CloudGenesis tooling.--## [v1.0.0.2](https://github.com/freckle/stackctl/compare/v1.0.0.1...v1.0.0.2)--- Fix tailing all events to read most recent, causing Throttling errors--## [v1.0.0.1](https://github.com/freckle/stackctl/compare/v1.0.0.0...v1.0.0.1)--- Fix non-portable paths issue in OSX executable build--## [v1.0.0.0](https://github.com/freckle/stackctl/tree/v1.0.0.0)--First release+See https://github.com/freckle/stackctl/releases
app/Main.hs view
@@ -11,8 +11,8 @@ main = runSubcommand $ subcommand Commands.cat- <> subcommand Commands.capture- <> subcommand Commands.changes- <> subcommand Commands.deploy- <> subcommand Commands.list- <> subcommand Commands.version+ <> subcommand Commands.capture+ <> subcommand Commands.changes+ <> subcommand Commands.deploy+ <> subcommand Commands.list+ <> subcommand Commands.version
src/Stackctl/AWS/CloudFormation.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE DuplicateRecordFields #-}+ module Stackctl.AWS.CloudFormation ( Stack (..) , stack_stackName@@ -194,7 +196,7 @@ handling_ _ValidationError (pure Nothing) $ awsSilently -- don't log said 400 $ Just- <$> awsCloudFormationDescribeStack stackName+ <$> awsCloudFormationDescribeStack stackName awsCloudFormationDescribeStackOutputs :: (MonadIO m, MonadAWS m)@@ -218,10 +220,10 @@ runConduit $ AWS.paginate req- .| mapC (fromMaybe [] . (^. describeStackEventsResponse_stackEvents))- .| concatC- .| takeWhileC (\e -> Just (e ^. stackEvent_eventId) /= mLastId)- .| sinkList+ .| mapC (fromMaybe [] . (^. describeStackEventsResponse_stackEvents))+ .| concatC+ .| takeWhileC (\e -> Just (e ^. stackEvent_eventId) /= mLastId)+ .| sinkList awsCloudFormationGetStackNamesMatching :: (MonadIO m, MonadAWS m)@@ -232,12 +234,12 @@ runConduit $ AWS.paginate req- .| concatMapC (^. listStacksResponse_stackSummaries)- .| concatC- .| mapC (^. stackSummary_stackName)- .| filterC ((p `match`) . unpack)- .| mapC StackName- .| sinkList+ .| concatMapC (^. listStacksResponse_stackSummaries)+ .| concatC+ .| mapC (^. stackSummary_stackName)+ .| filterC ((p `match`) . unpack)+ .| mapC StackName+ .| sinkList awsCloudFormationGetMostRecentStackEventId :: (MonadIO m, MonadAWS m)@@ -258,9 +260,9 @@ AWS.simple req $ pure- . getFirstEventId- . fromMaybe []- . (^. describeStackEventsResponse_stackEvents)+ . getFirstEventId+ . fromMaybe []+ . (^. describeStackEventsResponse_stackEvents) awsCloudFormationDeleteStack :: (MonadIO m, MonadLogger m, MonadAWS m)@@ -314,7 +316,7 @@ awaitStack waiter stackName = AWS.await waiter $ newDescribeStacks- & describeStacks_stackName ?~ unStackName stackName+ & describeStacks_stackName ?~ unStackName stackName makeParameter :: Text -> Maybe Text -> Parameter makeParameter k v =@@ -424,7 +426,7 @@ logInfo $ "Creating changeset..."- :# ["name" .= name, "type" .= changeSetType]+ :# ["name" .= name, "type" .= changeSetType] csId <- AWS.simple req (^. createChangeSetResponse_id) logDebug "Awaiting CREATE_COMPLETE"@@ -471,16 +473,16 @@ logInfo "Deleting all changesets" runConduit $ AWS.paginate (newListChangeSets $ unStackName stackName)- .| concatMapC- ( \resp -> fromMaybe [] $ do- ss <- resp ^. listChangeSetsResponse_summaries- pure $ mapMaybe Summary.changeSetId ss- )- .| mapM_C- ( \csId -> do- logInfo $ "Enqueing delete" :# ["changeSetId" .= csId]- void $ AWS.send $ newDeleteChangeSet csId- )+ .| concatMapC+ ( \resp -> fromMaybe [] $ do+ ss <- resp ^. listChangeSetsResponse_summaries+ pure $ mapMaybe Summary.changeSetId ss+ )+ .| mapM_C+ ( \csId -> do+ logInfo $ "Enqueing delete" :# ["changeSetId" .= csId]+ void $ AWS.send $ newDeleteChangeSet csId+ ) -- | Did we abandoned this Stack's first ever ChangeSet? --
src/Stackctl/AWS/Core.hs view
@@ -77,8 +77,6 @@ , MonadIO m , MonadAWS m , AWSRequest a- , Typeable a- , Typeable (AWSResponse a) ) => a -> (AWSResponse a -> Maybe b)@@ -160,10 +158,10 @@ handling _ServiceError $ \e -> do logError $ "Exiting due to AWS Service error"- :# [ "code" .= toText (e ^. serviceError_code)- , "message" .= fmap toText (e ^. serviceError_message)- , "requestId" .= fmap toText (e ^. serviceError_requestId)- ]+ :# [ "code" .= toText (e ^. serviceError_code)+ , "message" .= fmap toText (e ^. serviceError_message)+ , "requestId" .= fmap toText (e ^. serviceError_requestId)+ ] exitFailure formatServiceError :: ServiceError -> Text
src/Stackctl/AWS/Lambda.hs view
@@ -93,11 +93,11 @@ logDebug $ "Function result"- :# [ "name" .= name- , "status" .= status- , "error" .= mError- , "functionError" .= mFunctionError- ]+ :# [ "name" .= name+ , "status" .= status+ , "error" .= mError+ , "functionError" .= mFunctionError+ ] pure $ if
src/Stackctl/AWS/Orphans.hs view
@@ -14,6 +14,9 @@ import Data.Aeson import GHC.Generics (Rep) +-- TODO: upstream+deriving newtype instance MonadUnliftIO m => MonadUnliftIO (WithLogger env m)+ -- Makes it syntactally easier to do a bunch of these newtype Generically a = Generically {unGenerically :: a}
src/Stackctl/AWS/Scope.hs view
@@ -26,20 +26,16 @@ awsScopeSpecPatterns AwsScope {..} = [ compile $ "stacks"- </> unpack (unAccountId awsAccountId)- <> ".*"- </> unpack (fromRegion awsRegion)- <> "**"- </> "*"- <.> "yaml"+ </> unpack (unAccountId awsAccountId) <> ".*"+ </> unpack (fromRegion awsRegion)+ </> "**"+ </> "*" <.> "yaml" , compile $ "stacks"- </> "*."- <> unpack (unAccountId awsAccountId)- </> unpack (fromRegion awsRegion)- <> "**"- </> "*"- <.> "yaml"+ </> "*." <> unpack (unAccountId awsAccountId)+ </> unpack (fromRegion awsRegion)+ </> "**"+ </> "*" <.> "yaml" ] awsScopeSpecStackName :: AwsScope -> FilePath -> Maybe StackName@@ -50,13 +46,13 @@ -- pretty fast and loose with the "parsing" step pure $ path -- stacks/account/region/x/y.yaml- & splitPath -- [stacks/, account/, region/, x/, y.yaml]- & drop 3 -- [x, y.yaml]- & joinPath -- x/y.yaml- & dropExtension -- x/y- & pack- & T.replace "/" "-" -- x-y- & StackName+ & splitPath -- [stacks/, account/, region/, x/, y.yaml]+ & drop 3 -- [x, y.yaml]+ & joinPath -- x/y.yaml+ & dropExtension -- x/y+ & pack+ & T.replace "/" "-" -- x-y+ & StackName class HasAwsScope env where awsScopeL :: Lens' env AwsScope
src/Stackctl/Action.hs view
@@ -128,10 +128,10 @@ Nothing -> do logError $ "Output not found"- :# [ "stackName" .= stackName- , "desiredOutput" .= outputName- , "availableOutputs" .= map (^. output_outputKey) outputs- ]+ :# [ "stackName" .= stackName+ , "desiredOutput" .= outputName+ , "availableOutputs" .= map (^. output_outputKey) outputs+ ] throwIO NoSuchOutput Just name -> invoke name InvokeLambdaByName name -> invoke name
src/Stackctl/CLI.hs view
@@ -7,6 +7,7 @@ import Stackctl.Prelude +import Blammo.Logging.LogSettings import qualified Blammo.Logging.LogSettings.Env as LoggingEnv import Control.Monad.AWS as AWS import Control.Monad.AWS.ViaReader as AWS@@ -60,7 +61,7 @@ autoSSOOptionL = optionsL . autoSSOOptionL newtype AppT app m a = AppT- { unAppT :: ReaderT app (LoggingT (ResourceT m)) a+ { unAppT :: ReaderT app (ResourceT m) a } deriving newtype ( Functor@@ -70,12 +71,13 @@ , MonadUnliftIO , MonadResource , MonadReader app- , MonadLogger , MonadThrow , MonadCatch , MonadMask ) deriving (MonadAWS) via (ReaderAWS (AppT app m))+ deriving (MonadLogger) via (WithLogger app (ResourceT m))+ deriving (MonadLoggerIO) via (WithLogger app (ResourceT m)) runAppT :: ( MonadMask m@@ -94,36 +96,33 @@ . setLogSettingsConcurrency (Just 1) $ defaultLogSettings - logger <-- newLogger- $ adjustLogSettings- (options ^. colorOptionL)- (options ^. verboseOptionL)- envLogSettings+ let logSettings =+ adjustLogSettings+ (options ^. colorOptionL)+ (options ^. verboseOptionL)+ envLogSettings - app <- runResourceT $ runLoggerLoggingT logger $ do- aws <- runReaderT (handleAutoSSO options AWS.discover) logger+ withLogger logSettings $ \appLogger -> do+ appAwsEnv <- runWithLogger appLogger $ handleAutoSSO options AWS.discover+ appConfig <- runWithLogger appLogger loadConfigOrExit+ appAwsScope <- AWS.runEnvT fetchAwsScope appAwsEnv - App logger- <$> loadConfigOrExit- <*> pure options- <*> AWS.runEnvT fetchAwsScope aws- <*> pure aws+ let+ AwsScope {..} = appAwsScope - let- AwsScope {..} = appAwsScope app+ context =+ [ "region" .= awsRegion+ , "accountId" .= awsAccountId+ , "accountName" .= awsAccountName+ ] - context =- [ "region" .= awsRegion- , "accountId" .= awsAccountId- , "accountName" .= awsAccountName- ]+ appOptions = options+ app = App {..} - runResourceT- $ runLoggerLoggingT app- $ flip runReaderT app- $ withThreadContext context- $ unAppT f+ runResourceT+ $ flip runReaderT app+ $ withThreadContext context+ $ unAppT f adjustLogSettings :: Maybe ColorOption -> Verbosity -> LogSettings -> LogSettings
src/Stackctl/Config.hs view
@@ -75,9 +75,10 @@ loadConfig :: MonadIO m => m (Either ConfigError Config) loadConfig =- runExceptT $ getConfigFile >>= \case- Nothing -> pure emptyConfig- Just cf -> loadConfigFrom cf+ runExceptT+ $ getConfigFile >>= \case+ Nothing -> pure emptyConfig+ Just cf -> loadConfigFrom cf loadConfigFrom :: (MonadIO m, MonadError ConfigError m) => FilePath -> m Config loadConfigFrom path = loadConfigFromBytes =<< liftIO (readFileBinary path)
src/Stackctl/Config/RequiredVersion.hs view
@@ -54,7 +54,7 @@ ws -> Left $ show (unpack $ T.unwords ws)- <> " did not parse as optional operator and version string"+ <> " did not parse as optional operator and version string" parseRequiredVersion :: Text -> Text -> Either String RequiredVersion parseRequiredVersion op w = RequiredVersion <$> parseOp op <*> parseVersion w@@ -71,8 +71,8 @@ op -> Left $ "Invalid comparison operator ("- <> unpack op- <> "), may only be =, <, <=, >, >=, or =~"+ <> unpack op+ <> "), may only be =, <, <=, >, >=, or =~" parseVersion :: Text -> Either String Version parseVersion t =
src/Stackctl/FilterOption.hs view
@@ -44,8 +44,8 @@ Env.var (first Env.UnreadError . readFilterOption) name $ Env.help $ "Filter "- <> items- <> " by patterns"+ <> items+ <> " by patterns" filterOption :: String -> Parser FilterOption filterOption items =
src/Stackctl/Options.hs view
@@ -55,11 +55,11 @@ envParser = Env.prefixed "STACKCTL_" $ Options- <$> optional envDirectoryOption- <*> optional (envFilterOption "specifications")- <*> pure mempty -- use LOG_COLOR- <*> pure mempty -- use LOG_LEVEL- <*> optional envAutoSSOOption+ <$> optional envDirectoryOption+ <*> optional (envFilterOption "specifications")+ <*> pure mempty -- use LOG_COLOR+ <*> pure mempty -- use LOG_LEVEL+ <*> optional envAutoSSOOption -- brittany-disable-next-binding
src/Stackctl/Prelude.hs view
@@ -20,6 +20,8 @@ ) import Blammo.Logging as X+import Blammo.Logging.Setup as X+import Blammo.Logging.ThreadContext as X import Control.Error.Util as X (hush, note) import Data.Aeson as X (ToJSON (..), object) import Data.Text as X (pack, unpack)
src/Stackctl/Spec/Capture.hs view
@@ -132,9 +132,8 @@ case results of [] -> do logError- $ "No Active Stacks match "- <> pack (decompile scoStackName)- :# []+ $ "No Active Stacks match " <> pack (decompile scoStackName)+ :# [] exitFailure [stackName] -> do stack <- awsCloudFormationDescribeStack stackName
src/Stackctl/Spec/Cat.hs view
@@ -138,11 +138,11 @@ kvs <- f <$> mA pure $ [cyan label <> ":"]- <> map- ( \(k, mV) ->- " " <> cyan k <> ":" <> maybe "" (\v -> " " <> green v) mV- )- kvs+ <> map+ ( \(k, mV) ->+ " " <> cyan k <> ":" <> maybe "" (\v -> " " <> green v) mV+ )+ kvs ppList :: Text -> (a -> [Text]) -> Maybe a -> [Text] ppList label f = maybe [] (((cyan label <> ":") :) . f)@@ -186,8 +186,8 @@ displayObjectProperty = displayPropertyWith @(HashMap Text Value) $ map ((" - " <>) . green)- . sort- . HashMap.keys+ . sort+ . HashMap.keys displayPropertyWith :: (FromJSON a, ToJSON a) => (a -> [Text]) -> Text -> [Text]
src/Stackctl/Spec/Changes/Format.hs view
@@ -76,10 +76,11 @@ (Nothing, _) -> "No changes for " <> name (_, Nothing) -> "Metadata only changes (e.g. Tags or Outputs)" (_, Just rcs) ->- ("\n" <>) $ (<> "\n") $ mconcat $ ("Changes for " <> cyan name <> ":")- : map- (("\n " <>) . formatResourceChange)- (NE.toList rcs)+ ("\n" <>)+ $ (<> "\n")+ $ mconcat+ $ ("Changes for " <> cyan name <> ":")+ : map (("\n " <>) . formatResourceChange) (NE.toList rcs) where rChanges = do cs <- mChangeSet@@ -149,20 +150,20 @@ , "\n| Action | Logical Id | Physical Id | Type | Replacement | Scope | Details |" , "\n| --- | --- | --- | --- | --- | --- | --- |" ]- <> map commentTableRow (NE.toList rcs)- <> case omitFull of- OmitFull -> []- IncludeFull ->- [ "\n"- , "\n<details>"- , "\n<summary>Full changes</summary>"- , "\n"- , "\n```json"- , "\n" <> changeSetJSON cs- , "\n```"- , "\n"- , "\n</details>"- ]+ <> map commentTableRow (NE.toList rcs)+ <> case omitFull of+ OmitFull -> []+ IncludeFull ->+ [ "\n"+ , "\n<details>"+ , "\n<summary>Full changes</summary>"+ , "\n"+ , "\n```json"+ , "\n" <> changeSetJSON cs+ , "\n```"+ , "\n"+ , "\n</details>"+ ] commentTableRow :: ResourceChange -> Text commentTableRow ResourceChange' {..} =@@ -194,10 +195,10 @@ pure $ toText c- <> maybe "" ((" in " <>) . toText) attr- <> maybe "" (\x -> " (" <> magenta (toText x) <> ")") n- <> maybe "" ((", recreation " <>) . formatRR) rr- <> maybe "" ((", caused by " <>) . toText) causingEntity+ <> maybe "" ((" in " <>) . toText) attr+ <> maybe "" (\x -> " (" <> magenta (toText x) <> ")") n+ <> maybe "" ((", recreation " <>) . formatRR) rr+ <> maybe "" ((", caused by " <>) . toText) causingEntity where formatRR = \case x@RequiresRecreation_Always -> red (toText x)
src/Stackctl/Spec/Deploy.hs view
@@ -266,8 +266,7 @@ timestamp <- liftIO $ formatTime defaultTimeLocale "%F %T %Z"- <$> utcToLocalZonedTime- (e ^. stackEvent_timestamp)+ <$> utcToLocalZonedTime (e ^. stackEvent_timestamp) pure $ mconcat@@ -276,8 +275,7 @@ , maybe "" colorStatus $ e ^. stackEvent_resourceStatus , maybe "" (magenta . (" " <>)) $ e ^. stackEvent_logicalResourceId , maybe "" ((\x -> " (" <> x <> ")") . T.strip)- $ e- ^. stackEvent_resourceStatusReason+ $ e ^. stackEvent_resourceStatusReason ] where colorStatus = \case
src/Stackctl/Spec/Discover.hs view
@@ -105,9 +105,9 @@ logError $ "Multiple specifications produced the same Stack name"- :# [ "name" .= stackSpecPathStackName (NE.head specPaths)- , "paths" .= collidingPaths- ]+ :# [ "name" .= stackSpecPathStackName (NE.head specPaths)+ , "paths" .= collidingPaths+ ] exitFailure @@ -130,18 +130,17 @@ for_ depends $ \depend -> do let (nearest, _distance) = NE.minimumBy1 (comparing snd)- $ (id &&& getDistance depend)- <$> known+ $ (id &&& getDistance depend) <$> known logWarn $ "Stack lists dependency that does not exist"- :# [ "dependency"- .= ( unStackName (stackSpecStackName spec)- <> " -> "- <> unStackName depend- )- , "hint" .= ("Did you mean " <> unStackName nearest <> "?")- ]+ :# [ "dependency"+ .= ( unStackName (stackSpecStackName spec)+ <> " -> "+ <> unStackName depend+ )+ , "hint" .= ("Did you mean " <> unStackName nearest <> "?")+ ] getDistance = levenshtein `on` unStackName
src/Stackctl/Spec/List.hs view
@@ -79,7 +79,7 @@ when loLegend $ pushLoggerLn $ "\nLegend:\n "- <> T.intercalate ", " (map legendItem [minBound .. maxBound])+ <> T.intercalate ", " (map legendItem [minBound .. maxBound]) data Indicator = Deployed
src/Stackctl/StackSpec.hs view
@@ -81,8 +81,7 @@ stackSpecTemplate spec = StackTemplate $ FilePath.normalise- $ ssSpecRoot spec- </> stackSpecTemplateFile spec+ $ ssSpecRoot spec </> stackSpecTemplateFile spec stackSpecParameters :: StackSpec -> [Parameter] stackSpecParameters =@@ -197,8 +196,7 @@ (stackSpecStackName spec) (stackSpecStackDescription spec) (stackSpecTemplate spec)- ( nubOrdOn (^. parameter_parameterKey) $ parameters <> stackSpecParameters spec- )+ (nubOrdOn (^. parameter_parameterKey) $ parameters <> stackSpecParameters spec) (stackSpecCapabilities spec) (nubOrdOn (^. tag_key) $ tags <> stackSpecTags spec)
src/Stackctl/StackSpecPath.hs view
@@ -83,16 +83,16 @@ unless (pathAccountId == awsAccountId) $ Left $ "Unexpected account: "- <> unpack (unAccountId pathAccountId)- <> " != "- <> unpack (unAccountId awsAccountId)+ <> unpack (unAccountId pathAccountId)+ <> " != "+ <> unpack (unAccountId awsAccountId) unless (unpack (fromRegion awsRegion) == pathRegion) $ Left $ "Unexpected region: "- <> pathRegion- <> " != "- <> unpack (fromRegion awsRegion)+ <> pathRegion+ <> " != "+ <> unpack (fromRegion awsRegion) stackName <- maybe (Left "Must end in .yaml") (Right . StackName)@@ -117,6 +117,6 @@ _ -> Left $ "Path matches neither {account-id}.{account-name}, nor {account-name}.{account-id}: "- <> path+ <> path where isAccountId x = T.length x == 12 && T.all isDigit x
src/Stackctl/StackSpecYaml.hs view
@@ -85,8 +85,7 @@ $ KeyMap.toList $ KeyMap.fromListWith (<>) $ map (pyKey &&& pyValue)- $ bs -- flipped to make sure Last-wins- <> as+ $ bs <> as -- flipped to make sure Last-wins instance FromJSON ParametersYaml where parseJSON = \case@@ -108,7 +107,7 @@ toJSON = object . parametersYamlPairs toEncoding = pairs . mconcat . parametersYamlPairs -parametersYamlPairs :: KeyValue kv => ParametersYaml -> [kv]+parametersYamlPairs :: KeyValue e kv => ParametersYaml -> [kv] parametersYamlPairs = map parameterYamlPair . unParametersYaml parametersYaml :: [ParameterYaml] -> ParametersYaml@@ -125,7 +124,7 @@ (mkParameterYaml <$> o .: "Name" <*> o .:? "Value") <|> (mkParameterYaml <$> o .: "ParameterKey" <*> o .:? "ParameterValue") -parameterYamlPair :: KeyValue kv => ParameterYaml -> kv+parameterYamlPair :: KeyValue e kv => ParameterYaml -> kv parameterYamlPair ParameterYaml {..} = pyKey .= pyValue parameterYaml :: Parameter -> Maybe ParameterYaml@@ -215,8 +214,7 @@ $ HashMap.toList $ HashMap.fromList $ map (toPair . unTagYaml)- $ as- <> bs+ $ as <> bs where toPair :: Tag -> (Text, Text) toPair = (^. tag_key) &&& (^. tag_value)@@ -237,7 +235,7 @@ toJSON = object . tagsYamlPairs toEncoding = pairs . mconcat . tagsYamlPairs -tagsYamlPairs :: KeyValue kv => TagsYaml -> [kv]+tagsYamlPairs :: KeyValue e kv => TagsYaml -> [kv] tagsYamlPairs = map tagYamlPair . unTagsYaml tagsYaml :: [TagYaml] -> TagsYaml@@ -253,5 +251,5 @@ t <- newTag <$> o .: "Key" <*> o .: "Value" pure $ TagYaml t -tagYamlPair :: KeyValue kv => TagYaml -> kv+tagYamlPair :: KeyValue e kv => TagYaml -> kv tagYamlPair (TagYaml t) = Key.fromText (t ^. tag_key) .= (t ^. tag_value)
src/Stackctl/VerboseOption.hs view
@@ -7,6 +7,7 @@ import Stackctl.Prelude +import Blammo.Logging.LogSettings import Blammo.Logging.LogSettings.LogLevels import Options.Applicative
src/Stackctl/Version.hs view
@@ -3,10 +3,10 @@ ) where import Stackctl.Prelude+import Prelude (putStrLn) import Data.Version import qualified Paths_stackctl as Pkg-import Prelude (putStrLn) logVersion :: MonadIO m => m () logVersion = liftIO $ putStrLn $ ("Stackctl v" <>) $ showVersion Pkg.version
stackctl.cabal view
@@ -1,6 +1,6 @@ cabal-version: 1.18 name: stackctl-version: 1.7.3.0+version: 1.7.3.2 license: MIT license-file: LICENSE copyright: 2022 Renaissance Learning Inc@@ -79,17 +79,17 @@ -fignore-optim-changes -fwrite-ide-info -Weverything -Wno-all-missed-specialisations -Wno-missed-specialisations -Wno-missing-import-lists -Wno-missing-kind-signatures- -Wno-missing-local-signatures -Wno-missing-safe-haskell-mode- -Wno-prepositive-qualified-module -Wno-unsafe- -optP-Wno-nonportable-include-path+ -Wno-missing-local-signatures -Wno-missing-role-annotations+ -Wno-missing-safe-haskell-mode -Wno-prepositive-qualified-module+ -Wno-unsafe -optP-Wno-nonportable-include-path build-depends: Blammo >=1.1.2.3, Glob >=0.10.2,- QuickCheck >=2.14.2,- aeson >=2.0.3.0,+ QuickCheck >=2.14.3,+ aeson >=2.2.3.0, aeson-casing >=0.2.0.0,- aeson-pretty >=0.8.9,+ aeson-pretty >=0.8.10, amazonka >=2.0, amazonka-cloudformation >=2.0, amazonka-core >=2.0,@@ -99,33 +99,33 @@ amazonka-sso >=2.0, amazonka-sts >=2.0, base >=4 && <5,- bytestring >=0.11.3.1,+ bytestring >=0.12.1.0, cfn-flip >=0.1.0.3,- conduit >=1.3.4.3,- containers >=0.6.5.1,- envparse >=0.5.0,+ conduit >=1.3.6,+ containers >=0.6.8,+ envparse >=0.6.0, errors >=2.3.0,- exceptions >=0.10.4,- extra >=1.7.12,- filepath >=1.4.2.2,- lens >=5.1.1,- lens-aeson >=1.2.2,- monad-logger >=0.3.37,- mtl >=2.2.2,- optparse-applicative >=0.17.0.0,- resourcet >=1.2.6,+ exceptions >=0.10.7,+ extra >=1.7.16,+ filepath >=1.4.301.0,+ lens >=5.3.3,+ lens-aeson >=1.2.3,+ monad-logger >=0.3.41,+ mtl >=2.3.1,+ optparse-applicative >=0.18.1.0,+ resourcet >=1.3.0, rio >=0.1.22.0, semigroups >=0.20,- text >=1.2.5.0,- text-metrics >=0.3.2,- time >=1.11.1.1,- transformers >=0.5.6.2,- typed-process >=0.2.10.1,- unix >=2.7.2.2,+ text >=2.1.1,+ text-metrics >=0.3.3,+ time >=1.12.2,+ transformers >=0.6.1.0,+ typed-process >=0.2.12.0,+ unix >=2.8.6.0, unliftio >=0.2.25.0,- unordered-containers >=0.2.19.1,- uuid >=1.3.15,- yaml >=0.11.8.0+ unordered-containers >=0.2.20,+ uuid >=1.3.16,+ yaml >=0.11.11.2 executable stackctl main-is: Main.hs@@ -145,9 +145,9 @@ -fignore-optim-changes -fwrite-ide-info -Weverything -Wno-all-missed-specialisations -Wno-missed-specialisations -Wno-missing-import-lists -Wno-missing-kind-signatures- -Wno-missing-local-signatures -Wno-missing-safe-haskell-mode- -Wno-prepositive-qualified-module -Wno-unsafe- -optP-Wno-nonportable-include-path -threaded -rtsopts+ -Wno-missing-local-signatures -Wno-missing-role-annotations+ -Wno-missing-safe-haskell-mode -Wno-prepositive-qualified-module+ -Wno-unsafe -optP-Wno-nonportable-include-path -threaded -rtsopts -with-rtsopts=-N build-depends:@@ -190,31 +190,31 @@ -fignore-optim-changes -fwrite-ide-info -Weverything -Wno-all-missed-specialisations -Wno-missed-specialisations -Wno-missing-import-lists -Wno-missing-kind-signatures- -Wno-missing-local-signatures -Wno-missing-safe-haskell-mode- -Wno-prepositive-qualified-module -Wno-unsafe- -optP-Wno-nonportable-include-path+ -Wno-missing-local-signatures -Wno-missing-role-annotations+ -Wno-missing-safe-haskell-mode -Wno-prepositive-qualified-module+ -Wno-unsafe -optP-Wno-nonportable-include-path build-depends:- Blammo >=1.1.2.3,+ Blammo >=2.1.1.0, Glob >=0.10.2,- QuickCheck >=2.14.2,- aeson >=2.0.3.0,+ QuickCheck >=2.14.3,+ aeson >=2.2.3.0, amazonka >=2.0, amazonka-cloudformation >=2.0, amazonka-ec2 >=2.0, amazonka-lambda >=2.0, amazonka-mtl >=0.1.1.0, base >=4 && <5,- bytestring >=0.11.3.1,- filepath >=1.4.2.2,- hspec >=2.9.7,+ bytestring >=0.12.1.0,+ filepath >=1.4.301.0,+ hspec >=2.11.10, hspec-expectations-lifted >=0.10.0, hspec-golden >=0.2.1.0,- http-types >=0.12.3,- lens >=5.1.1,- mtl >=2.2.2,+ http-types >=0.12.4,+ lens >=5.3.3,+ mtl >=2.3.1, stackctl,- text >=1.2.5.0,- time >=1.11.1.1,+ text >=2.1.1,+ time >=1.12.2, unliftio >=0.2.25.0,- yaml >=0.11.8.0+ yaml >=0.11.11.2
test/Stackctl/AWS/EC2Spec.hs view
@@ -23,7 +23,7 @@ $ Right $ newDescribeAvailabilityZonesResponse 200 & describeAvailabilityZonesResponse_availabilityZones- ?~ zones+ ?~ zones withMatcher matcher awsEc2DescribeFirstAvailabilityZoneRegionName `shouldReturn` "us-east-1"
test/Stackctl/AWS/LambdaSpec.hs view
@@ -33,18 +33,16 @@ [ SendMatcher (isInvocation "lambda-1") $ Right $ newInvokeResponse 200- & invokeResponse_payload- ?~ "<response>"+ & invokeResponse_payload ?~ "<response>" , SendMatcher (isInvocation "lambda-2") $ Right $ newInvokeResponse 200- & invokeResponse_payload- ?~ BSL.toStrict (encode lambdaError)+ & invokeResponse_payload ?~ BSL.toStrict (encode lambdaError) , SendMatcher (isInvocation "lambda-3") $ Right $ newInvokeResponse 500 & (invokeResponse_payload ?~ "<response>")- . (invokeResponse_functionError ?~ "<error>")+ . (invokeResponse_functionError ?~ "<error>") ] withMatchers matchers $ do
test/Stackctl/ConfigSpec.hs view
@@ -32,8 +32,7 @@ case result of Left err -> do expectationFailure- $ "Expected to load a Config, got error: "- <> show err+ $ "Expected to load a Config, got error: " <> show err Right config -> do configParameters config `shouldBe` Just (toParametersYaml [("Some", Just "Parameter")])@@ -56,15 +55,15 @@ Right config = loadConfigFromBytes $ "defaults:"- <> "\n tags:"- <> "\n From: Defaults"- <> "\n Keep: \"You?\""+ <> "\n tags:"+ <> "\n From: Defaults"+ <> "\n Keep: \"You?\"" Just tags = ssyTags (applyConfig config specYaml) tags `shouldBe` toTagsYaml- [("From", "Defaults"), ("Hi", "There"), ("Keep", "Me")]+ [("Hi", "There"), ("From", "Defaults"), ("Keep", "Me")] loadConfigFromLines :: MonadError ConfigError m => [ByteString] -> m Config loadConfigFromLines = loadConfigFromBytes . mconcat . map (<> "\n")
test/Stackctl/Test/App.hs view
@@ -15,6 +15,7 @@ import Stackctl.Prelude +import Blammo.Logging.LogSettings (defaultLogSettings) import Blammo.Logging.Logger (newTestLogger) import Control.Lens ((?~)) import Control.Monad.AWS@@ -92,5 +93,4 @@ "stacks" </> "0123456789.test" </> "us-east-1"- </> unpack base- <.> "yaml"+ </> unpack base <.> "yaml"