diff --git a/doc/source/user/usage.rst b/doc/source/user/usage.rst index d6e6cdb..8dc58e6 100644 --- a/doc/source/user/usage.rst +++ b/doc/source/user/usage.rst @@ -56,8 +56,8 @@ list: prelude - General comments about the release. The prelude from all notes in a - section are combined, in note order, to produce a single prelude + General comments about the release. Prelude sections from all notes in a + release are combined, in note order, to produce a single prelude introducing that release. This section is always included, regardless of what sections are configured. @@ -197,6 +197,9 @@ the most convenient way to manage the values consistently. - [api, API Changes] - [security, Security Issues] - [fixes, Bug Fixes] + # Change prelude_section_name to 'release_summary' from default value + # 'prelude'. + prelude_section_name: release_summary template: | ... @@ -284,6 +287,15 @@ The following options are configurable: order in which the final report will be generated. A prelude section will 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` OpenStack used to use null-merges to bring final release tags from diff --git a/reno/config.py b/reno/config.py index 2a8de90..d44c72c 100644 --- a/reno/config.py +++ b/reno/config.py @@ -19,74 +19,6 @@ from reno import defaults 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): @@ -113,7 +45,7 @@ class Config(object): 'earliest_version': None, # 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 # release version. The pattern is compiled with the verbose and unicode @@ -154,6 +86,13 @@ class Config(object): ['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 # changes and in which the second or later parent is tagged # are considered "null-merges" that bring the tag information @@ -220,6 +159,13 @@ class Config(object): else: 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): """Set the values of the named configuration options. @@ -228,6 +174,9 @@ class Config(object): present. """ + # Replace prelude section name if it has been changed. + self._rename_prelude_section(**kwds) + for n, v in kwds.items(): if n not in self._OPTS: LOG.warning('ignoring unknown configuration value %r = %r', @@ -269,6 +218,15 @@ class Config(object): """ 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): # """Parse the user config onto the namespace arguments. diff --git a/reno/defaults.py b/reno/defaults.py index b30a18d..927656d 100644 --- a/reno/defaults.py +++ b/reno/defaults.py @@ -12,3 +12,72 @@ RELEASE_NOTES_SUBDIR = 'releasenotes' 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. +""" diff --git a/reno/formatter.py b/reno/formatter.py index 646d68e..4092a8d 100644 --- a/reno/formatter.py +++ b/reno/formatter.py @@ -48,13 +48,21 @@ def format_report(loader, config, versions_to_include, title=None, # Add the preludes. notefiles = loader[version] - for n, sha in notefiles: - if 'prelude' in file_contents[n]: - if show_source: - report.append('.. %s @ %s\n' % (n, sha)) - report.append(file_contents[n]['prelude']) - report.append('') + prelude_name = config.prelude_section_name + notefiles_with_prelude = [(n, sha) for n, sha in notefiles + if prelude_name in file_contents[n]] + if notefiles_with_prelude: + report.append(prelude_name.replace('_', ' ').title()) + 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: notes = [ (n, fn, sha) diff --git a/reno/linter.py b/reno/linter.py index 5071842..9cbda99 100644 --- a/reno/linter.py +++ b/reno/linter.py @@ -30,8 +30,8 @@ def lint_cmd(args, conf): error = 0 load = loader.Loader(conf, ignore_cache=True) - - allowed_section_names = ['prelude'] + [s[0] for s in conf.sections] + allowed_section_names = [conf.prelude_section_name] + \ + [s[0] for s in conf.sections] uids = {} for f in notes: diff --git a/reno/loader.py b/reno/loader.py index f39bd04..6f8dcb0 100644 --- a/reno/loader.py +++ b/reno/loader.py @@ -104,13 +104,13 @@ class Loader(object): cleaned_content = {} 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): LOG.warning( - ('The prelude section of %s ' + ('The %s section of %s ' 'does not parse as a single string. ' 'Is the YAML input escaped properly?') % - filename, + (self._config.prelude_section_name, filename), ) else: if isinstance(section_content, six.string_types): diff --git a/reno/tests/test_config.py b/reno/tests/test_config.py index 3a0ea62..82a4446 100644 --- a/reno/tests/test_config.py +++ b/reno/tests/test_config.py @@ -17,6 +17,7 @@ import os import fixtures from reno import config +from reno import defaults from reno import main from reno.tests import base @@ -35,10 +36,7 @@ collapse_pre_releases: false def test_defaults(self): c = config.Config(self.tempdir.path) - actual = { - o: getattr(c, o) - for o in config.Config._OPTS.keys() - } + actual = c.options self.assertEqual(config.Config._OPTS, actual) def test_override(self): @@ -46,10 +44,7 @@ collapse_pre_releases: false c.override( collapse_pre_releases=False, ) - actual = { - o: getattr(c, o) - for o in config.Config._OPTS.keys() - } + actual = c.options expected = {} expected.update(config.Config._OPTS) expected['collapse_pre_releases'] = False @@ -63,10 +58,7 @@ collapse_pre_releases: false c.override( notesdir='value2', ) - actual = { - o: getattr(c, o) - for o in config.Config._OPTS.keys() - } + actual = c.options expected = {} expected.update(config.Config._OPTS) expected['notesdir'] = 'value2' @@ -125,10 +117,7 @@ collapse_pre_releases: false c = self._run_override_from_parsed_args([ '--no-collapse-pre-releases', ]) - actual = { - o: getattr(c, o) - for o in config.Config._OPTS.keys() - } + actual = c.options expected = {} expected.update(config.Config._OPTS) expected['collapse_pre_releases'] = False @@ -164,6 +153,22 @@ class TestConfigProperties(base.TestCase): self.assertEqual('releasenotes/thenotes', self.c.notespath) 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.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)