Release Notes¶
Release notes for charts are written as git trailers in the commit that makes
the change. At build time they are collected into the
artifacthub.io/changes annotation of the chart’s Chart.yaml, which
Artifact Hub turns
into a changelog spanning every published version of the chart.
Nothing is generated into the git tree: the annotation is written into
Chart.yaml only for as long as it takes helm package to run, and the
file is restored afterwards.
Writing a release note¶
Add a Changelog: trailer to the last paragraph of the commit message, next
to Change-Id:
neutron: fix the health probe for the OVN agent
health-probe.py picks its check from the configuration file name it is
given, and the ovn-agent daemonset passes ovn_agent.ini, which matched
neither sriov_agent.ini nor metadata_agent.ini.
Changelog: fixed
Change-Id: I7d940919531125e2806b18fcb6cfe245d6b31450
The trailer takes one of the change kinds Artifact Hub understands:
Kind |
Use for |
|---|---|
|
New functionality, new values, new templates. |
|
Behaviour changes, upgrade notes, changes to the values schema. |
|
Functionality still present but on its way out. |
|
Functionality that is gone. |
|
Bug fixes. |
|
Fixes for security issues. |
|
Not a kind: states that the commit deliberately needs no release note. |
Without a description the commit subject becomes the release note. Give a description when the subject is not what a deployer needs to read:
Changelog: fixed: Restart the DHCP agent cleanly when its configuration changes
Repeat the trailer to attach several notes to one commit:
Changelog: added: The probes can now be tuned under pod.probes
Changelog: fixed: The OVN agent is probed through its metadata socket
Conventional Commits subjects¶
A subject written in the Conventional Commits style already names the kind of change, so a commit written that way needs no trailer to repeat it:
fix(nova): Bla-bla-bla
produces a fixed note reading Bla-bla-bla. The type and scope are not
part of the note: the annotation carries the kind in its own field, and the
charts come from the diff, so repeating either in the description would only
make it read worse.
Type |
Kind |
|---|---|
|
|
|
|
|
|
any type with a |
|
|
no note, and no trailer needed |
Only those types count. This repository also writes neutron: fix the
probe, which has the same shape, and a chart name is not a change kind, so
subjects like that still need a trailer.
A Changelog: trailer always wins over the subject, which is how a
conventional commit says something other than its subject, splits itself into
several notes, or opts out with Changelog: skip.
A reno note wins over both¶
A commit that adds a file under releasenotes/notes has already written
its release note, so that note is used and the commit message is not consulted
for the charts it reaches. Without this a change carrying both would be
announced twice, once in the note’s words and once in the subject’s, and the
subject is usually the poorer of the two.
Such a commit also needs no Changelog: trailer: adding the note is the
declaration. This is transitional. Reno notes are frozen and will be
forbidden outright once the changes already in review have merged, after
which the commit message is the only place a release note is written.
Which charts a note reaches¶
By default a note goes to the charts whose directories the commit touches. A
commit that only changes roles, playbooks, tools, zuul.d or
doc touches no chart and therefore produces no release note at all, which
is why such a commit needs no Changelog: trailer.
Use a Charts: trailer when the default is wrong:
Charts: barbican, keystone
Charts: all
Charts: none
all fans the note out to every chart, which is what a change affecting all
of them should use. none suppresses routing entirely. Note that changing
helm-toolkit infers helm-toolkit alone: if the change is visible to the
charts that depend on it, say so with Charts: all.
A commit that changes a chart must either carry a Changelog: trailer or opt
out explicitly:
Changelog: skip
Use skip for changes with nothing to tell a deployer: whitespace, comments,
test-only changes, or a fix to an unreleased change earlier in the same series.
Checking before you push¶
The openstack-helm-release-notes job validates the trailers of every
change. Run the same check locally against the commit you are about to push:
python3 tools/check_commit_message.py
To see the annotation a chart would ship:
python3 tools/chart_annotations.py --charts neutron \
--base-version 2026.1.0 --dry-run
Common failures are a Changelog: line written in the middle of the message
rather than in the trailer block, where git does not recognise it, and a
Changelog: trailer on a commit that touches no chart directory and names
none with Charts:, where the note would reach nothing.
A commit that changes a chart passes when it carries a Changelog: trailer,
a Conventional Commits subject, or a reno note. A subject in this
repository’s other style, neutron: fix the probe, names no kind, so a
commit with that subject and no note still needs a trailer.
Which notes end up in which version¶
A chart’s version counts the commits that touched it, and the commits that
touched helm-toolkit when it depends on it, since helm-toolkit is vendored
into the tarball. A version is bounded by two of those commits: the newest is
the version’s own, and the one before it produced the previous version.
Consecutive versions therefore partition the history, and since a reader
assembles a chart’s changelog from the versions in the index, each note
appears exactly once.
The boundaries are taken along the branch’s first parent. Gerrit merges each change from its own branch, so the commits which touched a chart are not all on that line, and a git range is resolved by ancestry rather than by date. A boundary taken from a side branch therefore reaches back past every change merged from a different one, and the windows of two consecutive versions overlap. Taking the merge instead keeps them apart. This also means the end of a window is usually the merge rather than the change itself, so it need not be the sha that appears in the version; the two name the same change.
A note routed to a chart the commit did not touch, through Charts: all for
instance, does not bump that chart’s version. It is carried by the next
version of the chart, the first one that can hold it.
At the series bump¶
Chart versions are raised once per OpenStack release, for every chart at
once, by a single commit that sets version: in all of the Chart.yaml
files and BASE_VERSION in the Makefile. That commit is then tagged
with the new version, as 2026.1.0 tags the commit that introduced it.
Because every chart’s version changes in that one commit, every chart is republished from it, and that is the only moment at which the whole history can be attached to a version. The same commit therefore also sets:
chart_full_annotations: 1
in the vars of zuul.d/project.yaml. The publish job passes it through
to make as FULL_ANNOTATIONS, and each chart’s first version in the new
series carries every release note it has ever had, the frozen reno notes
included, rather than only the notes of that version. A follow-up commit sets
it back to 0 so that later versions carry only their own notes again.
The full render does not depend on the tag, so it is correct on the publish run that follows the bump commit even though the tag can only be pushed once that commit has merged. The tag matters from the next commit onward, when it starts the patch count for the series.
To see what a chart would ship before committing to any of this:
python3 tools/chart_annotations.py --charts neutron \
--base-version 2026.2.0 --full --dry-run
Legacy reno notes¶
Release notes used to be written as reno note files under
releasenotes/notes. Those files are frozen but still read: a note is
attributed to the commit that added it and routed to charts by its file name,
so it appears in the same version it always would have. Their sections map
onto the Artifact Hub kinds as follows.
reno section |
Artifact Hub kind |
Notes |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
Artifact Hub has no upgrade kind. |
|
|
|
|
|
Artifact Hub has no known-issues kind. |
|
|
A section named after a chart. |
A note file belongs to the chart whose name is the longest chart name its file
name starts with, so mariadb-backup-<hash>.yaml belongs to mariadb-backup
rather than to mariadb. A common-<hash>.yaml note reaches every chart, and
a section named after a chart reaches that chart whatever the file is called.
Notes were not always written one file per change. Before 2024.2.0 each chart
had a single file named after it, releasenotes/notes/<chart>.yaml, holding
every version that chart had ever had, oldest first:
neutron:
- 0.1.0 Initial Chart
- 0.1.1 Change helm-toolkit dependency version to ">= 0.1.0"
Seventy-five of those remain. They are a changelog in their own right and run
the opposite way round to the annotation, which is newest first, so their
entries are reversed when they are rendered: 0.3.50 appears above
0.1.0. A note file with a hash in its name describes one change and its
items have no chronology, so those keep the order they were written in.
There is no way to write a new reno note, because reno is gone. The
releasenotes tox environment, the release notes site it built from
releasenotes/source, releasenotes/config.yaml and the reno requirement
were all removed along with tools/changelog.py; releasenotes/notes is
all that is left under that directory, and the chart build is the only thing
that reads it. Charts no longer carry a CHANGELOG.md either: the
annotation is the only release note metadata a chart ships.