Mercurial > piecrust2
changeset 544:9a00e694b42c
cm: Changelog generator script.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Fri, 31 Jul 2015 23:35:07 -0700 |
parents | bedfa0156bf7 |
children | 1856e7aa6ce8 |
files | util/changelog/category_title.rst util/changelog/header.rst util/changelog/version_title.rst util/generate_changelog.py |
diffstat | 4 files changed, 180 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/util/changelog/category_title.rst Fri Jul 31 23:35:07 2015 -0700 @@ -0,0 +1,4 @@ + +1.%sub_num% %category% +---------------------- +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/util/changelog/header.rst Fri Jul 31 23:35:07 2015 -0700 @@ -0,0 +1,10 @@ + +######### +CHANGELOG +######### + +This is the changelog for PieCrust_. + +.. _PieCrust: http://bolt80.com/piecrust/ + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/util/changelog/version_title.rst Fri Jul 31 23:35:07 2015 -0700 @@ -0,0 +1,5 @@ + +================================== +%num%. PieCrust %version% (%date%) +================================== +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/util/generate_changelog.py Fri Jul 31 23:35:07 2015 -0700 @@ -0,0 +1,161 @@ +import os +import os.path +import re +import sys +import subprocess + + +hg_log_template = ("{if(tags, '>>{tags};{date|shortdate}\n')}" + "{desc|firstline}\n\n") + +re_add_tag_changeset = re.compile('^Added tag [^\s]+ for changeset [\w\d]+$') +re_merge_pr_changeset = re.compile('^Merge pull request') +re_tag = re.compile('^\d+\.\d+\.\d+([ab]\d+)?(rc\d+)?$') +re_change = re.compile('^(\w+):') +re_clean_code_span = re.compile('([^\s])``([^\s]+)') + +category_commands = [ + 'chef', 'bake', 'find', 'help', 'import', 'init', 'paths', 'plugin', + 'plugins', 'prepare', 'purge', 'root', 'routes', 'serve', + 'showconfig', 'showrecord', 'sources', 'theme', 'themes'] +category_core = [ + 'internal', 'bug', 'templating', 'formatting', 'performance', + 'data', 'config', 'rendering', 'render', 'debug', 'reporting', + 'linker', 'pagination', 'routing', 'caching'] +category_project = ['build', 'cm', 'docs', 'tests', 'setup'] +categories = [ + ('commands', category_commands), + ('core', category_core), + ('project', category_project), + ('miscellaneous', None)] +category_names = list(map(lambda i: i[0], categories)) + + +def generate(): + out_file = 'CHANGELOG.rst' + if len(sys.argv) > 1: + out_file = sys.argv[1] + + print("Generating %s" % out_file) + + if not os.path.exists('.hg'): + raise Exception("You must run this script from the root of a " + "Mercurial clone of the PieCrust repository.") + hglog = subprocess.check_output([ + 'hg', 'log', + '--rev', 'reverse(::master)', + '--template', hg_log_template]) + hglog = hglog.decode('utf8') + + templates = _get_templates() + + with open(out_file, 'w') as fp: + fp.write(templates['header']) + + skip = False + in_desc = False + current_version = 0 + current_version_info = None + current_changes = None + for line in hglog.splitlines(): + if line == '': + skip = False + in_desc = False + continue + + if not in_desc and line.startswith('>>'): + tags, tag_date = line[2:].split(';') + if re_tag.match(tags): + if current_version > 0: + _write_version_changes( + templates, + current_version, current_version_info, + current_changes, fp) + + current_version += 1 + current_version_info = tags, tag_date + current_changes = {} + in_desc = True + else: + skip = True + continue + + if skip or current_version == 0: + continue + + if re_add_tag_changeset.match(line): + continue + if re_merge_pr_changeset.match(line): + continue + + m = re_change.match(line) + if m: + ch_type = m.group(1) + for cat_name, ch_types in categories: + if ch_types is None or ch_type in ch_types: + msgs = current_changes.setdefault(cat_name, []) + msgs.append(line) + break + else: + assert False, ("Change '%s' should have gone in the " + "misc. bucket." % line) + else: + msgs = current_changes.setdefault('miscellaneous', []) + msgs.append(line) + + if current_version > 0: + _write_version_changes( + templates, + current_version, current_version_info, + current_changes, fp) + + +def _write_version_changes(templates, version, version_info, changes, fp): + tokens = { + 'num': str(version), + 'version': version_info[0], + 'date': version_info[1]} + tpl = _multi_replace(templates['version_title'], tokens) + fp.write(tpl) + + for i, cat_name in enumerate(category_names): + msgs = changes.get(cat_name) + if not msgs: + continue + + tokens = { + 'sub_num': str(i), + 'category': cat_name.title()} + tpl = _multi_replace(templates['category_title'], tokens) + fp.write(tpl) + + for msg in msgs: + msg = msg.replace('`', '``').rstrip('\n') + msg = re_clean_code_span.sub(r'\1`` \2', msg) + fp.write('* ' + msg + '\n') + + +def _multi_replace(s, tokens): + for token in tokens: + s = s.replace('%%%s%%' % token, tokens[token]) + return s + + +def _get_templates(): + tpl_dir = os.path.join(os.path.dirname(__file__), 'changelog') + tpls = {} + for name in os.listdir(tpl_dir): + tpl = _get_template(os.path.join(tpl_dir, name)) + name_no_ext, _ = os.path.splitext(name) + tpls[name_no_ext] = tpl + return tpls + + +def _get_template(filename): + with open(filename, 'r', encoding='utf8') as fp: + return fp.read() + + +if __name__ == '__main__': + generate() +