mirror of
https://github.com/simonmichael/hledger.git
synced 2024-12-28 04:46:31 +03:00
shake: move changelog scripts to Shake, enhance
New shake targets: ./Shake changelogs ./Shake CHANGES.md ./Shake CHANGES.md-dry ./Shake PKG/CHANGES.md ./Shake PKG/CHANGES.md-dry Enhancements: - removes the changelog's previous top heading - ignores commits like "changelog", "doc: update changelogs".. - does not write temporary files - dry run mode [ci skip]
This commit is contained in:
parent
29c41dc84b
commit
89bb4816c6
@ -1234,22 +1234,10 @@ Project documentation lives in a number of places:
|
|||||||
|
|
||||||
How to prepare changelogs & release notes
|
How to prepare changelogs & release notes
|
||||||
|
|
||||||
Draft:
|
|
||||||
|
|
||||||
- `make changelog-draft >> doc/CHANGES.draft.org` (or `>` if this is the first draft)
|
|
||||||
- open this org file and sort the nodes (`C-c ^ a`)
|
|
||||||
- categorisation pass 1: go through and add topic prefixes where missing
|
|
||||||
- sort the nodes again
|
|
||||||
- categorisation pass 2: move significant items to the appropriate package subnode as appropriate; keep "soft" items that might appear in release notes; delete the rest
|
|
||||||
- cleanup pass: combine/rewrite items for clarity
|
|
||||||
|
|
||||||
Changelogs:
|
Changelogs:
|
||||||
|
|
||||||
- `CHANGES.md` in each package directory, and one in the top directory (project-wide changes, perhaps just for staging)
|
- ./Shake changelogs
|
||||||
- markdown format: - bullets, indented literal blocks
|
- edit the new changelog items (identify, filter, move to correct changelog, deduplicate, rewrite, sort/group)
|
||||||
- there's always a heading at the top whose first word is a release version or (between releases) a commit hash
|
|
||||||
- `make changelogs` to add any new commits to the top of all changelogs
|
|
||||||
- then clean those up manually: identify, filter, move to correct changelog, deduplicate, rewrite, sort/group
|
|
||||||
|
|
||||||
Release notes:
|
Release notes:
|
||||||
|
|
||||||
|
92
Makefile
92
Makefile
@ -1109,98 +1109,6 @@ haddock: \
|
|||||||
# # cd site/api && \
|
# # cd site/api && \
|
||||||
# # hoogle --convert=main.txt --output=default.hoo
|
# # hoogle --convert=main.txt --output=default.hoo
|
||||||
|
|
||||||
#
|
|
||||||
|
|
||||||
# in subsequent rules, allow automatic variables to be used in prerequisites (use $$)
|
|
||||||
.SECONDEXPANSION:
|
|
||||||
|
|
||||||
########################
|
|
||||||
# changelogs
|
|
||||||
|
|
||||||
# -E for extended regular expressions
|
|
||||||
SED=sed -E
|
|
||||||
# GNU sed, when needed. It's gsed eg with homebrew. This test may print an error message
|
|
||||||
GSED=$(notdir $(shell which gsed || which sed)) -E
|
|
||||||
|
|
||||||
# --abbrev-commit for short commit hashes
|
|
||||||
GITLOG=git log --abbrev-commit
|
|
||||||
|
|
||||||
# git exclude pathspecs, https://git-scm.com/docs/gitglossary.html#gitglossary-aiddefpathspecapathspec
|
|
||||||
EXCLUDEPKGDIRS=\
|
|
||||||
':!hledger-lib' \
|
|
||||||
':!hledger' \
|
|
||||||
':!hledger-ui' \
|
|
||||||
':!hledger-web' \
|
|
||||||
':!hledger-api' \
|
|
||||||
':!tests' \
|
|
||||||
|
|
||||||
# XXX would like to include tests/ in hledger changelog
|
|
||||||
|
|
||||||
# git log format suitable for changelogs/release notes
|
|
||||||
# %s=subject, %an=author name, %n=newline if needed, %w=width/indent1/indent2, %b=body, %h=hash
|
|
||||||
CHANGEFMT=--pretty=format:'- %s (%an)%n%w(0,2,2)%b'
|
|
||||||
|
|
||||||
# git log format like the above plus hashes and --stat info
|
|
||||||
VERBOSEFMT=--pretty=format:'- %s (%an)%n%w(0,2,2)%b%h' --stat
|
|
||||||
|
|
||||||
# Format a git log message, with one of the formats above, as a changelog item:
|
|
||||||
# ensure bullet lists in descriptions use hyphens not stars
|
|
||||||
# strip maintainer's author name
|
|
||||||
# strip [ci skip] lines
|
|
||||||
# replace lines containing only spaces with empty lines
|
|
||||||
# strip windows carriage returns (XXX can't edit this with IDEA right now, it rewrites the ^M)
|
|
||||||
# replace consecutive newlines with one
|
|
||||||
CHANGECLEANUP=$(SED) \
|
|
||||||
-e 's/^( )*\* /\1- /' \
|
|
||||||
-e 's/ \(Simon Michael\)//' \
|
|
||||||
-e 's/\[ci skip\]//' \
|
|
||||||
-e 's/^ $$//' \
|
|
||||||
-e 's/
//' \
|
|
||||||
-e '/./,/^$$/!d' \
|
|
||||||
|
|
||||||
#CHANGECLEANUP=cat
|
|
||||||
|
|
||||||
# periodically run this to add new commits to changelogs, then clean up manually
|
|
||||||
changelogs: */CHANGES.md CHANGES.md \
|
|
||||||
$(call def-help,changelogs, update all changelogs with the latest commits )
|
|
||||||
|
|
||||||
# inserts a blank line + heading + new items after line 2.
|
|
||||||
# dry run: put echo before the last $(SED), ls Makefile | entr bash -c 'make hledger/CHANGES.md && cat hledger/CHANGES.md.new'
|
|
||||||
# Needs GNU sed to do the r insertion.
|
|
||||||
%/CHANGES.md: .FORCE \
|
|
||||||
$(call def-help,*/CHANGES.md, add commits to the specified changelog(s) since the tag/commit in the topmost heading )
|
|
||||||
$(eval PKGDIR=$(dir $@))
|
|
||||||
$(eval PKG=$(shell echo $(PKGDIR) | $(SED) -e "s/\///;"))
|
|
||||||
$(eval LAST=$(shell grep -E '^#' $@ | head -1 | cut -d' ' -f2 | $(SED) -e "s/(.*\..*)/$(PKG)-\1/;"))
|
|
||||||
$(eval HEAD=$(shell $(GITLOG) -1 --pretty=%h -- $(PKGDIR)))
|
|
||||||
@( [[ $(HEAD) == $(LAST) ]] \
|
|
||||||
&& echo "$@: up to date" \
|
|
||||||
|| ( \
|
|
||||||
( printf "\n# $(HEAD)\n\n"; \
|
|
||||||
$(GITLOG) $(CHANGEFMT) $(LAST).. -- $(PKGDIR) | $(CHANGECLEANUP) \
|
|
||||||
) >$@.new ; \
|
|
||||||
$(GSED) -i "2r $@.new" $@ ; \
|
|
||||||
echo "$@: added $(LAST)..$(HEAD)" \
|
|
||||||
) \
|
|
||||||
)
|
|
||||||
|
|
||||||
CHANGES.md: .FORCE \
|
|
||||||
$(call def-help,CHANGES.md, add commits to the project-wide changelog since the tag/commit in the topmost heading )
|
|
||||||
$(eval LAST=$(shell grep -E '^#' $@ | head -1 | cut -d' ' -f2 | $(SED) -e "s/(.*\..*)/hledger-\1/;"))
|
|
||||||
$(eval HEAD=$(shell $(GITLOG) -1 --pretty=%h -- . $(EXCLUDEPKGDIRS)))
|
|
||||||
@( [[ $(HEAD) == $(LAST) ]] \
|
|
||||||
&& echo "$@: up to date" \
|
|
||||||
|| ( \
|
|
||||||
( printf "\n# $(HEAD)\n\n"; $(GITLOG) $(CHANGEFMT) $(LAST).. -- . $(EXCLUDEPKGDIRS) | $(CHANGECLEANUP) ) >$@.new ; \
|
|
||||||
$(SED) -i "2r $@.new" $@ ; \
|
|
||||||
echo "$@: added $(LAST)..$(HEAD)" \
|
|
||||||
) \
|
|
||||||
)
|
|
||||||
|
|
||||||
.FORCE:
|
|
||||||
|
|
||||||
#LASTTAG=$(shell git describe --tags --abbrev=0)
|
|
||||||
|
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
$(call def-help-subheading,RELEASING:)
|
$(call def-help-subheading,RELEASING:)
|
||||||
|
98
Shake.hs
98
Shake.hs
@ -39,11 +39,14 @@ multiple individually accessible wildcards
|
|||||||
not having to write :: Action ExitCode after a non-final cmd
|
not having to write :: Action ExitCode after a non-final cmd
|
||||||
-}
|
-}
|
||||||
|
|
||||||
{-# LANGUAGE PackageImports, ScopedTypeVariables #-}
|
{-# LANGUAGE MultiWayIf #-}
|
||||||
|
{-# LANGUAGE PackageImports #-}
|
||||||
|
{-# LANGUAGE ScopedTypeVariables #-}
|
||||||
|
|
||||||
import Prelude ()
|
import Prelude ()
|
||||||
import "base-prelude" BasePrelude
|
import "base-prelude" BasePrelude
|
||||||
-- keep imports synced with Makefile -> SHAKEDEPS
|
import "base" Control.Exception as C
|
||||||
|
-- required packages, keep synced with Makefile -> SHAKEDEPS:
|
||||||
import "directory" System.Directory as S (getDirectoryContents)
|
import "directory" System.Directory as S (getDirectoryContents)
|
||||||
import "extra" Data.List.Extra
|
import "extra" Data.List.Extra
|
||||||
import "process" System.Process
|
import "process" System.Process
|
||||||
@ -63,6 +66,7 @@ usage = unlines
|
|||||||
,"./Shake build # build all hledger packages, with awareness of embedded docs"
|
,"./Shake build # build all hledger packages, with awareness of embedded docs"
|
||||||
,"./Shake all # generate everything"
|
,"./Shake all # generate everything"
|
||||||
,""
|
,""
|
||||||
|
,"./Shake changelogs # update the changelogs with any new commits"
|
||||||
,"./Shake site/doc/VERSION/.snapshot # save the checked-out web manuals as a versioned snapshot"
|
,"./Shake site/doc/VERSION/.snapshot # save the checked-out web manuals as a versioned snapshot"
|
||||||
,"./Shake FILE # build any individual file"
|
,"./Shake FILE # build any individual file"
|
||||||
,"./Shake clean # clean generated files"
|
,"./Shake clean # clean generated files"
|
||||||
@ -124,6 +128,9 @@ main = do
|
|||||||
,"hledger-api"
|
,"hledger-api"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
changelogs = "CHANGES.md" : map (</> "CHANGES.md") packages
|
||||||
|
changelogsdry = map (++"-dry") changelogs
|
||||||
|
|
||||||
-- doc files (or related targets) that should be generated
|
-- doc files (or related targets) that should be generated
|
||||||
-- before building hledger packages.
|
-- before building hledger packages.
|
||||||
-- [(PKG, [TARGETS])]
|
-- [(PKG, [TARGETS])]
|
||||||
@ -375,6 +382,90 @@ main = do
|
|||||||
-- "m4 -P -DHELP -I" commandsdir lib src "|"
|
-- "m4 -P -DHELP -I" commandsdir lib src "|"
|
||||||
pandoc fromsrcmd src "--lua-filter" "tools/pandoc-dedent-code-blocks.lua" "-t plain" ">" out
|
pandoc fromsrcmd src "--lua-filter" "tools/pandoc-dedent-code-blocks.lua" "-t plain" ">" out
|
||||||
|
|
||||||
|
-- CHANGELOGS
|
||||||
|
|
||||||
|
let
|
||||||
|
-- git log showing short commit hashes
|
||||||
|
gitlog = "git log --abbrev-commit"
|
||||||
|
|
||||||
|
-- git log formats suitable for changelogs/release notes
|
||||||
|
-- %s=subject, %an=author name, %n=newline if needed, %w=width/indent1/indent2, %b=body, %h=hash
|
||||||
|
changelogGitFormat = "--pretty=format:'- %s (%an)%n%w(0,2,2)%b'"
|
||||||
|
-- changelogVerboseGitFormat = "--pretty=format:'- %s (%an)%n%w(0,2,2)%b%h' --stat"
|
||||||
|
|
||||||
|
-- Format a git log message, with one of the formats above, as a changelog item
|
||||||
|
changelogCleanupCmd = unwords [
|
||||||
|
"sed -E"
|
||||||
|
,"-e 's/^( )*\\* /\1- /'" -- ensure bullet lists in descriptions use hyphens not stars
|
||||||
|
,"-e 's/ \\(Simon Michael\\)//'" -- strip maintainer's author name
|
||||||
|
,"-e 's/^- (doc: *)?(updated? *)?changelogs?( *updates?)?$//'" -- strip some variants of "updated changelog"
|
||||||
|
,"-e 's/^ +\\[ci skip\\] *$//'" -- strip [ci skip] lines
|
||||||
|
,"-e 's/^ +$//'" -- replace lines containing only spaces with empty lines
|
||||||
|
-- ,"-e 's/\r//'" -- strip windows carriage returns (XXX \r untested. IDEA doesn't like a real ^M here)
|
||||||
|
,"-e '/./,/^$/!d'" -- replace consecutive newlines with one
|
||||||
|
]
|
||||||
|
|
||||||
|
-- Things to exclude when doing git log for project-wide changelog.
|
||||||
|
-- git exclude pathspecs, https://git-scm.com/docs/gitglossary.html#gitglossary-aiddefpathspecapathspec
|
||||||
|
projectChangelogExcludeDirs = unwords [
|
||||||
|
":!hledger-lib"
|
||||||
|
,":!hledger"
|
||||||
|
,":!hledger-ui"
|
||||||
|
,":!hledger-web"
|
||||||
|
,":!hledger-api"
|
||||||
|
,":!tests"
|
||||||
|
]
|
||||||
|
|
||||||
|
-- update all changelogs with latest commits
|
||||||
|
phony "changelogs" $ need changelogs
|
||||||
|
|
||||||
|
-- show the changelogs updates that would be written
|
||||||
|
-- phony "changelogs-dry" $ need changelogsdry
|
||||||
|
|
||||||
|
-- CHANGES.md */CHANGES.md CHANGES.md-dry */CHANGES.md-dry
|
||||||
|
-- Add commits to the specified changelog since the tag/commit in
|
||||||
|
-- the topmost heading, also removing that previous heading if it
|
||||||
|
-- was an interim heading (a commit hash). Or (the -dry variants)
|
||||||
|
-- just print the new changelog items to stdout without saving.
|
||||||
|
phonys (\out' -> if
|
||||||
|
| not $ out' `elem` (changelogs ++ changelogsdry) -> Nothing
|
||||||
|
| otherwise -> Just $ do
|
||||||
|
let (out, dryrun) | "-dry" `isSuffixOf` out' = (take (length out' - 4) out', True)
|
||||||
|
| otherwise = (out', False)
|
||||||
|
old <- liftIO $ lines <$> readFileStrictly out
|
||||||
|
|
||||||
|
let dir = takeDirectory out
|
||||||
|
pkg | dir=="." = Nothing
|
||||||
|
| otherwise = Just dir
|
||||||
|
gitlogpaths = fromMaybe projectChangelogExcludeDirs pkg
|
||||||
|
isnotheading = not . ("#" `isPrefixOf`)
|
||||||
|
iscommithash s = length s > 6 && all isAlphaNum s
|
||||||
|
(preamble, oldheading:rest) = span isnotheading old
|
||||||
|
lastversion = words oldheading !! 1
|
||||||
|
lastrev | iscommithash lastversion = lastversion
|
||||||
|
| otherwise = fromMaybe "hledger" pkg ++ "-" ++ lastversion
|
||||||
|
|
||||||
|
headrev <- unwords . words . fromStdout <$>
|
||||||
|
(cmd Shell gitlog "-1 --pretty=%h -- " gitlogpaths :: Action (Stdout String))
|
||||||
|
|
||||||
|
if headrev == lastrev
|
||||||
|
then liftIO $ putStrLn $ out ++ ": up to date"
|
||||||
|
else do
|
||||||
|
newitems <- fromStdout <$>
|
||||||
|
(cmd Shell gitlog changelogGitFormat (lastrev++"..") "--" gitlogpaths
|
||||||
|
"|" changelogCleanupCmd :: Action (Stdout String))
|
||||||
|
let newcontent = "# "++headrev++"\n\n" ++ newitems
|
||||||
|
newfile = unlines $ concat [
|
||||||
|
preamble
|
||||||
|
,[newcontent]
|
||||||
|
,if iscommithash lastrev then [] else [oldheading]
|
||||||
|
,rest
|
||||||
|
]
|
||||||
|
liftIO $ if dryrun
|
||||||
|
then putStr newcontent
|
||||||
|
else writeFile out newfile
|
||||||
|
)
|
||||||
|
|
||||||
-- MISC
|
-- MISC
|
||||||
|
|
||||||
-- Generate the web manuals based on the current checkout and save
|
-- Generate the web manuals based on the current checkout and save
|
||||||
@ -425,3 +516,6 @@ manualNameToManpageName s
|
|||||||
|
|
||||||
dropDirectory2 = dropDirectory1 . dropDirectory1
|
dropDirectory2 = dropDirectory1 . dropDirectory1
|
||||||
|
|
||||||
|
readFileStrictly :: FilePath -> IO String
|
||||||
|
readFileStrictly f = readFile f >>= \s -> C.evaluate (length s) >> return s
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user