define options with help text
Expand the way options are defined to include help text so we can eventually include that in generated configuration files and in online documentation. Change-Id: I0636f5e2fb9b21519f6cdda25a1ac546a3ffe174 Signed-off-by: Doug Hellmann <doug@doughellmann.com>
This commit is contained in:
parent
9d058ae097
commit
fab39dfcc8
115
reno/config.py
115
reno/config.py
@ -10,8 +10,10 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import collections
|
||||
import logging
|
||||
import os.path
|
||||
import textwrap
|
||||
|
||||
import yaml
|
||||
|
||||
@ -20,41 +22,61 @@ from reno import defaults
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Config(object):
|
||||
Opt = collections.namedtuple('Opt', 'name default help')
|
||||
|
||||
_OPTS = {
|
||||
# The notes subdirectory within the relnotesdir where the
|
||||
# notes live.
|
||||
'notesdir': defaults.NOTES_SUBDIR,
|
||||
_OPTIONS = [
|
||||
Opt('notesdir', defaults.NOTES_SUBDIR,
|
||||
textwrap.dedent("""
|
||||
The notes subdirectory within the relnotesdir where the
|
||||
notes live.
|
||||
""")),
|
||||
|
||||
# Should pre-release versions be merged into the final release
|
||||
# of the same number (1.0.0.0a1 notes appear under 1.0.0).
|
||||
'collapse_pre_releases': True,
|
||||
Opt('collapse_pre_releases', True,
|
||||
textwrap.dedent("""
|
||||
Should pre-release versions be merged into the final release
|
||||
of the same number (1.0.0.0a1 notes appear under 1.0.0).
|
||||
""")),
|
||||
|
||||
# Should the scanner stop at the base of a branch (True) or go
|
||||
# ahead and scan the entire history (False)?
|
||||
'stop_at_branch_base': True,
|
||||
Opt('stop_at_branch_base', True,
|
||||
textwrap.dedent("""
|
||||
Should the scanner stop at the base of a branch (True) or go
|
||||
ahead and scan the entire history (False)?
|
||||
""")),
|
||||
|
||||
Opt('branch', None,
|
||||
textwrap.dedent("""
|
||||
# The git branch to scan. Defaults to the "current" branch
|
||||
# checked out.
|
||||
'branch': None,
|
||||
""")),
|
||||
|
||||
Opt('earliest_version', None,
|
||||
textwrap.dedent("""
|
||||
# The earliest version to be included. This is usually the
|
||||
# lowest version number, and is meant to be the oldest
|
||||
# version.
|
||||
'earliest_version': None,
|
||||
""")),
|
||||
|
||||
Opt('template', defaults.TEMPLATE.format(defaults.PRELUDE_SECTION_NAME),
|
||||
textwrap.dedent("""
|
||||
# The template used by reno new to create a note.
|
||||
'template': defaults.TEMPLATE.format(defaults.PRELUDE_SECTION_NAME),
|
||||
""")),
|
||||
|
||||
Opt('release_tag_re',
|
||||
textwrap.dedent('''
|
||||
((?:[\d.ab]|rc)+) # digits, a, b, and rc cover regular and
|
||||
# pre-releases
|
||||
'''),
|
||||
textwrap.dedent("""
|
||||
# The RE pattern used to match the repo tags representing a valid
|
||||
# release version. The pattern is compiled with the verbose and unicode
|
||||
# flags enabled.
|
||||
'release_tag_re': '''
|
||||
((?:[\d.ab]|rc)+) # digits, a, b, and rc cover regular and
|
||||
# pre-releases
|
||||
''',
|
||||
""")),
|
||||
|
||||
Opt('pre_release_tag_re',
|
||||
textwrap.dedent('''
|
||||
(?P<pre_release>\.\d+(?:[ab]|rc)+\d*)$
|
||||
'''),
|
||||
textwrap.dedent("""
|
||||
# The RE pattern used to check if a valid release version tag is also a
|
||||
# valid pre-release version. The pattern is compiled with the verbose
|
||||
# and unicode flags enabled. The pattern must define a group called
|
||||
@ -62,20 +84,17 @@ class Config(object):
|
||||
# separator, e.g for pre-release version '12.0.0.0rc1' the default RE
|
||||
# pattern will identify '.0rc1' as the value of the group
|
||||
# 'pre_release'.
|
||||
'pre_release_tag_re': '''
|
||||
(?P<pre_release>\.\d+(?:[ab]|rc)+\d*)$
|
||||
''',
|
||||
""")),
|
||||
|
||||
Opt('branch_name_re', 'stable/.+',
|
||||
textwrap.dedent("""
|
||||
# The pattern for names for branches that are relevant when
|
||||
# scanning history to determine where to stop, to find the
|
||||
# "base" of a branch. Other branches are ignored.
|
||||
'branch_name_re': 'stable/.+',
|
||||
""")),
|
||||
|
||||
# The identifiers and names of permitted sections in the
|
||||
# release notes, in the order in which the final report will
|
||||
# be generated. A prelude section will always be automatically
|
||||
# inserted before the first element of this list.
|
||||
'sections': [
|
||||
Opt('sections',
|
||||
[
|
||||
['features', 'New Features'],
|
||||
['issues', 'Known Issues'],
|
||||
['upgrade', 'Upgrade Notes'],
|
||||
@ -85,14 +104,24 @@ class Config(object):
|
||||
['fixes', 'Bug Fixes'],
|
||||
['other', 'Other Notes'],
|
||||
],
|
||||
textwrap.dedent("""
|
||||
# The identifiers and names of permitted sections in the
|
||||
# release notes, in the order in which the final report will
|
||||
# be generated. A prelude section will always be automatically
|
||||
# inserted before the first element of this list.
|
||||
""")),
|
||||
|
||||
Opt('prelude_section_name', defaults.PRELUDE_SECTION_NAME,
|
||||
textwrap.dedent("""
|
||||
# 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,
|
||||
""")),
|
||||
|
||||
Opt('ignore_null_merges', True,
|
||||
textwrap.dedent("""
|
||||
# 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
|
||||
@ -103,20 +132,27 @@ class Config(object):
|
||||
# confuses the regular traversal because it makes that stable
|
||||
# branch appear to be part of master and/or the later stable
|
||||
# branch. This option allows us to ignore those.
|
||||
'ignore_null_merges': True,
|
||||
""")),
|
||||
|
||||
Opt('ignore_notes', [],
|
||||
textwrap.dedent("""
|
||||
# Note files to be ignored. It's useful to be able to ignore a
|
||||
# file if it is edited on the wrong branch. Notes should be
|
||||
# specified by their filename or UID. Setting the value in the
|
||||
# configuration file makes it apply to all branches.
|
||||
'ignore_notes': [],
|
||||
}
|
||||
""")),
|
||||
]
|
||||
|
||||
|
||||
class Config(object):
|
||||
|
||||
_OPTS = {o.name: o for o in _OPTIONS}
|
||||
|
||||
@classmethod
|
||||
def get_default(cls, opt):
|
||||
"Return the default for an option."
|
||||
try:
|
||||
return cls._OPTS[opt]
|
||||
return cls._OPTS[opt].default
|
||||
except KeyError:
|
||||
raise ValueError('unknown option name %r' % (opt,))
|
||||
|
||||
@ -134,7 +170,7 @@ class Config(object):
|
||||
relnotesdir = defaults.RELEASE_NOTES_SUBDIR
|
||||
self.relnotesdir = relnotesdir
|
||||
# Initialize attributes from the defaults.
|
||||
self.override(**self._OPTS)
|
||||
self.override(**{o.name: o.default for o in _OPTIONS})
|
||||
|
||||
self._contents = {}
|
||||
self._load_file()
|
||||
@ -161,7 +197,7 @@ class Config(object):
|
||||
|
||||
def _rename_prelude_section(self, **kwargs):
|
||||
key = 'prelude_section_name'
|
||||
if key in kwargs and kwargs[key] != self._OPTS[key]:
|
||||
if key in kwargs and kwargs[key] != self._OPTS[key].default:
|
||||
new_prelude_name = kwargs[key]
|
||||
|
||||
self.template = defaults.TEMPLATE.format(new_prelude_name)
|
||||
@ -192,9 +228,9 @@ class Config(object):
|
||||
|
||||
"""
|
||||
arg_values = {
|
||||
o: getattr(parsed_args, o)
|
||||
for o in self._OPTS.keys()
|
||||
if hasattr(parsed_args, o)
|
||||
o.name: getattr(parsed_args, o.name)
|
||||
for o in _OPTIONS
|
||||
if hasattr(parsed_args, o.name)
|
||||
}
|
||||
self.override(**arg_values)
|
||||
|
||||
@ -224,7 +260,10 @@ class Config(object):
|
||||
|
||||
Returns the actual configuration options after overrides.
|
||||
"""
|
||||
options = {o: getattr(self, o) for o in self._OPTS}
|
||||
options = {
|
||||
o.name: getattr(self, o.name)
|
||||
for o in _OPTIONS
|
||||
}
|
||||
return options
|
||||
|
||||
# def parse_config_into(parsed_arguments):
|
||||
|
@ -37,7 +37,11 @@ collapse_pre_releases: false
|
||||
def test_defaults(self):
|
||||
c = config.Config(self.tempdir.path)
|
||||
actual = c.options
|
||||
self.assertEqual(config.Config._OPTS, actual)
|
||||
expected = {
|
||||
o.name: o.default
|
||||
for o in config._OPTIONS
|
||||
}
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
def test_override(self):
|
||||
c = config.Config(self.tempdir.path)
|
||||
@ -45,8 +49,10 @@ collapse_pre_releases: false
|
||||
collapse_pre_releases=False,
|
||||
)
|
||||
actual = c.options
|
||||
expected = {}
|
||||
expected.update(config.Config._OPTS)
|
||||
expected = {
|
||||
o.name: o.default
|
||||
for o in config._OPTIONS
|
||||
}
|
||||
expected['collapse_pre_releases'] = False
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
@ -59,8 +65,10 @@ collapse_pre_releases: false
|
||||
notesdir='value2',
|
||||
)
|
||||
actual = c.options
|
||||
expected = {}
|
||||
expected.update(config.Config._OPTS)
|
||||
expected = {
|
||||
o.name: o.default
|
||||
for o in config._OPTIONS
|
||||
}
|
||||
expected['notesdir'] = 'value2'
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
@ -108,18 +116,24 @@ collapse_pre_releases: false
|
||||
def test_override_from_parsed_args_empty(self):
|
||||
c = self._run_override_from_parsed_args([])
|
||||
actual = {
|
||||
o: getattr(c, o)
|
||||
for o in config.Config._OPTS.keys()
|
||||
o.name: getattr(c, o.name)
|
||||
for o in config._OPTIONS
|
||||
}
|
||||
self.assertEqual(config.Config._OPTS, actual)
|
||||
expected = {
|
||||
o.name: o.default
|
||||
for o in config._OPTIONS
|
||||
}
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
def test_override_from_parsed_args(self):
|
||||
c = self._run_override_from_parsed_args([
|
||||
'--no-collapse-pre-releases',
|
||||
])
|
||||
actual = c.options
|
||||
expected = {}
|
||||
expected.update(config.Config._OPTS)
|
||||
expected = {
|
||||
o.name: o.default
|
||||
for o in config._OPTIONS
|
||||
}
|
||||
expected['collapse_pre_releases'] = False
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user