1e01aa904Sopenharmony_ci#!/usr/bin/env python
2e01aa904Sopenharmony_ci# SPDX-License-Identifier: LGPL-2.0-or-later
3e01aa904Sopenharmony_ci#
4e01aa904Sopenharmony_ci# -*- mode: python -*-
5e01aa904Sopenharmony_ci#
6e01aa904Sopenharmony_ci# This python program has been copied from
7e01aa904Sopenharmony_ci# https://github.com/GNOME/gnet/blob/master/gen-changelog.py
8e01aa904Sopenharmony_ci#
9e01aa904Sopenharmony_ci# It has been authored by Edward Hervey, of GStreamer fame.  I have
10e01aa904Sopenharmony_ci# asked his permission to copy it and re-use it here, as part of the
11e01aa904Sopenharmony_ci# Libabigail project.  He granted me the permission to distribute the
12e01aa904Sopenharmony_ci# program under the terms of the GNU Lesser Public License as
13e01aa904Sopenharmony_ci# published by the Free Software Foundaion; either version 2, or (at
14e01aa904Sopenharmony_ci# your option) any later version.
15e01aa904Sopenharmony_ci#
16e01aa904Sopenharmony_ci
17e01aa904Sopenharmony_ciimport sys
18e01aa904Sopenharmony_ciimport subprocess
19e01aa904Sopenharmony_ciimport re
20e01aa904Sopenharmony_ci
21e01aa904Sopenharmony_ci# Makes a GNU-Style ChangeLog from a git repository
22e01aa904Sopenharmony_ci# Handles git-svn repositories also
23e01aa904Sopenharmony_ci
24e01aa904Sopenharmony_ci# Arguments : same as for git log
25e01aa904Sopenharmony_cirelease_refs={}
26e01aa904Sopenharmony_ci
27e01aa904Sopenharmony_cidef process_commit(lines, files):
28e01aa904Sopenharmony_ci    # DATE NAME
29e01aa904Sopenharmony_ci    # BLANK LINE
30e01aa904Sopenharmony_ci    # Subject
31e01aa904Sopenharmony_ci    # BLANK LINE
32e01aa904Sopenharmony_ci    # ...
33e01aa904Sopenharmony_ci    # FILES
34e01aa904Sopenharmony_ci    fileincommit = False
35e01aa904Sopenharmony_ci    lines = [x.strip() for x in lines if x.strip() and not x.startswith('git-svn-id')]
36e01aa904Sopenharmony_ci    files = [x.strip() for x in files if x.strip()]
37e01aa904Sopenharmony_ci    for l in lines:
38e01aa904Sopenharmony_ci        if l.startswith('* '):
39e01aa904Sopenharmony_ci            fileincommit = True
40e01aa904Sopenharmony_ci            break
41e01aa904Sopenharmony_ci
42e01aa904Sopenharmony_ci    top_line = lines[0]
43e01aa904Sopenharmony_ci    subject_line_index = 0 if lines[1].startswith('*') else 1;
44e01aa904Sopenharmony_ci    first_cl_body_line_index = 0;
45e01aa904Sopenharmony_ci
46e01aa904Sopenharmony_ci    for i in range(1, len(lines)):
47e01aa904Sopenharmony_ci        if lines[i].startswith('*'):
48e01aa904Sopenharmony_ci            first_cl_body_line_index = i
49e01aa904Sopenharmony_ci            break;
50e01aa904Sopenharmony_ci
51e01aa904Sopenharmony_ci    # Clean up top line of ChangeLog entry:
52e01aa904Sopenharmony_ci    fields = top_line.split(' ')
53e01aa904Sopenharmony_ci
54e01aa904Sopenharmony_ci    # 1. remove the time and timezone stuff in "2008-05-13 07:10:28 +0000  name"
55e01aa904Sopenharmony_ci    if fields[2].startswith('+') or fields[2].startswith('-'):
56e01aa904Sopenharmony_ci      del fields[2]
57e01aa904Sopenharmony_ci    if fields[1][2] == ':' and fields[1][5] == ':':
58e01aa904Sopenharmony_ci      del fields[1]
59e01aa904Sopenharmony_ci
60e01aa904Sopenharmony_ci    # 2. munge at least my @src.gnome.org e-mail address...
61e01aa904Sopenharmony_ci    if fields[-1] == '<tpm@src.gnome.org>':
62e01aa904Sopenharmony_ci      fields[-1] = '<tim@centricular.net>'
63e01aa904Sopenharmony_ci
64e01aa904Sopenharmony_ci    top_line = ' '.join(fields)
65e01aa904Sopenharmony_ci    print(top_line.strip())
66e01aa904Sopenharmony_ci    print()
67e01aa904Sopenharmony_ci
68e01aa904Sopenharmony_ci    if subject_line_index > 0:
69e01aa904Sopenharmony_ci        print('\t%s' % lines[subject_line_index].strip())
70e01aa904Sopenharmony_ci
71e01aa904Sopenharmony_ci    if not fileincommit:
72e01aa904Sopenharmony_ci        for f in files:
73e01aa904Sopenharmony_ci            print('\t* %s:' % f.strip())
74e01aa904Sopenharmony_ci        print()
75e01aa904Sopenharmony_ci
76e01aa904Sopenharmony_ci    if first_cl_body_line_index > 0:
77e01aa904Sopenharmony_ci        for l in lines[first_cl_body_line_index:]:
78e01aa904Sopenharmony_ci            if l.startswith('Signed-off-by:'):
79e01aa904Sopenharmony_ci                continue
80e01aa904Sopenharmony_ci            print('\t%s' % l.strip())
81e01aa904Sopenharmony_ci        print()
82e01aa904Sopenharmony_ci
83e01aa904Sopenharmony_cidef output_commits():
84e01aa904Sopenharmony_ci    cmd = ['git', 'log', '--pretty=format:--START-COMMIT--%H%n%ai  %an <%ae>%n%n%s%n%b%n--END-COMMIT--',
85e01aa904Sopenharmony_ci           '--date=short', '--name-only']
86e01aa904Sopenharmony_ci
87e01aa904Sopenharmony_ci    start_tag = find_start_tag()
88e01aa904Sopenharmony_ci
89e01aa904Sopenharmony_ci    if start_tag is None:
90e01aa904Sopenharmony_ci        cmd.extend(sys.argv[1:])
91e01aa904Sopenharmony_ci    else:
92e01aa904Sopenharmony_ci        cmd.extend(["%s..HEAD" % (start_tag)])
93e01aa904Sopenharmony_ci
94e01aa904Sopenharmony_ci    p = subprocess.Popen(args=cmd, shell=False,
95e01aa904Sopenharmony_ci                         stdout=subprocess.PIPE,
96e01aa904Sopenharmony_ci                         text=True)
97e01aa904Sopenharmony_ci    buf = []
98e01aa904Sopenharmony_ci    files = []
99e01aa904Sopenharmony_ci    filemode = False
100e01aa904Sopenharmony_ci    for lin in p.stdout.readlines():
101e01aa904Sopenharmony_ci        if lin.startswith("--START-COMMIT--"):
102e01aa904Sopenharmony_ci            if buf != []:
103e01aa904Sopenharmony_ci                process_commit(buf, files)
104e01aa904Sopenharmony_ci            hash = lin[16:].strip()
105e01aa904Sopenharmony_ci            try:
106e01aa904Sopenharmony_ci                rel = release_refs[hash]
107e01aa904Sopenharmony_ci                print("=== release %d.%d.%d ===\n" % (int(rel[0]), int(rel[1]), int(rel[2])))
108e01aa904Sopenharmony_ci            except:
109e01aa904Sopenharmony_ci                pass
110e01aa904Sopenharmony_ci            buf = []
111e01aa904Sopenharmony_ci            files = []
112e01aa904Sopenharmony_ci            filemode = False
113e01aa904Sopenharmony_ci        elif lin.startswith("--END-COMMIT--"):
114e01aa904Sopenharmony_ci            filemode = True
115e01aa904Sopenharmony_ci        elif filemode == True:
116e01aa904Sopenharmony_ci            files.append(lin)
117e01aa904Sopenharmony_ci        else:
118e01aa904Sopenharmony_ci            buf.append(lin)
119e01aa904Sopenharmony_ci    if buf != []:
120e01aa904Sopenharmony_ci        process_commit(buf, files)
121e01aa904Sopenharmony_ci
122e01aa904Sopenharmony_cidef get_rel_tags():
123e01aa904Sopenharmony_ci    # Populate the release_refs dict with the tags for previous releases
124e01aa904Sopenharmony_ci    reltagre = re.compile("^([a-z0-9]{40}) refs\/tags\/GNET-([0-9]+)[-_.]([0-9]+)[-_.]([0-9]+)")
125e01aa904Sopenharmony_ci
126e01aa904Sopenharmony_ci    cmd = ['git', 'show-ref', '--tags', '--dereference']
127e01aa904Sopenharmony_ci    p = subprocess.Popen(args=cmd, shell=False,
128e01aa904Sopenharmony_ci                         stdout=subprocess.PIPE,
129e01aa904Sopenharmony_ci                         text=True)
130e01aa904Sopenharmony_ci    for lin in p.stdout:
131e01aa904Sopenharmony_ci       match = reltagre.search(lin)
132e01aa904Sopenharmony_ci       if match:
133e01aa904Sopenharmony_ci           (sha, maj, min, nano) = match.groups()
134e01aa904Sopenharmony_ci           release_refs[sha] = (maj, min, nano)
135e01aa904Sopenharmony_ci
136e01aa904Sopenharmony_cidef find_start_tag():
137e01aa904Sopenharmony_ci    starttagre = re.compile("^([a-z0-9]{40}) refs\/tags\/CHANGELOG_START")
138e01aa904Sopenharmony_ci    cmd = ['git', 'show-ref', '--tags']
139e01aa904Sopenharmony_ci    p = subprocess.Popen(args=cmd, shell=False,
140e01aa904Sopenharmony_ci                         stdout=subprocess.PIPE,
141e01aa904Sopenharmony_ci                         text=True)
142e01aa904Sopenharmony_ci    for lin in p.stdout:
143e01aa904Sopenharmony_ci       match = starttagre.search(lin)
144e01aa904Sopenharmony_ci       if match:
145e01aa904Sopenharmony_ci           return match.group(1)
146e01aa904Sopenharmony_ci    return None
147e01aa904Sopenharmony_ci
148e01aa904Sopenharmony_ciif __name__ == "__main__":
149e01aa904Sopenharmony_ci    get_rel_tags()
150e01aa904Sopenharmony_ci    output_commits()
151