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. It sets version: and appVersion: in all of
the Chart.yaml files, moves the default images in values.yaml to the
new release, and sets BASE_VERSION in the Makefile and
base_version in zuul.d/project.yaml. That commit is then tagged with
the new version, as 2026.1.0 tags the commit that introduced it.
The bump is published like any other commit. Each chart’s first version in the new series carries only the notes of its own window, usually just the bump commit’s. The history before it is not repeated: it is already in the versions published earlier.
The tag can only be pushed once the bump commit has merged, so the first
publish happens without it. The version is the same either way, because the
patch number is 0 with or without the tag. The tag matters from the next
commit onward, when it starts the patch count for the series.
Push the tag after the publish job for the bump commit has finished. A build at the tagged commit itself finds no commits since the tag and writes no annotation, so if that publish failed and ran again after tagging, the first version of the series would ship without its notes.
To see what a chart’s first version of the series would carry:
python3 tools/chart_annotations.py --charts neutron \
--base-version 2026.2.0 --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.