#!/usr/bin/env python3 """ Generate Debian package changelog from git """ import argparse import logging import os import re import sys import git DEFAULT_GIT_PATCH = './' DEFAULT_CODE_NAME = 'unstable' DEFAULT_URGENCY = 'medium' parser = argparse.ArgumentParser(description=__doc__) parser.add_argument( '-d', '--debug', action='store_true', help='Show debug messages' ) parser.add_argument( '-v', '--verbose', action='store_true', help='Show verbose messages' ) parser.add_argument( '-w', '--warning', action='store_true', help='Show warning messages' ) parser.add_argument( '-l', '--log-file', action="store", type=str, dest="logfile", help="Log file path" ) parser.add_argument( '-q', '--quiet', action='store_true', help='Quiet mode: do not log on console (only if log file is provided)' ) parser.add_argument( '-p', '--path', type=str, dest='git_path', help='Git repository path (default: %s)' % DEFAULT_GIT_PATCH, default=DEFAULT_GIT_PATCH ) parser.add_argument( '-o', '--output', type=str, dest='output', help='Generated Debian changelog output path (default: stdout)', ) parser.add_argument( '-n', '--package-name', type=str, dest='package_name', help='Package name' ) parser.add_argument( '-V', '--version', type=str, dest='version', help=( 'Currrent version (default: autodetected using git describe ' '--always --tags)') ) parser.add_argument( '--version-suffix', type=str, dest='version_suffix', help='Suffix for autodetected version' ) parser.add_argument( '-c', '--code-name', type=str, dest='code_name', help='Debian code name (default: %s)' % DEFAULT_CODE_NAME, default=DEFAULT_CODE_NAME ) parser.add_argument( '-u', '--urgency', type=str, dest='urgency', help='Package urgency (default: %s)' % DEFAULT_URGENCY, default=DEFAULT_URGENCY ) parser.add_argument( '-N', '--maintainer-name', type=str, dest='maintainer_name', help='Maintainer name (default: last commit author name)' ) parser.add_argument( '-E', '--maintainer-email', type=str, dest='maintainer_email', help='Maintainer email (default: last commit author email)' ) options = parser.parse_args() if not options.package_name: parser.error( 'You must provide package name using -n/--package-name paramter') # Initialize log log = logging.getLogger() logformat = logging.Formatter( "%(asctime)s - {0} - %(levelname)s : %(message)s".format( os.path.basename(sys.argv[0]) ) ) # Set root logger to DEBUG (filtering done by handlers) log.setLevel(logging.DEBUG) log_level = None if options.debug: log_level = logging.DEBUG elif options.verbose: log_level = logging.INFO elif options.warning: log_level = logging.WARNING if options.logfile: logfile = logging.FileHandler(options.logfile) logfile.setFormatter(logformat) logfile.setLevel(log_level if log_level is not None else logging.INFO) log.addHandler(logfile) if not options.quiet or not options.logfile: logconsole = logging.StreamHandler() logconsole.setLevel(log_level if log_level is not None else logging.FATAL) logconsole.setFormatter(logformat) log.addHandler(logconsole) repo = git.Repo(options.git_path) log.info('Generate changelog from git commits') versions = [] tag_commits = dict( (tag.commit.binsha, tag) for tag in repo.tags ) def clean_deb_version(version_name): """ Clean debian version name """ version_name = re.sub('^[^0-9]*', '', version_name) if options.version_suffix: version_name += options.version_suffix return version_name def add_version(): """ Add version info """ if messages: log.info('Add version %s:\n - %s', version, '\n - '.join(messages)) versions.append({ 'name': version, 'tag': tag, 'commit': version_commit, 'messages': messages, }) tag = None version_commit = None version = ( options.version or clean_deb_version( repo.git.describe('--always', '--tags') ) ) messages = [] for commit in repo.iter_commits(): if version_commit is None: version_commit = commit log.debug('Commit %s', commit) if commit.binsha in tag_commits: new_tag = tag_commits[commit.binsha] log.debug('Reach new tag %s', new_tag) add_version() tag = new_tag version = clean_deb_version(tag.name) version_commit = commit messages = [] log.debug('Iter commits for version %s') messages.append(commit.summary) add_version() log.info('%d versions found', len(versions)) changelog_lines = [] for version in versions: changelog_lines.append( '{package} ({version}-1) {code_name}; urgency={urgency}\n\n'.format( package=options.package_name, version=version['name'], code_name=options.code_name, urgency=options.urgency ) ) for message in version['messages']: changelog_lines.append(' * {0}\n'.format(message)) changelog_lines.append( "\n -- {name} <{email}> {date}\n\n".format( name=( options.maintainer_name if options.maintainer_name else version['commit'].author.name), email=( options.maintainer_email if options.maintainer_email else version['commit'].author.email), date=version['commit'].committed_datetime.strftime( "%a, %d %b %Y %H:%M:%S %z") ) ) if options.output: log.info('Write generated Debian changelog in file %s', options.output) with open(options.output, 'w') as fd: fd.writelines(changelog_lines) else: print(''.join(changelog_lines))