diff options
author | Rob Browning <rlb@defaultvalue.org> | 2010-12-06 08:30:22 +0100 |
---|---|---|
committer | Guido Günther <agx@sigxcpu.org> | 2010-12-06 09:17:04 +0100 |
commit | 3640569c90a3326aa8b882fa72d63ed881785de4 (patch) | |
tree | de2c96284fadad8e87b4c258202b68a526d7b905 /gbp/dch.py | |
parent | e8757040c20697c7cce1180127e257f9f17ab713 (diff) |
Add git-dch --customizations FILE to allow changelog entry customization
Add support for git-dch --customizations FILE. FILE must be Python
code, and for now, the only useful thing it can do is define a
format_changelog_entry() function which will override
gbp.dch.format_changelog_entry().
Add a new customization option group for --customizations.
Create a gbp.dch module and move the changelog entry formatting
functions there. Create separate procedures to handle extracting
metadata from the git log, and use them in the default
format_changelog_entry(). These functions are also available for use
by custom formatters: extract_git_dch_cmds(),
filter_ignore_rx_matches(), extract_bts_cmds(), extract_thanks_info(),
etc.
Add a GitRepository.get_commit_info() method, and use it in git-dch
parse_commit().
Signed-off-by: Rob Browning <rlb@defaultvalue.org>
Diffstat (limited to 'gbp/dch.py')
-rw-r--r-- | gbp/dch.py | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/gbp/dch.py b/gbp/dch.py new file mode 100644 index 00000000..8ce8f2bc --- /dev/null +++ b/gbp/dch.py @@ -0,0 +1,116 @@ +# vim: set fileencoding=utf-8 : +# +# (C) 2010 Rob Browning <rlb@defaultvalue.org> +"""provides git-dch helpers""" + +import re + + +def extract_git_dch_cmds(lines, options): + """Return a dictionary of all Git-Dch: commands found in lines. + The command keys will be lowercased, i.e. {'ignore' : True, + 'short': True}. For now, all the options are binary. Also return + all of the lines that do not contain Git-Dch: commands.""" + commands = {} + other_lines = [] + for line in lines: + if line.startswith('Git-Dch: '): + cmd = line.split(' ', 1)[1].strip().lower() + commands[cmd] = True + else: + other_lines.append(line) + return (commands, other_lines) + + +def filter_ignore_rx_matches(lines, options): + """Filter any lines that match options.ignore_regex + (i.e. --ignore-regex).""" + if options.ignore_regex: + ignore_re = re.compile(options.ignore_regex) + return [line for line in lines if not ignore_re.match(line)] + else: + return lines + + +_bug_r = r'(?:bug|issue)?\#?\s?\d+' +_bug_re = re.compile(_bug_r, re.I) + +def extract_bts_cmds(lines, opts): + """Return a dictionary of the bug tracking system commands + contained in the the given lines. i.e. {'closed' : [1], 'fixed': + [3, 4]}. Right now, this will only notice a single directive + clause on a line. Also return all of the lines that do not + contain bug tracking system commands.""" + bts_rx = re.compile(r'(?P<bts>%s):\s+%s' % (opts.meta_closes, _bug_r), re.I) + commands = {} + other_lines = [] + for line in lines: + m = bts_rx.match(line) + if m: + bug_nums = [ bug.strip() for bug in _bug_re.findall(line, re.I) ] + try: + commands[m.group('bts')] += bug_nums + except KeyError: + commands[m.group('bts')] = bug_nums + else: + other_lines.append(line) + return (commands, other_lines) + + +def extract_thanks_info(lines, options): + """Return a list of all of the Thanks: entries, and a list of all + of the lines that do not contain Thanks: entries.""" + thanks = [] + other_lines = [] + for line in lines: + if line.startswith('Thanks: '): + thanks.append(line.split(' ', 1)[1].strip()) + else: + other_lines.append(line) + return (thanks, other_lines) + + +def _ispunct(ch): + return not ch.isalnum() and not ch.isspace() + + +def terminate_first_line_if_needed(lines): + """Terminate the first line of lines with a '.' if multi-line.""" + # Don't add a period to empty or one line commit messages. + if len(lines) < 2: + return lines + if lines[0] and _ispunct(lines[0][-1]): + return lines + if lines[1] and (_ispunct(lines[1][0]) or lines[1][0].islower()): + return lines + return [lines[0] + "."] + lines[1:] + + +def format_changelog_entry(commit_info, options, last_commit=False): + """Return a list of lines (without newlines) as the changelog + entry for commit_info (generated by + GitRepository.get_commit_info()). If last_commit is not False, + then this entry is the last one in the series.""" + entry = [commit_info['subject']] + body = commit_info['body'] + (git_dch_cmds, body) = extract_git_dch_cmds(body, options) + if 'ignore' in git_dch_cmds: + return None + (bts_cmds, body) = extract_bts_cmds(body, options) + (thanks, body) = extract_thanks_info(body, options) + body = filter_ignore_rx_matches(body, options) + if options.full and not 'short' in git_dch_cmds: + # Add all non-blank body lines. + entry.extend([line for line in body if line.strip()]) + for bts in bts_cmds: + print bts_cmds + entry[-1] += '(%s: %s) ' % (bts, ', '.join(bts_cmds[bts])) + if thanks: + # Last wins for now (match old behavior). + entry[-1] += '- thanks to %s' % thanks[-1] + if options.idlen: + entry[0] = '[%s] ' % commitid[0:options.idlen] + entry[0] + entry = terminate_first_line_if_needed(entry) + if not last_commit: + entry += '' + return entry |