Julian Foad wrote on Thu, Jan 03, 2019 at 17:15:16 +0000: > Julian Foad wrote: > > [...] either inline or links to the verbose text samples above. [...] > > More precisely: I propose the output of "svn log" as illustrated in those > samples,
Here you go. [[[ % ./upcoming.py | tail -46 ------------------------------------------------------------------------ r1847610 | svn-role | 2018-11-28 04:00:29 +0000 (Wed, 28 Nov 2018) Merge the r1847181 group from trunk: * r1847181, r1847182, r1847188, r1847264 Fix issue SVN-4792: Foreign repo copy of file adding mergeinfo. Justification: We don't want bogus mergeinfo. Votes: +1: julianfoad, brane, rhuijben ------------------------------------------------------------------------ r1849266 | svn-role | 2018-12-19 04:00:55 +0000 (Wed, 19 Dec 2018) Merge the r1847572 group from trunk: * r1847572, r1847596 fsfs: Fix SVN-4791, an issue with the DAG open_path() that was causing unexpected SVN_ERR_FS_NOT_DIRECTORY errors when attempting to open a path with `open_path_node_only | open_path_allow_null` flags. Justification: Some valid FSFS read operations errored out. This could break some end-user operations like 'update'. Votes: +1: julianfoad, brane, stefan2 ------------------------------------------------------------------------ ]]] > concatenated with the full content of the relevant 'STATUS' file. Minus the "Veto-blocked" changes, though. Cheers, Daniel
#! /usr/bin/env python3 """ WIP - INCOMPLETE Generate 'svn log' output since the last tag to HEAD of the release branch, filtering all but merge commits. """ import datetime import os import re import subprocess import sys import tempfile import xml.etree.ElementTree as ET SINCE = '1.11.0' SVN = os.getenv('SVN', 'svn') LOG_SEPARATOR_LINE = ('-' * 72) + '\n' def get_copyfrom_revision_of_tag(version_number): """Given a version number, return the copyfrom revision of that release's tag.""" assert version_number == SINCE # TODO: parse and return `svn log -r0:HEAD --limit=1 --stop-on-copy ^/subversion/tags/1.11.0 -vq` return 1845131 def get_merges_for_range(start, end): """Return an array of revision numbers in the range -r START:END that are merges. START must be an integer; END need not be.""" cache = [] revisions = \ subprocess.check_output( [SVN, 'log', '--xml', '-v', '-r', str(start) + ":" + str(end)], ).decode() log_xml = ET.fromstring(revisions) relative_url = subprocess.check_output([SVN, 'info', '--show-item', 'relative-url']).decode().rstrip('\n') for logentry in log_xml.findall('./logentry'): is_merge = relative_url[1:] in (path.text for path in logentry.findall('.//path')) if is_merge: yield logentry def main(): for logentry in get_merges_for_range(get_copyfrom_revision_of_tag(SINCE) + 1, "HEAD") : f = lambda s: logentry.findall('./' + s)[0].text f.__doc__ = """Get the contents of the first child tag whose name is given as an argument.""" print(LOG_SEPARATOR_LINE, end='') print("r%(revision)s | %(author)s | %(date)s | %(linecount)s lines" % dict( revision = logentry.attrib['revision'], author = f('author'), date = datetime.datetime.strptime(f('date'), '%Y-%m-%dT%H:%M:%S.%fZ').strftime('%Y-%m-%d %H:%M:%S +0000 (%a, %d %b %Y)'), linecount = 1+len(f('msg').splitlines()), # increment because of the empty line printed next )) print() print(f('msg')) print(LOG_SEPARATOR_LINE) if __name__ == '__main__': main()