gitdch/gitdch
2022-11-24 11:09:41 +01:00

286 lines
6.6 KiB
Python
Executable file

#!/usr/bin/env python3
""" Generate Debian package changelog from git """
import argparse
import logging
import os
import re
import sys
import git
VERSION = '0.0'
DEFAULT_GIT_PATCH = './'
DEFAULT_CODE_NAME = 'unstable'
DEFAULT_URGENCY = 'medium'
parser = argparse.ArgumentParser(
description='{0} (version: {1})'.format(__doc__, VERSION)
)
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)'
)
parser.add_argument(
'-R',
'--release-notes',
type=str,
dest='release_notes',
help='Specify an optional Markdown release notes output path'
)
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 - {} - %(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:
# pylint: disable=consider-using-f-string
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
)
)
# pylint: disable=consider-using-f-string
changelog_lines.extend([
' * {0}\n'.format(message)
for message in version['messages']
])
# pylint: disable=consider-using-f-string
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', encoding='utf8') as fd:
fd.writelines(changelog_lines)
else:
print(''.join(changelog_lines))
if options.release_notes:
log.info('Generate Markdown release notes')
release_notes_lines = ['# Changelog:\n\n']
release_notes_lines.extend([
'* {0}\n'.format(message)
for message in versions[0]['messages']
])
log.info(
'Write generated Markdown release notes in file %s',
options.release_notes)
with open(options.release_notes, 'w', encoding='utf8') as fd:
fd.writelines(release_notes_lines)