Add scripts/gen-changelog.py, which builds the changelog page from the
git log for releases after 9.0.3 (older history stays in the historical
changelog). "make website" regenerates it before the Sphinx build, and
"make doc" creates a placeholder so the documentation still builds
without it.
The website workflow now checks out the full history so the tags and log
are available.
Signed-off-by: Rui Yang <yangrr.2009(a)tsinghua.org.cn>
---
.github/workflows/website.yml | 8 ++++
.gitignore | 1 +
Makefile | 1 +
doc/Makefile | 9 ++--
doc/index.rst | 1 +
scripts/gen-changelog.py | 82 +++++++++++++++++++++++++++++++++++
6 files changed, 99 insertions(+), 3 deletions(-)
create mode 100644 scripts/gen-changelog.py
diff --git a/.github/workflows/website.yml b/.github/workflows/website.yml
index 31be1d414713..a67c85d02f64 100644
--- a/.github/workflows/website.yml
+++ b/.github/workflows/website.yml
@@ -31,6 +31,14 @@ jobs:
timeout-minutes: 90
steps:
- uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+ fetch-tags: true
+
+ - name: Fetch release tags
+ run: |
+ git remote add upstream
https://github.com/crash-utility/crash.git
2>/dev/null || true
+ git fetch --tags upstream
- name: Install build and documentation dependencies
run: |
diff --git a/.gitignore b/.gitignore
index 1f6cd8212d5e..265c829a3059 100644
--- a/.gitignore
+++ b/.gitignore
@@ -32,3 +32,4 @@ TAGS
/_site/
/doc/help/
+/doc/changelog.rst
diff --git a/Makefile b/Makefile
index 11dcde08f0ef..114bd59bd39d 100644
--- a/Makefile
+++ b/Makefile
@@ -860,6 +860,7 @@ SITE_DIR=_site
website: ${PROGRAM}
rm -rf ${SITE_DIR}
python3 scripts/gen-help-rst.py --crash $(abspath ${PROGRAM}) --out $(abspath doc/help)
+ python3 scripts/gen-changelog.py --repo . --out $(abspath doc/changelog.rst)
$(MAKE) -C doc website WEBSITE_DIR=$(abspath ${SITE_DIR})
@echo "Site generated in ${SITE_DIR}"
diff --git a/doc/Makefile b/doc/Makefile
index bf9568f073fd..c02a66b052fe 100644
--- a/doc/Makefile
+++ b/doc/Makefile
@@ -24,12 +24,15 @@ help/index.rst:
@mkdir -p help
@printf 'Crash command help\n==================\n\nThe command help pages are
generated from the crash binary when the\ndocumentation website is built.\n' > $@
-html htmldocs: help/index.rst
+changelog.rst:
+ @printf 'Crash changelog\n===============\n\nThe changelog is generated from the git
log when the documentation\nwebsite is built.\n' > $@
+
+html htmldocs: help/index.rst changelog.rst
$(SPHINXBUILD) -b html $(SPHINXOPTS) $(SOURCEDIR) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
-website: help/index.rst
+website: help/index.rst changelog.rst
$(SPHINXBUILD) -b html -d $(BUILDDIR)/doctrees $(SPHINXOPTS) $(SOURCEDIR)
$(WEBSITE_DIR)
@echo
@echo "Build finished. The HTML pages are in $(WEBSITE_DIR)."
@@ -42,4 +45,4 @@ pdf latexpdf: latex
@echo "Build finished. The PDF is in $(BUILDDIR)/latex."
clean cleandocs:
- rm -rf $(BUILDDIR) help
+ rm -rf $(BUILDDIR) help changelog.rst
diff --git a/doc/index.rst b/doc/index.rst
index 39cc55a0c25d..02112644b543 100644
--- a/doc/index.rst
+++ b/doc/index.rst
@@ -16,4 +16,5 @@ produced a core dump (a *dumpfile*).
help/index
extensions
whitepaper
+ changelog
links
diff --git a/scripts/gen-changelog.py b/scripts/gen-changelog.py
new file mode 100644
index 000000000000..c0dd15c60563
--- /dev/null
+++ b/scripts/gen-changelog.py
@@ -0,0 +1,82 @@
+#!/usr/bin/env python3
+"""Generate the crash changelog from the git log.
+
+Each tagged release gets a section with the commits since the previous
+tag, followed by the unreleased changes.
+
+Usage:
+ scripts/gen-changelog.py --repo . --out doc/changelog.rst
+"""
+import argparse
+import os
+import re
+import subprocess
+import sys
+
+
+def git(repo, *args):
+ result = subprocess.run(["git"] + list(args), cwd=repo,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ if result.returncode != 0:
+ sys.stderr.write(result.stderr.decode("utf-8", "replace"))
+ raise SystemExit("failed to run: git %s" % " ".join(args))
+ return result.stdout.decode("utf-8", "replace")
+
+
+def esc(text):
+ text = text.replace("\\", "\\\\")
+ return re.sub(r"([*`|_])", r"\\\1", text)
+
+
+def version(tag):
+ match = re.search(r"(\d+)\.(\d+)\.(\d+)", tag)
+ return tuple(int(x) for x in match.groups()) if match else (0, 0, 0)
+
+
+def entries(repo, rev):
+ out = git(repo, "log", "--no-merges", "--date=short",
+ "--pretty=format:%ad %an %s", rev)
+ return [line for line in out.splitlines() if line.strip()]
+
+
+def section(title, lines, out):
+ out.append(title)
+ out.append("-" * len(title))
+ out.append("")
+ for line in lines:
+ out.append("* " + esc(line))
+ out.append("")
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument("--repo", default=".", help="crash git
repository")
+ parser.add_argument("--out", required=True, help="output RST
file")
+ args = parser.parse_args()
+
+ repo = os.path.abspath(args.repo)
+ tags = git(repo, "tag", "--sort=creatordate").split()
+ tags = [tag for tag in tags if version(tag) > (0, 0, 0)]
+
+ parts = []
+ if tags:
+ section("unreleased", entries(repo, "%s..HEAD" % tags[-1]),
parts)
+ for i in range(len(tags) - 1, -1, -1):
+ tag = tags[i]
+ rev = tag if i == 0 else "%s..%s" % (tags[i - 1], tag)
+ section(tag, entries(repo, rev), parts)
+
+ header = [
+ "Crash changelog",
+ "=" * len("Crash changelog"),
+ "",
+ ]
+ text = "\n".join(header + parts).rstrip() + "\n"
+ with open(args.out, "w", encoding="utf-8") as f:
+ f.write(text)
+ count = len(tags) + 1 if tags else 0
+ print("generated %s (%d releases)" % (args.out, count))
+
+
+if __name__ == "__main__":
+ main()