Allow users to change prelude section name
Convert note template to a format string. Also include prelude section in the report generated and update docs. Closes-Bug: #1698203 Change-Id: I7bef68bfb518dd8554d56cb200f2844e7d395fc8
This commit is contained in:
parent
b2aadef726
commit
4003fc1321
|
@ -56,8 +56,8 @@ list:
|
||||||
|
|
||||||
prelude
|
prelude
|
||||||
|
|
||||||
General comments about the release. The prelude from all notes in a
|
General comments about the release. Prelude sections from all notes in a
|
||||||
section are combined, in note order, to produce a single prelude
|
release are combined, in note order, to produce a single prelude
|
||||||
introducing that release. This section is always included, regardless
|
introducing that release. This section is always included, regardless
|
||||||
of what sections are configured.
|
of what sections are configured.
|
||||||
|
|
||||||
|
@ -197,6 +197,9 @@ may be the most convenient way to manage the values consistently.
|
||||||
- [api, API Changes]
|
- [api, API Changes]
|
||||||
- [security, Security Issues]
|
- [security, Security Issues]
|
||||||
- [fixes, Bug Fixes]
|
- [fixes, Bug Fixes]
|
||||||
|
# Change prelude_section_name to 'release_summary' from default value
|
||||||
|
# 'prelude'.
|
||||||
|
prelude_section_name: release_summary
|
||||||
template: |
|
template: |
|
||||||
<template-used-to-create-new-notes>
|
<template-used-to-create-new-notes>
|
||||||
...
|
...
|
||||||
|
@ -284,6 +287,15 @@ The following options are configurable:
|
||||||
order in which the final report will be generated. A prelude section will
|
order in which the final report will be generated. A prelude section will
|
||||||
always be automatically inserted before the first element of this list.
|
always be automatically inserted before the first element of this list.
|
||||||
|
|
||||||
|
`prelude_section_name`
|
||||||
|
|
||||||
|
The name of the prelude section in the note template. Note that the
|
||||||
|
value for this must be a single word, but can have underscores. The
|
||||||
|
value is displayed in titlecase in the report after replacing
|
||||||
|
underscores with spaces.
|
||||||
|
|
||||||
|
Defaults to ``prelude``
|
||||||
|
|
||||||
`ignore_null_merges`
|
`ignore_null_merges`
|
||||||
|
|
||||||
OpenStack used to use null-merges to bring final release tags from
|
OpenStack used to use null-merges to bring final release tags from
|
||||||
|
|
|
@ -19,74 +19,6 @@ from reno import defaults
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
_TEMPLATE = """\
|
|
||||||
---
|
|
||||||
prelude: >
|
|
||||||
Replace this text with content to appear at the top of the section for this
|
|
||||||
release. All of the prelude content is merged together and then rendered
|
|
||||||
separately from the items listed in other parts of the file, so the text
|
|
||||||
needs to be worded so that both the prelude and the other items make sense
|
|
||||||
when read independently. This may mean repeating some details. Not every
|
|
||||||
release note requires a prelude. Usually only notes describing major
|
|
||||||
features or adding release theme details should have a prelude.
|
|
||||||
features:
|
|
||||||
- |
|
|
||||||
List new features here, or remove this section. All of the list items in
|
|
||||||
this section are combined when the release notes are rendered, so the text
|
|
||||||
needs to be worded so that it does not depend on any information only
|
|
||||||
available in another section, such as the prelude. This may mean repeating
|
|
||||||
some details.
|
|
||||||
issues:
|
|
||||||
- |
|
|
||||||
List known issues here, or remove this section. All of the list items in
|
|
||||||
this section are combined when the release notes are rendered, so the text
|
|
||||||
needs to be worded so that it does not depend on any information only
|
|
||||||
available in another section, such as the prelude. This may mean repeating
|
|
||||||
some details.
|
|
||||||
upgrade:
|
|
||||||
- |
|
|
||||||
List upgrade notes here, or remove this section. All of the list items in
|
|
||||||
this section are combined when the release notes are rendered, so the text
|
|
||||||
needs to be worded so that it does not depend on any information only
|
|
||||||
available in another section, such as the prelude. This may mean repeating
|
|
||||||
some details.
|
|
||||||
deprecations:
|
|
||||||
- |
|
|
||||||
List deprecations notes here, or remove this section. All of the list
|
|
||||||
items in this section are combined when the release notes are rendered, so
|
|
||||||
the text needs to be worded so that it does not depend on any information
|
|
||||||
only available in another section, such as the prelude. This may mean
|
|
||||||
repeating some details.
|
|
||||||
critical:
|
|
||||||
- |
|
|
||||||
Add critical notes here, or remove this section. All of the list items in
|
|
||||||
this section are combined when the release notes are rendered, so the text
|
|
||||||
needs to be worded so that it does not depend on any information only
|
|
||||||
available in another section, such as the prelude. This may mean repeating
|
|
||||||
some details.
|
|
||||||
security:
|
|
||||||
- |
|
|
||||||
Add security notes here, or remove this section. All of the list items in
|
|
||||||
this section are combined when the release notes are rendered, so the text
|
|
||||||
needs to be worded so that it does not depend on any information only
|
|
||||||
available in another section, such as the prelude. This may mean repeating
|
|
||||||
some details.
|
|
||||||
fixes:
|
|
||||||
- |
|
|
||||||
Add normal bug fixes here, or remove this section. All of the list items
|
|
||||||
in this section are combined when the release notes are rendered, so the
|
|
||||||
text needs to be worded so that it does not depend on any information only
|
|
||||||
available in another section, such as the prelude. This may mean repeating
|
|
||||||
some details.
|
|
||||||
other:
|
|
||||||
- |
|
|
||||||
Add other notes here, or remove this section. All of the list items in
|
|
||||||
this section are combined when the release notes are rendered, so the text
|
|
||||||
needs to be worded so that it does not depend on any information only
|
|
||||||
available in another section, such as the prelude. This may mean repeating
|
|
||||||
some details.
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
class Config(object):
|
class Config(object):
|
||||||
|
|
||||||
|
@ -115,7 +47,7 @@ class Config(object):
|
||||||
'earliest_version': None,
|
'earliest_version': None,
|
||||||
|
|
||||||
# The template used by reno new to create a note.
|
# The template used by reno new to create a note.
|
||||||
'template': _TEMPLATE,
|
'template': defaults.TEMPLATE.format(defaults.PRELUDE_SECTION_NAME),
|
||||||
|
|
||||||
# The RE pattern used to match the repo tags representing a valid
|
# The RE pattern used to match the repo tags representing a valid
|
||||||
# release version. The pattern is compiled with the verbose and unicode
|
# release version. The pattern is compiled with the verbose and unicode
|
||||||
|
@ -156,6 +88,13 @@ class Config(object):
|
||||||
['other', 'Other Notes'],
|
['other', 'Other Notes'],
|
||||||
],
|
],
|
||||||
|
|
||||||
|
# The name of the prelude section in the note template. This
|
||||||
|
# allows users to rename the section to, for example,
|
||||||
|
# 'release_summary' or 'project_wide_general_announcements',
|
||||||
|
# which is displayed in titlecase in the report after
|
||||||
|
# replacing underscores with spaces.
|
||||||
|
'prelude_section_name': defaults.PRELUDE_SECTION_NAME,
|
||||||
|
|
||||||
# When this option is set to True, any merge commits with no
|
# When this option is set to True, any merge commits with no
|
||||||
# changes and in which the second or later parent is tagged
|
# changes and in which the second or later parent is tagged
|
||||||
# are considered "null-merges" that bring the tag information
|
# are considered "null-merges" that bring the tag information
|
||||||
|
@ -219,6 +158,13 @@ class Config(object):
|
||||||
else:
|
else:
|
||||||
self.override(**self._contents)
|
self.override(**self._contents)
|
||||||
|
|
||||||
|
def _rename_prelude_section(self, **kwargs):
|
||||||
|
key = 'prelude_section_name'
|
||||||
|
if key in kwargs and kwargs[key] != self._OPTS[key]:
|
||||||
|
new_prelude_name = kwargs[key]
|
||||||
|
|
||||||
|
self.template = defaults.TEMPLATE.format(new_prelude_name)
|
||||||
|
|
||||||
def override(self, **kwds):
|
def override(self, **kwds):
|
||||||
"""Set the values of the named configuration options.
|
"""Set the values of the named configuration options.
|
||||||
|
|
||||||
|
@ -227,6 +173,9 @@ class Config(object):
|
||||||
present.
|
present.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
# Replace prelude section name if it has been changed.
|
||||||
|
self._rename_prelude_section(**kwds)
|
||||||
|
|
||||||
for n, v in kwds.items():
|
for n, v in kwds.items():
|
||||||
if n not in self._OPTS:
|
if n not in self._OPTS:
|
||||||
LOG.warning('ignoring unknown configuration value %r = %r',
|
LOG.warning('ignoring unknown configuration value %r = %r',
|
||||||
|
@ -268,6 +217,15 @@ class Config(object):
|
||||||
"""
|
"""
|
||||||
return os.path.join(self.relnotesdir, self.notesdir)
|
return os.path.join(self.relnotesdir, self.notesdir)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def options(self):
|
||||||
|
"""Get all configuration options as a dict.
|
||||||
|
|
||||||
|
Returns the actual configuration options after overrides.
|
||||||
|
"""
|
||||||
|
options = {o: getattr(self, o) for o in self._OPTS}
|
||||||
|
return options
|
||||||
|
|
||||||
# def parse_config_into(parsed_arguments):
|
# def parse_config_into(parsed_arguments):
|
||||||
|
|
||||||
# """Parse the user config onto the namespace arguments.
|
# """Parse the user config onto the namespace arguments.
|
||||||
|
|
|
@ -12,3 +12,72 @@
|
||||||
|
|
||||||
RELEASE_NOTES_SUBDIR = 'releasenotes'
|
RELEASE_NOTES_SUBDIR = 'releasenotes'
|
||||||
NOTES_SUBDIR = 'notes'
|
NOTES_SUBDIR = 'notes'
|
||||||
|
PRELUDE_SECTION_NAME = 'prelude'
|
||||||
|
# This is a format string, so it needs to be formatted wherever it is used.
|
||||||
|
TEMPLATE = """\
|
||||||
|
---
|
||||||
|
{0}: >
|
||||||
|
Replace this text with content to appear at the top of the section for this
|
||||||
|
release. All of the prelude content is merged together and then rendered
|
||||||
|
separately from the items listed in other parts of the file, so the text
|
||||||
|
needs to be worded so that both the prelude and the other items make sense
|
||||||
|
when read independently. This may mean repeating some details. Not every
|
||||||
|
release note requires a prelude. Usually only notes describing major
|
||||||
|
features or adding release theme details should have a prelude.
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
List new features here, or remove this section. All of the list items in
|
||||||
|
this section are combined when the release notes are rendered, so the text
|
||||||
|
needs to be worded so that it does not depend on any information only
|
||||||
|
available in another section, such as the prelude. This may mean repeating
|
||||||
|
some details.
|
||||||
|
issues:
|
||||||
|
- |
|
||||||
|
List known issues here, or remove this section. All of the list items in
|
||||||
|
this section are combined when the release notes are rendered, so the text
|
||||||
|
needs to be worded so that it does not depend on any information only
|
||||||
|
available in another section, such as the prelude. This may mean repeating
|
||||||
|
some details.
|
||||||
|
upgrade:
|
||||||
|
- |
|
||||||
|
List upgrade notes here, or remove this section. All of the list items in
|
||||||
|
this section are combined when the release notes are rendered, so the text
|
||||||
|
needs to be worded so that it does not depend on any information only
|
||||||
|
available in another section, such as the prelude. This may mean repeating
|
||||||
|
some details.
|
||||||
|
deprecations:
|
||||||
|
- |
|
||||||
|
List deprecations notes here, or remove this section. All of the list
|
||||||
|
items in this section are combined when the release notes are rendered, so
|
||||||
|
the text needs to be worded so that it does not depend on any information
|
||||||
|
only available in another section, such as the prelude. This may mean
|
||||||
|
repeating some details.
|
||||||
|
critical:
|
||||||
|
- |
|
||||||
|
Add critical notes here, or remove this section. All of the list items in
|
||||||
|
this section are combined when the release notes are rendered, so the text
|
||||||
|
needs to be worded so that it does not depend on any information only
|
||||||
|
available in another section, such as the prelude. This may mean repeating
|
||||||
|
some details.
|
||||||
|
security:
|
||||||
|
- |
|
||||||
|
Add security notes here, or remove this section. All of the list items in
|
||||||
|
this section are combined when the release notes are rendered, so the text
|
||||||
|
needs to be worded so that it does not depend on any information only
|
||||||
|
available in another section, such as the prelude. This may mean repeating
|
||||||
|
some details.
|
||||||
|
fixes:
|
||||||
|
- |
|
||||||
|
Add normal bug fixes here, or remove this section. All of the list items
|
||||||
|
in this section are combined when the release notes are rendered, so the
|
||||||
|
text needs to be worded so that it does not depend on any information only
|
||||||
|
available in another section, such as the prelude. This may mean repeating
|
||||||
|
some details.
|
||||||
|
other:
|
||||||
|
- |
|
||||||
|
Add other notes here, or remove this section. All of the list items in
|
||||||
|
this section are combined when the release notes are rendered, so the text
|
||||||
|
needs to be worded so that it does not depend on any information only
|
||||||
|
available in another section, such as the prelude. This may mean repeating
|
||||||
|
some details.
|
||||||
|
"""
|
||||||
|
|
|
@ -48,13 +48,21 @@ def format_report(loader, config, versions_to_include, title=None,
|
||||||
|
|
||||||
# Add the preludes.
|
# Add the preludes.
|
||||||
notefiles = loader[version]
|
notefiles = loader[version]
|
||||||
for n, sha in notefiles:
|
prelude_name = config.prelude_section_name
|
||||||
if 'prelude' in file_contents[n]:
|
notefiles_with_prelude = [(n, sha) for n, sha in notefiles
|
||||||
if show_source:
|
if prelude_name in file_contents[n]]
|
||||||
report.append('.. %s @ %s\n' % (n, sha))
|
if notefiles_with_prelude:
|
||||||
report.append(file_contents[n]['prelude'])
|
report.append(prelude_name.replace('_', ' ').title())
|
||||||
report.append('')
|
report.append('-' * len(prelude_name))
|
||||||
|
report.append('')
|
||||||
|
|
||||||
|
for n, sha in notefiles_with_prelude:
|
||||||
|
if show_source:
|
||||||
|
report.append('.. %s @ %s\n' % (n, sha))
|
||||||
|
report.append(file_contents[n][prelude_name])
|
||||||
|
report.append('')
|
||||||
|
|
||||||
|
# Add other sections.
|
||||||
for section_name, section_title in config.sections:
|
for section_name, section_title in config.sections:
|
||||||
notes = [
|
notes = [
|
||||||
(n, fn, sha)
|
(n, fn, sha)
|
||||||
|
|
|
@ -30,8 +30,8 @@ def lint_cmd(args, conf):
|
||||||
|
|
||||||
error = 0
|
error = 0
|
||||||
load = loader.Loader(conf, ignore_cache=True)
|
load = loader.Loader(conf, ignore_cache=True)
|
||||||
|
allowed_section_names = [conf.prelude_section_name] + \
|
||||||
allowed_section_names = ['prelude'] + [s[0] for s in conf.sections]
|
[s[0] for s in conf.sections]
|
||||||
|
|
||||||
uids = {}
|
uids = {}
|
||||||
for f in notes:
|
for f in notes:
|
||||||
|
|
|
@ -104,13 +104,13 @@ class Loader(object):
|
||||||
cleaned_content = {}
|
cleaned_content = {}
|
||||||
|
|
||||||
for section_name, section_content in content.items():
|
for section_name, section_content in content.items():
|
||||||
if section_name == 'prelude':
|
if section_name == self._config.prelude_section_name:
|
||||||
if not isinstance(section_content, six.string_types):
|
if not isinstance(section_content, six.string_types):
|
||||||
LOG.warning(
|
LOG.warning(
|
||||||
('The prelude section of %s '
|
('The %s section of %s '
|
||||||
'does not parse as a single string. '
|
'does not parse as a single string. '
|
||||||
'Is the YAML input escaped properly?') %
|
'Is the YAML input escaped properly?') %
|
||||||
filename,
|
(self._config.prelude_section_name, filename),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
if isinstance(section_content, six.string_types):
|
if isinstance(section_content, six.string_types):
|
||||||
|
|
|
@ -17,6 +17,7 @@ import os
|
||||||
import fixtures
|
import fixtures
|
||||||
|
|
||||||
from reno import config
|
from reno import config
|
||||||
|
from reno import defaults
|
||||||
from reno import main
|
from reno import main
|
||||||
from reno.tests import base
|
from reno.tests import base
|
||||||
|
|
||||||
|
@ -35,10 +36,7 @@ collapse_pre_releases: false
|
||||||
|
|
||||||
def test_defaults(self):
|
def test_defaults(self):
|
||||||
c = config.Config(self.tempdir.path)
|
c = config.Config(self.tempdir.path)
|
||||||
actual = {
|
actual = c.options
|
||||||
o: getattr(c, o)
|
|
||||||
for o in config.Config._OPTS.keys()
|
|
||||||
}
|
|
||||||
self.assertEqual(config.Config._OPTS, actual)
|
self.assertEqual(config.Config._OPTS, actual)
|
||||||
|
|
||||||
def test_override(self):
|
def test_override(self):
|
||||||
|
@ -46,10 +44,7 @@ collapse_pre_releases: false
|
||||||
c.override(
|
c.override(
|
||||||
collapse_pre_releases=False,
|
collapse_pre_releases=False,
|
||||||
)
|
)
|
||||||
actual = {
|
actual = c.options
|
||||||
o: getattr(c, o)
|
|
||||||
for o in config.Config._OPTS.keys()
|
|
||||||
}
|
|
||||||
expected = {}
|
expected = {}
|
||||||
expected.update(config.Config._OPTS)
|
expected.update(config.Config._OPTS)
|
||||||
expected['collapse_pre_releases'] = False
|
expected['collapse_pre_releases'] = False
|
||||||
|
@ -63,10 +58,7 @@ collapse_pre_releases: false
|
||||||
c.override(
|
c.override(
|
||||||
notesdir='value2',
|
notesdir='value2',
|
||||||
)
|
)
|
||||||
actual = {
|
actual = c.options
|
||||||
o: getattr(c, o)
|
|
||||||
for o in config.Config._OPTS.keys()
|
|
||||||
}
|
|
||||||
expected = {}
|
expected = {}
|
||||||
expected.update(config.Config._OPTS)
|
expected.update(config.Config._OPTS)
|
||||||
expected['notesdir'] = 'value2'
|
expected['notesdir'] = 'value2'
|
||||||
|
@ -119,10 +111,7 @@ collapse_pre_releases: false
|
||||||
c = self._run_override_from_parsed_args([
|
c = self._run_override_from_parsed_args([
|
||||||
'--no-collapse-pre-releases',
|
'--no-collapse-pre-releases',
|
||||||
])
|
])
|
||||||
actual = {
|
actual = c.options
|
||||||
o: getattr(c, o)
|
|
||||||
for o in config.Config._OPTS.keys()
|
|
||||||
}
|
|
||||||
expected = {}
|
expected = {}
|
||||||
expected.update(config.Config._OPTS)
|
expected.update(config.Config._OPTS)
|
||||||
expected['collapse_pre_releases'] = False
|
expected['collapse_pre_releases'] = False
|
||||||
|
@ -158,6 +147,22 @@ class TestConfigProperties(base.TestCase):
|
||||||
self.assertEqual('releasenotes/thenotes', self.c.notespath)
|
self.assertEqual('releasenotes/thenotes', self.c.notespath)
|
||||||
|
|
||||||
def test_template(self):
|
def test_template(self):
|
||||||
self.assertEqual(config._TEMPLATE, self.c.template)
|
template = defaults.TEMPLATE.format(defaults.PRELUDE_SECTION_NAME)
|
||||||
|
self.assertEqual(template, self.c.template)
|
||||||
self.c.override(template='i-am-a-template')
|
self.c.override(template='i-am-a-template')
|
||||||
self.assertEqual('i-am-a-template', self.c.template)
|
self.assertEqual('i-am-a-template', self.c.template)
|
||||||
|
|
||||||
|
def test_prelude_override(self):
|
||||||
|
template = defaults.TEMPLATE.format(defaults.PRELUDE_SECTION_NAME)
|
||||||
|
self.assertEqual(template, self.c.template)
|
||||||
|
self.c.override(prelude_section_name='fake_prelude_name')
|
||||||
|
expected_template = defaults.TEMPLATE.format('fake_prelude_name')
|
||||||
|
self.assertEqual(expected_template, self.c.template)
|
||||||
|
|
||||||
|
def test_prelude_and_template_override(self):
|
||||||
|
template = defaults.TEMPLATE.format(defaults.PRELUDE_SECTION_NAME)
|
||||||
|
self.assertEqual(template, self.c.template)
|
||||||
|
self.c.override(prelude_section_name='fake_prelude_name',
|
||||||
|
template='i-am-a-template')
|
||||||
|
self.assertEqual('fake_prelude_name', self.c.prelude_section_name)
|
||||||
|
self.assertEqual('i-am-a-template', self.c.template)
|
||||||
|
|
Loading…
Reference in New Issue