Generate CHANGELOG.md for charts

We use reno>=4.1.0 features to combine release notes from
a bunch of release notes files. Reno uses git tags
to figure out which release notes files to include
to a given release.

When building charts for deployment tests we skip
generating CHANGELOG.md files.

Change-Id: I2f55e76844afa05139a5c4b63ecb6c0ae2bcb5b2
This commit is contained in:
Vladimir Kozhukalov 2025-01-30 13:38:12 -06:00
parent eb60e37c55
commit 7a403d5db2
4 changed files with 196 additions and 4 deletions

View File

@ -14,6 +14,12 @@
SHELL := /bin/bash
HELM := helm
TASK := build
PYTHON := python3
# We generate CHANGELOG.md files by default which
# requires reno>=4.1.0 installed.
# To skip generating it use the following:
# make all SKIP_CHANGELOG=1
SKIP_CHANGELOG ?= 0
PKG_ARGS =
ifdef VERSION
@ -45,7 +51,11 @@ init-%:
lint-%: init-%
if [ -d $* ]; then $(HELM) lint $*; fi
build-%: lint-%
# reno required for changelog generation
%/CHANGELOG.md:
if [ -d $* ]; then $(PYTHON) tools/changelog.py --charts $*; fi
build-%: lint-% $(if $(filter-out 1,$(SKIP_CHANGELOG)),%/CHANGELOG.md)
if [ -d $* ]; then \
$(HELM) package $* --version $$(tools/chart_version.sh $* $(BASE_VERSION)) $(PKG_ARGS); \
fi

View File

@ -62,7 +62,57 @@ sections:
- [fixes, Bug Fixes]
template: |
---
# To create a new release note related to a specific chart:
# reno new <chart_name>
#
# To create a new release note for a common change (when multiple charts
# are changed):
# reno new common
<chart_name>:
- Short change description
- |
Describe changes here, or remove this section. This paragraph will appear in
the unnamed section of the <chart_name>/CHANGELOG.md for a given version.
features:
- |
List new features here, or remove this section. If this section is given
in the releasenotes/notes/<chart_name>-<sha>.yaml it will only appear in the
"New Features" section of the <chart_name>/CHANGELOG.md. If this section is
given in the releasenotes/notes/common-<sha>.yaml it will appear in the
CHANGELOG.md files of all charts.
issues:
- |
List known issues here, or remove this section. If this section is given
in the releasenotes/notes/<chart_name>-<sha>.yaml it will only appear in the
"Known Issues" section of the <chart_name>/CHANGELOG.md. If this section is
given in the releasenotes/notes/common-<sha>.yaml it will appear in the
CHANGELOG.md files of all charts.
upgrade:
- |
List upgrade notes here, or remove this section. If this section is given
in the releasenotes/notes/<chart_name>-<sha>.yaml it will only appear in the
"Upgrade Notes" section of the <chart_name>/CHANGELOG.md. If this section is
given in the releasenotes/notes/common-<sha>.yaml it will appear in the
CHANGELOG.md files of all charts.
api:
- |
List API changes here (e.g. values format), or remove this section. If this section is given
in the releasenotes/notes/<chart_name>-<sha>.yaml it will only appear in the
"API Changes" section of the <chart_name>/CHANGELOG.md. If this section is
given in the releasenotes/notes/common-<sha>.yaml it will appear in the
CHANGELOG.md files of all charts.
security:
- |
List security issues here, or remove this section. If this section is given
in the releasenotes/notes/<chart_name>-<sha>.yaml it will only appear in the
"Security Issues" section of the <chart_name>/CHANGELOG.md. If this section is
given in the releasenotes/notes/common-<sha>.yaml it will appear in the
CHANGELOG.md files of all charts.
fixes:
- |
List bug fixes here, or remove this section. If this section is given
in the releasenotes/notes/<chart_name>-<sha>.yaml it will only appear in the
"Bug Fixes" section of the <chart_name>/CHANGELOG.md. If this section is
given in the releasenotes/notes/common-<sha>.yaml it will appear in the
CHANGELOG.md files of all charts.
...
...

132
tools/changelog.py Normal file
View File

@ -0,0 +1,132 @@
import argparse
import os.path
from collections import defaultdict
from reno import config
from reno import loader
BEFORE_2024_2_0_NOTE = """Before 2024.2.0 all the OpenStack-Helm charts were versioned independently.
Here we provide all the release notes for the chart for all versions before 2024.2.0.
"""
def _indent_for_list(text, prefix=' '):
lines = text.splitlines()
return '\n'.join([lines[0]] + [
prefix + l
for l in lines[1:]
])
def chart_reports(loader, config, versions_to_include, title=None, charts=None):
reports = defaultdict(list)
file_contents = {}
for version in versions_to_include:
for filename, sha in loader[version]:
body = loader.parse_note_file(filename, sha)
file_contents[filename] = body
for chart in charts:
if title:
reports[chart].append(f"# {title}")
reports[chart].append('')
for version in versions_to_include:
if '-' in version:
version_title = config.unreleased_version_title or version
else:
version_title = version
reports[chart].append(f"## {version_title}")
reports[chart].append('')
if version == "2024.2.0":
reports[chart].append(BEFORE_2024_2_0_NOTE)
if config.add_release_date:
reports[chart].append('Release Date: ' + loader.get_version_date(version))
reports[chart].append('')
notefiles = loader[version]
# Prepare not named section
# 1. Get all files named <chart>*.yaml
# and get <chart> section from all these files
# 2. Get all files named common*.yaml and get <chart>
# section from all these files
is_content = False
for fn, sha in notefiles:
if os.path.basename(fn).startswith(chart) or \
os.path.basename(fn).startswith("common"):
notes = file_contents[fn].get(chart, [])
for n in notes:
is_content = True
reports[chart].append(f"- {_indent_for_list(n)}")
# Add new line after unnamed section if it is not empty
if is_content:
reports[chart].append("")
# Prepare named sections
# 1. Get all files named <chart>*.yaml
# and get all sections from all these files except <chart>
# 2. Get all files named common*.yaml
# and get all sections from all these files except <chart>
for section in config.sections:
is_content = False
# Skip chart specific sections
if section.name not in ["features", "isseus", "upgrade", "api", "security", "fixes"]:
continue
for fn, sha in notefiles:
if os.path.basename(fn).startswith(chart) or \
os.path.basename(fn).startswith("common"):
notes = file_contents[fn].get(section.name, [])
if notes and not is_content:
reports[chart].append(f"### {section.title}")
reports[chart].append("")
if notes:
is_content = True
for n in notes:
reports[chart].append(f"- {_indent_for_list(n)}")
# Add new line after the section if it is not empty
if is_content:
reports[chart].append("")
report = reports[chart]
reports[chart] = '\n'.join(report)
return reports
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--charts", nargs="+", default=[], help="Charts to generate release notes for")
args = parser.parse_args()
conf = config.Config(".", "releasenotes")
with loader.Loader(conf) as ldr:
versions = ldr.versions
reports = chart_reports(
ldr,
conf,
versions,
title="Release notes",
charts=args.charts,
)
for chart in reports:
with open(f"{chart}/CHANGELOG.md", "w") as f:
f.write(reports[chart])
return
if __name__ == "__main__":
main()

View File

@ -14,10 +14,10 @@
set -ex
# Build all OSH charts
make all
make all SKIP_CHANGELOG=1
# Build all OSH charts (necessary for Openstack deployment)
(
cd ${OSH_PATH:-"../openstack-helm"} &&
make all
make all SKIP_CHANGELOG=1
)