Skip to content

Commit edf2baa

Browse files
authored
Merge pull request #6209 from IntersectMBO/mkarg/simplify-generate-markdown
scripts: replace heavy pandoc dependency with text-based markdown table in changelog link generator
2 parents be74c97 + cd85ac1 commit edf2baa

File tree

1 file changed

+51
-50
lines changed

1 file changed

+51
-50
lines changed

scripts/generate-release-changelog-links.hs

Lines changed: 51 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#!/usr/bin/env -S cabal --verbose=1 --index-state=2024-04-09T14:49:48Z run --
1+
#!/usr/bin/env -S cabal --verbose=1 --index-state=2025-04-16T18:30:40Z run --
22
{- cabal:
33
build-depends:
44
base,
@@ -14,7 +14,6 @@
1414
network-uri,
1515
optparse-applicative ^>= 0.18,
1616
ansi-wl-pprint >= 1,
17-
pandoc ^>= 3.1,
1817
prettyprinter,
1918
req,
2019
text,
@@ -36,7 +35,6 @@
3635

3736
module Main (main) where
3837

39-
import Cabal.Plan
4038
import qualified Control.Foldl as Foldl
4139
import Data.Aeson
4240
import Data.ByteString.Char8 (ByteString)
@@ -47,11 +45,11 @@ import Data.Map.Strict (Map)
4745
import qualified Data.Map.Strict as Map
4846
import Data.Maybe
4947
import qualified Data.Text as Text
50-
import qualified Data.Text.IO as Text
5148
import qualified Data.Text.Encoding as Text
49+
import qualified Data.Text.IO as Text
5250
import Data.Version
53-
import qualified GitHub
54-
import Network.HTTP.Client (HttpExceptionContent(..), HttpException(..), responseStatus, responseHeaders)
51+
import Network.HTTP.Client (HttpException (..), HttpExceptionContent (..),
52+
responseHeaders, responseStatus)
5553
import Network.HTTP.Req
5654
import Network.HTTP.Types.Header (hLocation)
5755
import Network.HTTP.Types.Status (found302)
@@ -60,7 +58,9 @@ import qualified Network.URI.Encode as URIE
6058
import Options.Applicative
6159
import Prettyprinter
6260
import qualified Prettyprinter.Util as PP
63-
import qualified Text.Pandoc as Pandoc
61+
62+
import Cabal.Plan
63+
import qualified GitHub
6464
import Turtle
6565

6666
main :: IO ()
@@ -91,15 +91,8 @@ main = sh do
9191
pure (n, v, changelogLocation)
9292

9393
-- generate a massive markdown table
94-
let writerOptions =
95-
Pandoc.def { Pandoc.writerExtensions = Pandoc.githubMarkdownExtensions }
96-
pandocOutput = Pandoc.runPure do
97-
Pandoc.writeMarkdown writerOptions (generatePandoc changelogPaths)
98-
99-
case pandocOutput of
100-
Left pandocError -> die $
101-
"Failed to render markdown with error " <> Pandoc.renderError pandocError
102-
Right res -> liftIO . Text.writeFile outputPath $ format (s%"\n") res
94+
let res = generateMarkdown changelogPaths
95+
liftIO . Text.writeFile outputPath $ format (s%"\n") res
10396

10497
generateReleaseChangelogLinksDescription :: Description
10598
generateReleaseChangelogLinksDescription = Description $
@@ -212,38 +205,38 @@ findChangelogFromGitHub :: MonadIO m => GitHubAccessToken -> CHaPEntry -> m (May
212205
findChangelogFromGitHub accessToken c@CHaPEntry{..} = do
213206
liftIO $ print c
214207
let query = changelogLookupGitHub entryGitHubOwner entryGitHubRepo entrySubdir entryGitHubRevision
215-
liftIO $ print query
208+
liftIO $ print query
216209
contentDir <- liftIO (runGitHub accessToken query) >>= \case
217-
Left (GitHub.HTTPError originalError@(HttpExceptionRequest _originalReq (StatusCodeException resp _))) -> do
210+
Left (GitHub.HTTPError originalError@(HttpExceptionRequest _originalReq (StatusCodeException resp _))) -> do
218211
if responseStatus resp == found302
219212
then do
220213
let responseHeaders' = responseHeaders resp
221-
case List.lookup hLocation responseHeaders' of
214+
case List.lookup hLocation responseHeaders' of
222215
Nothing -> die "findChangelogFromGitHub: Got HTTP 302 redirect but no location header found"
223216
Just redirectLocation -> do
224217

225218
-- We must construct the redirect URL
226219
-- We drop 2 characters at the end because the location appears to be malformed
227220
let responseLocation = URIE.decodeText $ Text.dropEnd 2 $ Text.decodeUtf8 redirectLocation
228-
finalResponseQueryURl = responseLocation
221+
finalResponseQueryURl = responseLocation
229222

230-
newLocationQuery <- case query of
223+
newLocationQuery <- case query of
231224
GitHub.Query _ queryString -> do
232225
redirectPathSegments <- generateRedirectPathSegments finalResponseQueryURl
233-
pure $ GitHub.query redirectPathSegments queryString
226+
pure $ GitHub.query redirectPathSegments queryString
234227
unexpected -> die $ "findChangelogFromGitHub: Expected a Query type but got: " <> repr unexpected
235-
236-
r <- liftIO (runGitHub accessToken newLocationQuery)
237-
case r of
228+
229+
r <- liftIO (runGitHub accessToken newLocationQuery)
230+
case r of
238231
Left e' -> die $ Text.unlines [ "Redirect failed: " <> repr e'
239232
, "Original http error: " <> repr originalError
240233
]
241234
Right (GitHub.ContentFile _) -> die
242235
"Redirect result: Expected changelogLookupGitHub to return a directory, but got a single file"
243236
Right (GitHub.ContentDirectory dir) -> pure dir
244-
237+
245238
else die $
246-
"GitHub lookup failed with HTTP exception: " <> Text.pack (show resp)
239+
"GitHub lookup failed with HTTP exception: " <> Text.pack (show resp)
247240
Left gitHubError -> die $
248241
"GitHub lookup failed with error " <> repr gitHubError
249242
Right (GitHub.ContentFile _) -> die
@@ -258,9 +251,9 @@ findChangelogFromGitHub accessToken c@CHaPEntry{..} = do
258251
Just (name, constructGitHubPath entryGitHubOwner entryGitHubRepo entryGitHubRevision path)
259252

260253
generateRedirectPathSegments :: MonadIO m => Text -> m [Text]
261-
generateRedirectPathSegments url =
254+
generateRedirectPathSegments url =
262255
case URI.parseURI (Text.unpack url) of
263-
Just uri ->
256+
Just uri ->
264257
let segments = map Text.pack $ URI.pathSegments uri
265258
in if null segments
266259
then die $ "generateRedirectPathSegments: No path segments found in URL: " <> url
@@ -298,25 +291,33 @@ runGitHub :: GitHub.GitHubRW req res => GitHubAccessToken -> req -> res
298291
runGitHub (GitHubAccessToken tok) =
299292
GitHub.github (GitHub.OAuth tok)
300293

301-
generatePandoc :: [(PkgName, Ver, Maybe (Text, Text))] -> Pandoc.Pandoc
302-
generatePandoc ps =
303-
Pandoc.Pandoc mempty
304-
[ Pandoc.Plain [Pandoc.Str "Package changelogs"]
305-
, Pandoc.Table mempty (Pandoc.Caption Nothing []) colSpec tableHead [tableBody] (Pandoc.TableFoot mempty mempty)
306-
]
294+
generateMarkdown :: [(PkgName, Ver, Maybe (Text, Text))] -> Text
295+
generateMarkdown changelogPaths =
296+
let
297+
rows = mkHeader : map mkRow changelogPaths
298+
table = render rows
299+
in Text.unlines $ "Package changelogs" : "" : table
307300
where
308-
colSpec = replicate 3 (Pandoc.AlignDefault, Pandoc.ColWidthDefault)
309-
tableHead = Pandoc.TableHead mempty [Pandoc.Row mempty tableHeadCells]
310-
tableHeadCells =
311-
[ mkCell [Pandoc.Str "Package"]
312-
, mkCell [Pandoc.Str "Version"]
313-
, mkCell [Pandoc.Str "Changelog"]
314-
]
315-
tableBody = Pandoc.TableBody mempty 0 [] (fmap mkTableRow ps)
316-
mkTableRow (PkgName n, v, linkMaybe) =
317-
Pandoc.Row mempty
318-
[ mkCell [Pandoc.Str n]
319-
, mkCell [Pandoc.Str (dispVer v)]
320-
, mkCell (foldMap (\(fn, link) -> [Pandoc.Link mempty [Pandoc.Str fn] (link, fn)]) linkMaybe)
321-
]
322-
mkCell t = Pandoc.Cell mempty Pandoc.AlignDefault 1 1 [Pandoc.Plain t]
301+
mkHeader = ["Package", "Version", "Changelog"]
302+
mkRow (PkgName n, v, linkMaybe) = [n , dispVer v, dispLink linkMaybe]
303+
304+
-- example result: [CHANGELOG.md](https://github.com/IntersectMBO/cardano-base/blob/f11ddc7f/cardano-slotting/CHANGELOG.md "CHANGELOG.md")
305+
dispLink (Just (file, link)) = format ("["%s%"]("%s%" \""%s%"\")") file link file
306+
dispLink Nothing = ""
307+
308+
render :: [[Text]] -> [Text]
309+
render = map renderRow . List.transpose . map (separator . innerMargins . alignLeft) . List.transpose
310+
where
311+
renderRow = surroundWith '|' . Text.intercalate "|"
312+
313+
alignLeft ts =
314+
let maxLen = maximum (Text.length <$> ts)
315+
in map (Text.justifyLeft maxLen ' ') ts
316+
317+
surroundWith c = Text.cons c . flip Text.snoc c
318+
319+
innerMargins = map (surroundWith ' ')
320+
321+
-- insert separator line after the first entry (assumed to be the header in its final width)
322+
separator (h:rs) = h : Text.replicate (Text.length h) "-" : rs
323+
separator [] = []

0 commit comments

Comments
 (0)