commit 9662a39abd4445590e3a9047a555f8f655d3224b Author: Benjamin Renard Date: Thu Mar 17 16:44:56 2022 +0100 Initial release diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b25c15b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*~ diff --git a/README.md b/README.md new file mode 100644 index 0000000..a1f5cfa --- /dev/null +++ b/README.md @@ -0,0 +1,56 @@ +# gitdch + +Simple python script using GitPython library to generate debian +changelog file from git commit history. Each existing tags is +considered as a release version and current working version is +numbered using ''git describe --tags'' command. + +# Installation +``` +apt install git python3-git +git clone https://gogs.zionetrix.net/bn8/gitdch.git /usr/local/src/gitdch +ln -s /usr/local/src/gitdch/gitdch /usr/local/bin/gitdch +``` + +# Usage +``` +usage: gitdch [-h] [-d] [-v] [-w] [-l LOGFILE] [-q] [-p GIT_PATH] [-o OUTPUT] [-n PACKAGE_NAME] [-V VERSION] [--version-suffix VERSION_SUFFIX] [-c CODE_NAME] [-u URGENCY] + +Generate Debian package changelog from git + +optional arguments: + -h, --help show this help message and exit + -d, --debug Show debug messages + -v, --verbose Show verbose messages + -w, --warning Show warning messages + -l LOGFILE, --log-file LOGFILE + Log file path + -q, --quiet Quiet mode: do not log on console (only if log file is provided) + -p GIT_PATH, --path GIT_PATH + Git repository path (default: ./) + -o OUTPUT, --output OUTPUT + Generated Debian changelog output path (default: stdout) + -n PACKAGE_NAME, --package-name PACKAGE_NAME + Package name + -V VERSION, --version VERSION + Currrent version (default: autodetected using git describe --tags) + --version-suffix VERSION_SUFFIX + Suffix for autodetected version + -c CODE_NAME, --code-name CODE_NAME + Debian code name (default: unstable) + -u URGENCY, --urgency URGENCY + Package urgency (default: medium) +``` + +## Copyright + +Copyright (c) 2013-2022 Benjamin Renard + +## License + +This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 3 as published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + diff --git a/gitdch b/gitdch new file mode 100755 index 0000000..de448f9 --- /dev/null +++ b/gitdch @@ -0,0 +1,227 @@ +#!/usr/bin/python + +""" Generate Debian package changelog from git """ + +import argparse +import logging +import os +import re +import sys + +import git + +default_git_path = './' +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_path, + default=default_git_path +) + +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 --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 +) + +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('--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=version['commit'].author.name, + email=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))