reno/reno/setup_command.py

139 lines
4.7 KiB
Python

# Copyright 2017, Red Hat, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""Custom distutils command.
For more information, refer to the distutils and setuptools source:
- https://github.com/python/cpython/blob/3.6/Lib/distutils/cmd.py
- https://github.com/pypa/setuptools/blob/v36.0.0/setuptools/command/sdist.py
"""
from distutils import cmd
from distutils import errors
from distutils import log
import six
from reno import cache
from reno import config
from reno import defaults
from reno import formatter
from reno import loader
COMMAND_NAME = 'build_reno' # duplicates what's found in setup.cfg
def load_config(distribution):
"""Utility method to parse distutils/setuptools configuration.
This is for use by other libraries to extract the command configuration.
:param distribution: A :class:`distutils.dist.Distribution` object
:returns: A tuple of a :class:`reno.config.Config` object, the output path
of the human-readable release notes file, and the output file of the
reno cache file
"""
option_dict = distribution.get_option_dict(COMMAND_NAME)
if option_dict.get('repo_root') is not None:
repo_root = option_dict.get('repo_root')[1]
else:
repo_root = defaults.REPO_ROOT
if option_dict.get('rel_notes_dir') is not None:
rel_notes_dir = option_dict.get('rel_notes_dir')[1]
else:
rel_notes_dir = defaults.RELEASE_NOTES_SUBDIR
if option_dict.get('output_file') is not None:
output_file = option_dict.get('output_file')[1]
else:
output_file = defaults.RELEASE_NOTES_FILENAME
conf = config.Config(repo_root, rel_notes_dir)
cache_file = loader.get_cache_filename(conf)
return (conf, output_file, cache_file)
class BuildReno(cmd.Command):
"""Distutils command to build reno release notes.
The release note build can be triggered from distutils, and some
configuration can be included in ``setup.py`` or ``setup.cfg`` instead of
being specified from the command-line.
"""
description = 'Build reno release notes'
user_options = [
('repo-root=', None, 'the root directory of the Git repository; '
'defaults to "."'),
('rel-notes-dir=', None, 'the parent directory; defaults to '
'"releasenotes"'),
('output-file=', None, 'the filename of the release notes file'),
]
def initialize_options(self):
self.repo_root = None
self.rel_notes_dir = None
self.output_file = None
def finalize_options(self):
if self.repo_root is None:
self.repo_root = defaults.REPO_ROOT
if self.rel_notes_dir is None:
self.rel_notes_dir = defaults.RELEASE_NOTES_SUBDIR
if self.output_file is None:
self.output_file = defaults.RELEASE_NOTES_FILENAME
# Overriding distutils' Command._ensure_stringlike which doesn't support
# unicode, causing finalize_options to fail if invoked again. Workaround
# for http://bugs.python.org/issue19570
def _ensure_stringlike(self, option, what, default=None):
# type: (unicode, unicode, Any) -> Any
val = getattr(self, option)
if val is None:
setattr(self, option, default)
return default
elif not isinstance(val, six.string_types):
raise errors.DistutilsOptionError("'%s' must be a %s (got `%s`)"
% (option, what, val))
return val
def run(self):
conf = config.Config(self.repo_root, self.rel_notes_dir)
# Generate the cache using the configuration options found
# in the release notes directory and the default output
# filename.
cache_filename = cache.write_cache_db(
conf=conf,
versions_to_include=[], # include all versions
outfilename=None, # generate the default name
)
log.info('wrote cache file to %s', cache_filename)
ldr = loader.Loader(conf)
text = formatter.format_report(
ldr,
conf,
ldr.versions,
title=self.distribution.metadata.name,
)
with open(self.output_file, 'w') as f:
f.write(text)
log.info('wrote release notes to %s', self.output_file)