From 034e3a0dff90343d8ca0f97ac9813e0981920cff Mon Sep 17 00:00:00 2001 From: Neil Mayhew Date: Wed, 8 Oct 2025 16:04:31 -0600 Subject: [PATCH 1/8] Improve error reporting in changelogs subcommand * Catch and report IO exceptions * Exit with a failure if exceptions or errors occurred --- changelogs/Changelogs.hs | 21 ++++++++++++++------- changelogs/changelogs.cabal | 1 + 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/changelogs/Changelogs.hs b/changelogs/Changelogs.hs index 5fe0188..26c305a 100644 --- a/changelogs/Changelogs.hs +++ b/changelogs/Changelogs.hs @@ -5,11 +5,16 @@ module Changelogs (subcmd) where import Changelog -import Data.Foldable (for_) +import Control.Monad (when, (<=<)) +import Data.Bitraversable (bitraverse) +import Data.Either (isLeft) import Data.Functor ((<&>)) import Data.Text.Lazy (Text, unpack) +import Data.Traversable (for) import Options.Applicative -import System.IO (stderr) +import System.Exit (exitFailure) +import System.IO (hPrint, stderr) +import UnliftIO.Exception (tryAny) import qualified Data.Text.Lazy as TL import qualified Data.Text.Lazy.IO as TL @@ -61,8 +66,10 @@ subcmd :: Mod CommandFields (Global.Options -> IO ()) subcmd = command "changelogs" $ options <&> \Options {..} Global.Options {} -> do - for_ optChangelogs $ \fp -> do - let - printError e = TL.hPutStrLn stderr $ TL.pack fp <> ": " <> e - writeLog = optWriteFile fp . renderChangelog optBulletHierarchy - either printError writeLog . parseChangelog =<< TL.readFile fp + failure <- fmap (any isLeft) . for optChangelogs $ \fp -> do + bitraverse (hPrint stderr) pure <=< tryAny $ do + let + throwError e = errorWithoutStackTrace $ fp <> ": " <> TL.unpack e + writeLog = optWriteFile fp . renderChangelog optBulletHierarchy + either throwError writeLog . parseChangelog =<< TL.readFile fp + when failure exitFailure diff --git a/changelogs/changelogs.cabal b/changelogs/changelogs.cabal index 3c19e52..4c1a940 100644 --- a/changelogs/changelogs.cabal +++ b/changelogs/changelogs.cabal @@ -33,3 +33,4 @@ library optparse-applicative, pretty-simple, text, + unliftio, From d635cec4ae463e2ebac8596f084b8444a8a48852 Mon Sep 17 00:00:00 2001 From: Neil Mayhew Date: Wed, 8 Oct 2025 16:20:37 -0600 Subject: [PATCH 2/8] Stop appending an extra blank line when writing to stdout --- changelogs/Changelogs.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelogs/Changelogs.hs b/changelogs/Changelogs.hs index 26c305a..7f21197 100644 --- a/changelogs/Changelogs.hs +++ b/changelogs/Changelogs.hs @@ -44,7 +44,7 @@ options = <> metavar "FILE" stdoutParser = -- Write output to stdout - pure $ const TL.putStrLn + pure $ const TL.putStr optWriteFile <- inplaceParser <|> fileParser <|> stdoutParser optBulletHierarchy <- strOption $ From 19dd0635a3417a97f652d3140a4f8266d34db883 Mon Sep 17 00:00:00 2001 From: Neil Mayhew Date: Wed, 8 Oct 2025 17:30:21 -0600 Subject: [PATCH 3/8] Add `--version` options to main and subcommands --- changelogs/Changelogs.hs | 6 ++++-- changelogs/changelogs.cabal | 8 ++++++-- main/main.hs | 19 ++++++++++++++++--- 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/changelogs/Changelogs.hs b/changelogs/Changelogs.hs index 7f21197..fba23d1 100644 --- a/changelogs/Changelogs.hs +++ b/changelogs/Changelogs.hs @@ -2,7 +2,7 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} -module Changelogs (subcmd) where +module Changelogs (name, subcmd, version) where import Changelog import Control.Monad (when, (<=<)) @@ -11,7 +11,9 @@ import Data.Either (isLeft) import Data.Functor ((<&>)) import Data.Text.Lazy (Text, unpack) import Data.Traversable (for) +import Data.Version (showVersion) import Options.Applicative +import PackageInfo_changelogs (name, version) import System.Exit (exitFailure) import System.IO (hPrint, stderr) import UnliftIO.Exception (tryAny) @@ -29,7 +31,7 @@ data Options = Options options :: ParserInfo Options options = info - ( helper <*> do + ( helper <*> simpleVersioner (showVersion version) <*> do let inplaceParser = flag' TL.writeFile $ diff --git a/changelogs/changelogs.cabal b/changelogs/changelogs.cabal index 4c1a940..3b828cc 100644 --- a/changelogs/changelogs.cabal +++ b/changelogs/changelogs.cabal @@ -1,4 +1,4 @@ -cabal-version: 3.0 +cabal-version: 3.12 name: changelogs version: 0.1.0.0 synopsis: Utilities for processing cardano-ledger changelogs @@ -24,7 +24,11 @@ flag compat library import: language, warnings exposed-modules: Changelogs - other-modules: Changelog + other-modules: + Changelog + PackageInfo_changelogs + + autogen-modules: PackageInfo_changelogs build-depends: base, cmark, diff --git a/main/main.hs b/main/main.hs index f142307..832688e 100644 --- a/main/main.hs +++ b/main/main.hs @@ -3,12 +3,26 @@ {-# LANGUAGE RecordWildCards #-} import Data.Foldable (fold) +import Data.List (intercalate) +import Data.Version (Version, showVersion) import Options (Options (..)) import Options.Applicative import qualified Changelogs import qualified System.Console.Terminal.Size as TS +type Subcommand = Options -> IO () + +subcommands :: [(String, Version, Mod CommandFields Subcommand)] +subcommands = + [ (Changelogs.name, Changelogs.version, Changelogs.subcmd) + ] + +versionMessage :: String +versionMessage = + intercalate "\n" $ + [n <> ": " <> showVersion v | (n, v, _) <- subcommands] + main :: IO () main = do cols <- maybe 100 TS.width <$> TS.size @@ -17,7 +31,7 @@ main = do customExecParser (prefs $ columns cols) ( info - ( helper <*> do + ( helper <*> simpleVersioner versionMessage <*> do optVerbose <- switch $ help "Produce verbose output" @@ -25,8 +39,7 @@ main = do <> long "verbose" subcmd <- subparser . fold $ - [ Changelogs.subcmd - ] + [sc | (_, _, sc) <- subcommands] pure (subcmd, Options {..}) ) (fullDesc <> header "Cardano Ledger release tool") From 0f793caf707ddba600f825734c09947758b3b783 Mon Sep 17 00:00:00 2001 From: Neil Mayhew Date: Fri, 10 Oct 2025 17:06:20 -0600 Subject: [PATCH 4/8] Refactor into a single cabal package --- cabal.project | 5 +-- cardano-ledger-release-tool.cabal | 58 +++++++++++++++++++++++++++++++ changelogs/changelogs.cabal | 40 --------------------- common/common.cabal | 25 ------------- main/main.cabal | 35 ------------------- {changelogs => src}/Changelog.hs | 0 {changelogs => src}/Changelogs.hs | 6 ++-- {common => src}/Options.hs | 0 {main => src}/main.hs | 21 +++-------- 9 files changed, 66 insertions(+), 124 deletions(-) create mode 100644 cardano-ledger-release-tool.cabal delete mode 100644 changelogs/changelogs.cabal delete mode 100644 common/common.cabal delete mode 100644 main/main.cabal rename {changelogs => src}/Changelog.hs (100%) rename {changelogs => src}/Changelogs.hs (92%) rename {common => src}/Options.hs (100%) rename {main => src}/main.hs (61%) diff --git a/cabal.project b/cabal.project index 4960f67..e6fdbad 100644 --- a/cabal.project +++ b/cabal.project @@ -1,4 +1 @@ -packages: - common - changelogs - main +packages: . diff --git a/cardano-ledger-release-tool.cabal b/cardano-ledger-release-tool.cabal new file mode 100644 index 0000000..5b71a63 --- /dev/null +++ b/cardano-ledger-release-tool.cabal @@ -0,0 +1,58 @@ +cabal-version: 3.12 +name: cardano-ledger-release-tool +version: 0.1.0.0 +author: Neil Mayhew +copyright: 2025 IOG +license: Apache-2.0 +synopsis: + Assist with release policy for cardano-ledger + +description: + This is a tool that is used by the cardano-ledger team to simplify and enforce + releasing and versioning policy + +tested-with: + ghc ==8.10.7 || ==9.2.8 || ==9.4.8 || ==9.6.7 || ==9.8.4 || ==9.10.2 || ==9.12.2 + +common language + default-language: Haskell2010 + other-extensions: + ApplicativeDo + OverloadedStrings + RecordWildCards + +common warnings + ghc-options: + -Wall + -Wcompat + -Wunused-packages + -Werror + +common rts + ghc-options: + -threaded + -rtsopts + -with-rtsopts=-N + +executable cardano-ledger-release-tool + import: language, warnings, rts + hs-source-dirs: src + main-is: main.hs + other-modules: + Changelog + Changelogs + Options + PackageInfo_cardano_ledger_release_tool + + autogen-modules: + PackageInfo_cardano_ledger_release_tool + + build-depends: + base, + cmark, + mtl, + optparse-applicative, + pretty-simple, + terminal-size, + text, + unliftio, diff --git a/changelogs/changelogs.cabal b/changelogs/changelogs.cabal deleted file mode 100644 index 3b828cc..0000000 --- a/changelogs/changelogs.cabal +++ /dev/null @@ -1,40 +0,0 @@ -cabal-version: 3.12 -name: changelogs -version: 0.1.0.0 -synopsis: Utilities for processing cardano-ledger changelogs -author: Neil Mayhew -copyright: 2025 IOG -license: Apache-2.0 -tested-with: - ghc ==8.10.7 || ==9.2.8 || ==9.4.8 || ==9.6.7 || ==9.8.4 || ==9.10.2 || ==9.12.2 - -common language - default-language: Haskell2010 - -common warnings - ghc-options: - -Wall - -Wcompat - -Wunused-packages - -Werror - -flag compat - description: Use the foldable1-classes-compat package - -library - import: language, warnings - exposed-modules: Changelogs - other-modules: - Changelog - PackageInfo_changelogs - - autogen-modules: PackageInfo_changelogs - build-depends: - base, - cmark, - common, - mtl, - optparse-applicative, - pretty-simple, - text, - unliftio, diff --git a/common/common.cabal b/common/common.cabal deleted file mode 100644 index 406f1f7..0000000 --- a/common/common.cabal +++ /dev/null @@ -1,25 +0,0 @@ -cabal-version: 3.0 -name: common -version: 0.1.0.0 -synopsis: Library for cardano-ledger-release-tool -author: Neil Mayhew -copyright: 2025 IOG -license: Apache-2.0 -tested-with: - ghc ==8.10.7 || ==9.2.8 || ==9.4.8 || ==9.6.7 || ==9.8.4 || ==9.10.2 || ==9.12.2 - -common language - default-language: Haskell2010 - -common warnings - ghc-options: - -Wall - -Wcompat - -Wunused-packages - -Werror - -library - import: language, warnings - exposed-modules: Options - build-depends: - base diff --git a/main/main.cabal b/main/main.cabal deleted file mode 100644 index 1c14d0e..0000000 --- a/main/main.cabal +++ /dev/null @@ -1,35 +0,0 @@ -cabal-version: 3.0 -name: main -version: 0.1.0.0 -synopsis: Main package for cardano-ledger-release-tool -author: Neil Mayhew -copyright: 2025 IOG -license: Apache-2.0 -tested-with: - ghc ==8.10.7 || ==9.2.8 || ==9.4.8 || ==9.6.7 || ==9.8.4 || ==9.10.2 || ==9.12.2 - -common language - default-language: Haskell2010 - -common warnings - ghc-options: - -Wall - -Wcompat - -Wunused-packages - -Werror - -common rts - ghc-options: - -threaded - -rtsopts - -with-rtsopts=-N - -executable cardano-ledger-release-tool - import: language, warnings, rts - main-is: main.hs - build-depends: - base, - changelogs, - common, - optparse-applicative, - terminal-size, diff --git a/changelogs/Changelog.hs b/src/Changelog.hs similarity index 100% rename from changelogs/Changelog.hs rename to src/Changelog.hs diff --git a/changelogs/Changelogs.hs b/src/Changelogs.hs similarity index 92% rename from changelogs/Changelogs.hs rename to src/Changelogs.hs index fba23d1..7f21197 100644 --- a/changelogs/Changelogs.hs +++ b/src/Changelogs.hs @@ -2,7 +2,7 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} -module Changelogs (name, subcmd, version) where +module Changelogs (subcmd) where import Changelog import Control.Monad (when, (<=<)) @@ -11,9 +11,7 @@ import Data.Either (isLeft) import Data.Functor ((<&>)) import Data.Text.Lazy (Text, unpack) import Data.Traversable (for) -import Data.Version (showVersion) import Options.Applicative -import PackageInfo_changelogs (name, version) import System.Exit (exitFailure) import System.IO (hPrint, stderr) import UnliftIO.Exception (tryAny) @@ -31,7 +29,7 @@ data Options = Options options :: ParserInfo Options options = info - ( helper <*> simpleVersioner (showVersion version) <*> do + ( helper <*> do let inplaceParser = flag' TL.writeFile $ diff --git a/common/Options.hs b/src/Options.hs similarity index 100% rename from common/Options.hs rename to src/Options.hs diff --git a/main/main.hs b/src/main.hs similarity index 61% rename from main/main.hs rename to src/main.hs index 832688e..5e5b770 100644 --- a/main/main.hs +++ b/src/main.hs @@ -3,26 +3,14 @@ {-# LANGUAGE RecordWildCards #-} import Data.Foldable (fold) -import Data.List (intercalate) -import Data.Version (Version, showVersion) +import Data.Version (showVersion) import Options (Options (..)) import Options.Applicative +import PackageInfo_cardano_ledger_release_tool (version) import qualified Changelogs import qualified System.Console.Terminal.Size as TS -type Subcommand = Options -> IO () - -subcommands :: [(String, Version, Mod CommandFields Subcommand)] -subcommands = - [ (Changelogs.name, Changelogs.version, Changelogs.subcmd) - ] - -versionMessage :: String -versionMessage = - intercalate "\n" $ - [n <> ": " <> showVersion v | (n, v, _) <- subcommands] - main :: IO () main = do cols <- maybe 100 TS.width <$> TS.size @@ -31,7 +19,7 @@ main = do customExecParser (prefs $ columns cols) ( info - ( helper <*> simpleVersioner versionMessage <*> do + ( helper <*> simpleVersioner (showVersion version) <*> do optVerbose <- switch $ help "Produce verbose output" @@ -39,7 +27,8 @@ main = do <> long "verbose" subcmd <- subparser . fold $ - [sc | (_, _, sc) <- subcommands] + [ Changelogs.subcmd + ] pure (subcmd, Options {..}) ) (fullDesc <> header "Cardano Ledger release tool") From fa5ebd4a3776e9166d3b5138a89310e850012808 Mon Sep 17 00:00:00 2001 From: Neil Mayhew Date: Fri, 10 Oct 2025 17:06:53 -0600 Subject: [PATCH 5/8] Shorten executable name to clrt --- cardano-ledger-release-tool.cabal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cardano-ledger-release-tool.cabal b/cardano-ledger-release-tool.cabal index 5b71a63..93c8379 100644 --- a/cardano-ledger-release-tool.cabal +++ b/cardano-ledger-release-tool.cabal @@ -34,7 +34,7 @@ common rts -rtsopts -with-rtsopts=-N -executable cardano-ledger-release-tool +executable clrt import: language, warnings, rts hs-source-dirs: src main-is: main.hs From 85a895050d8e6051ee48e4651c66d1acf320cacc Mon Sep 17 00:00:00 2001 From: Neil Mayhew Date: Fri, 10 Oct 2025 17:14:27 -0600 Subject: [PATCH 6/8] Bump package version --- cardano-ledger-release-tool.cabal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cardano-ledger-release-tool.cabal b/cardano-ledger-release-tool.cabal index 93c8379..be5d927 100644 --- a/cardano-ledger-release-tool.cabal +++ b/cardano-ledger-release-tool.cabal @@ -1,6 +1,6 @@ cabal-version: 3.12 name: cardano-ledger-release-tool -version: 0.1.0.0 +version: 0.1.1.0 author: Neil Mayhew copyright: 2025 IOG license: Apache-2.0 From 9fd061ad984a180257ae4d1124337ab7183f3f6d Mon Sep 17 00:00:00 2001 From: Neil Mayhew Date: Wed, 8 Oct 2025 16:17:19 -0600 Subject: [PATCH 7/8] Add a CHANGELOG --- CHANGELOG.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..dc24ad9 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,25 @@ +# Changelog + +Version history for `cardano-ledger-release-tool` + +## 0.1.1.0 + +* Add a `--version` option +* Shorten executable name to `clrt` + +### changelogs + +* Improve error reporting + - Catch and report IO exceptions + - Exit with a failure if exceptions or errors occurred +* Stop appending an extra blank line when writing to stdout + +## 0.1.0.0 + +* Restructure as a single `cardano-ledger-release-tool` app with subcommands + +## 0.0.0.0 + +### changelogs + +* Initial release of the `changelogs` app From 21455880d218208b3fcb606b536ea0a9313741f6 Mon Sep 17 00:00:00 2001 From: Neil Mayhew Date: Wed, 8 Oct 2025 17:53:05 -0600 Subject: [PATCH 8/8] Lint changelogs in CI --- .github/workflows/haskell.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/haskell.yml b/.github/workflows/haskell.yml index 2e0403a..5b45191 100644 --- a/.github/workflows/haskell.yml +++ b/.github/workflows/haskell.yml @@ -52,3 +52,8 @@ jobs: - name: Run tests run: cabal test all + + - name: Lint changelogs + run: | + cabal run -- clrt changelogs -i $(git ls-files '*CHANGELOG.md') + git diff --exit-code