Source code for catkin_pkg.cli.generate_changelog

"""This script generates REP-0132 CHANGELOG.rst files for git or hg repositories."""

from __future__ import print_function

import argparse
import logging
import os
import sys

from catkin_pkg.changelog import CHANGELOG_FILENAME
from catkin_pkg.changelog_generator import generate_changelog_file, generate_changelogs, get_all_changes, get_forthcoming_changes, update_changelogs
from catkin_pkg.changelog_generator_vcs import get_vcs_client
from catkin_pkg.packages import find_packages

try:
    raw_input
except NameError:
    raw_input = input  # noqa: A001


[docs]def prompt_continue(msg, default): """Prompt the user for continuation.""" if default: msg += ' [Y/n]?' else: msg += ' [y/N]?' while True: response = raw_input(msg) if not response: response = 'y' if default else 'n' else: response = response.lower() if response in ['y', 'n']: return response == 'y' print("Response '%s' was not recognized, please use one of the following options: y, Y, n, N" % response, file=sys.stderr)
[docs]def main(sysargs=None): parser = argparse.ArgumentParser(description='Generate a REP-0132 %s' % CHANGELOG_FILENAME) group_merge = parser.add_mutually_exclusive_group() parser.add_argument( '-a', '--all', action='store_true', default=False, help='Generate changelog for all versions instead of only the forthcoming one (only supported when no changelog file exists yet)') group_merge.add_argument( '--only-merges', action='store_true', default=False, help='Only add merge commits to the changelog') parser.add_argument( '--print-root', action='store_true', default=False, help='Output changelog content to the console as if there would be only one package in the root of the repository') parser.add_argument( '--skip-contributors', action='store_true', default=False, help='Skip adding the list of contributors to the changelog') group_merge.add_argument( '--skip-merges', action='store_true', default=False, help='Skip adding merge commits to the changelog') parser.add_argument( '-y', '--non-interactive', action='store_true', default=False, help="Run without user interaction, confirming all questions with 'yes'") args = parser.parse_args(sysargs) base_path = '.' logging.basicConfig(format='%(message)s', level=logging.DEBUG) vcs_client = get_vcs_client(base_path) if args.print_root: # printing status messages to stderr to allow piping the changelog to a file if args.all: print('Querying all tags and commit information...', file=sys.stderr) tag2log_entries = get_all_changes(vcs_client, skip_merges=args.skip_merges, only_merges=args.only_merges) print('Generating changelog output with all versions...', file=sys.stderr) else: print('Querying commit information since latest tag...', file=sys.stderr) tag2log_entries = get_forthcoming_changes(vcs_client, skip_merges=args.skip_merges, only_merges=args.only_merges) print('Generating changelog files with forthcoming version...', file=sys.stderr) print('', file=sys.stderr) data = generate_changelog_file('repository-level', tag2log_entries, vcs_client=vcs_client) print(data) return 0 # find packages packages = find_packages(base_path) if not packages: raise RuntimeError('No packages found') print('Found packages: %s' % ', '.join(sorted(p.name for p in packages.values()))) # check for missing changelogs missing_changelogs = [] for pkg_path, package in packages.items(): changelog_path = os.path.join(base_path, pkg_path, CHANGELOG_FILENAME) if not os.path.exists(changelog_path): missing_changelogs.append(package.name) if args.all and not missing_changelogs: raise RuntimeError('All packages already have a changelog. Either remove (some of) them before using --all or invoke the script without --all.') if args.all and len(missing_changelogs) != len(packages): ignored = set([p.name for p in packages.values()]) - set(missing_changelogs) print('The following packages already have a changelog file and will be ignored: %s' % ', '.join(sorted(ignored)), file=sys.stderr) # prompt to switch to --all if not args.all and missing_changelogs: print('Some of the packages have no changelog file: %s' % ', '.join(sorted(missing_changelogs))) print('You might consider to use --all to generate the changelogs for all versions (not only for the forthcoming version).') if not args.non_interactive and not prompt_continue('Continue without --all option', default=False): raise RuntimeError('Skipping generation, rerun the script with --all.') if args.all: print('Querying all tags and commit information...') tag2log_entries = get_all_changes(vcs_client, skip_merges=args.skip_merges, only_merges=args.only_merges) print('Generating changelog files with all versions...') generate_changelogs(base_path, packages, tag2log_entries, logger=logging, vcs_client=vcs_client, skip_contributors=args.skip_contributors) else: print('Querying commit information since latest tag...') tag2log_entries = get_forthcoming_changes(vcs_client, skip_merges=args.skip_merges, only_merges=args.only_merges) # separate packages with/without a changelog file packages_without = {pkg_path: package for pkg_path, package in packages.items() if package.name in missing_changelogs} if packages_without: print('Generating changelog files with forthcoming version...') generate_changelogs(base_path, packages_without, tag2log_entries, logger=logging, vcs_client=vcs_client, skip_contributors=args.skip_contributors) packages_with = {pkg_path: package for pkg_path, package in packages.items() if package.name not in missing_changelogs} if packages_with: print('Updating forthcoming section of changelog files...') update_changelogs(base_path, packages_with, tag2log_entries, logger=logging, vcs_client=vcs_client, skip_contributors=args.skip_contributors) print('Done.') print('Please review the extracted commit messages and consolidate the changelog entries before committing the files!')
[docs]def main_catching_runtime_error(*args, **kwargs): try: main(*args, **kwargs) except RuntimeError as e: print('ERROR: ' + str(e), file=sys.stderr) sys.exit(1)