[OS-BUILD PATCH] redhat: forward-port genlog.py updates from c9s

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Jan Stancek <jstancek@xxxxxxxxxx>

redhat: forward-port genlog.py updates from c9s

This is forward-port of c9s commit:
b9e094da37a1 ("redhat: rewrite genlog and support Y- tags")

It combines various parse functions into a common function
that goes over list of tag:regex pairs, which makes parsing
and adding new tags simpler. It also updates regexes to be
aligned with ones used by webhooks.

This is primarily for future RHEL downstreams, so I kept the
script identical to c9s.

Signed-off-by: Jan Stancek <jstancek@xxxxxxxxxx>

diff --git a/redhat/scripts/genspec/genlog.py b/redhat/scripts/genspec/genlog.py
index blahblah..blahblah 100755
--- a/redhat/scripts/genspec/genlog.py
+++ b/redhat/scripts/genspec/genlog.py
@@ -1,143 +1,132 @@
 #!/usr/bin/python3
-#
-# This script parses a git log from stdin, which should be given with:
-# $ git log [<options>] -z --format="- %s (%an)%n%b" [<range>] [[--] <path>...] | ...
-# And then outputs to stdout a trimmed changelog for use with rpm packaging
-#
-# Author: Herton R. Krzesinski <herton@xxxxxxxxxx>
-# Copyright (C) 2021 Red Hat, Inc.
-#
-# This software may be freely redistributed under the terms of the GNU
-# General Public License (GPL).
-
-"""Parses a git log from stdin, and output a log entry for an rpm."""
+# SPDX-License-Identifier: GPL-2.0-only
+# Copyright (C) 2023 Red Hat, Inc.
+
+"""Parses git log from stdin, expecting format of:
+$ git log [<options>] -z --format="- %s (%an)%n%N%n^^^NOTES-END^^^%n%b" [<range>] [[--] <path>...] | ...
+and prints changelog output to stdout."""
 
 import re
 import sys
 
-def find_ticket_in_line(line, prefix, tkt_re, tkt_groups):
-    """Return ticket referenced in the given line"""
-    _tkts = set()
-    if not line.startswith(f"{prefix}: "):
-        return _tkts
-    for match in tkt_re.finditer(line[len(f"{prefix}:"):]):
-        for group in tkt_groups:
-            if match.group(group):
-                tid = match.group(group).strip()
-                _tkts.add(tid)
-    return _tkts
-
-def find_bz_in_line(line, prefix):
-    bznum_re = re.compile(r'(?P<bug_ids> \d{4,8})|'
-        r'( http(s)?://bugzilla\.redhat\.com/(show_bug\.cgi\?id=)?(?P<url_bugs>\d{4,8}))')
-    return find_ticket_in_line(line, prefix, bznum_re, [ 'bug_ids', 'url_bugs' ])
-
-def find_ji_in_line(line, prefix):
-    ji_re = re.compile(r' https://issues\.redhat\.com/(?:browse|projects/RHEL/issues)/(?P<jira_id>RHEL-\d{1,8})\s*$')
-    return find_ticket_in_line(line, prefix, ji_re, [ 'jira_id' ])
-
-def find_cve_in_line(line):
-    """Return cve number from properly formated CVE: line."""
-    # CVEs must begin with 'CVE: '
-    cve_set = set()
-    if not line.startswith("CVE: "):
-        return cve_set
-    _cves = line[len("CVE: "):].split()
-    pattern = "(?P<cve>CVE-[0-9]+-[0-9]+)"
-    cve_re = re.compile(pattern)
-    for cve_item in _cves:
-        cve = cve_re.match(cve_item)
-        if cve:
-            cve_set.add(cve.group('cve'))
-    return cve_set
-
-
-def parse_commit(commit):
-    """Extract metadata from a commit log message."""
-    lines = commit.split('\n')
-
-    # Escape '%' as it will be used inside the rpm spec changelog
-    log_entry = lines[0].replace("%","%%")
 
-    cve_set = set()
-    bug_set = set()
-    zbug_set = set()
-    jira_set = set()
-    zjira_set = set()
-    for line in lines[1:]:
-        # Metadata in git notes has priority over commit log
-        # If we found any BZ/ZBZ/JIRA/ZJIRA/CVE in git notes,
-        # we ignore the commit log
-        if line == "^^^NOTES-END^^^":
-            if bug_set or zbug_set or jira_set or zjira_set or cve_set:
-                break
+# CommitTags and parse_commit() in kmt and genlog.py should match
+class CommitTags:
+    tag_patterns = {
+        'Bugzilla': [
+            r'(\d{4,8})\s*$',
+            r'https?://bugzilla\.redhat\.com/(?:show_bug\.cgi\?id=)?(\d{4,8})',
+        ],
+        'JIRA': [r'https://issues\.redhat\.com/(?:browse|projects/RHEL/issues)/(RHEL-\d{1,8})'],
+        'CVE': [r'(CVE-\d{4}-\d{4,7})'],
+        'MR': [r'(.*)'],
+        'Y-Commit': [r'([0-9a-fA-F]+)'],
+        'Patchwork-id': [r'(.*)'],
+        'Patchwork-instance': [r'(.*)'],
+    }
+    tag_patterns['Y-Bugzilla'] = tag_patterns['Bugzilla']
+    tag_patterns['Z-Bugzilla'] = tag_patterns['Bugzilla']
+    tag_patterns['Y-JIRA'] = tag_patterns['JIRA']
+    tag_patterns['Z-JIRA'] = tag_patterns['JIRA']
+    tag_patterns['O-JIRA'] = tag_patterns['JIRA']
+
+    compiled_patterns = {}
+    for tag_name, tag_pattern_list in tag_patterns.items():
+        tag_pattern_list.append(r'(N/A)')
+        compiled_patterns[tag_name] = []
+        for tag_pattern in tag_pattern_list:
+            pattern = r'^' + tag_name + ': ' + tag_pattern + r'\s*$'
+            tag_regex = re.compile(pattern, re.MULTILINE)
+            compiled_patterns[tag_name].append(tag_regex)
+
+    def __init__(self, input_str):
+        self.parse_tags(input_str)
+
+    def get_tag_values(self, tag_name):
+        if tag_name not in CommitTags.tag_patterns:
+            raise Exception('Unsupported tag name: ' + tag_name)
+        return self.tag_dict[tag_name]
+
+    def override_by(self, other_commit_tags):
+        for tag_name, tag_set in other_commit_tags.tag_dict.items():
+            if tag_set:
+                if tag_set == set(['N/A']):
+                    self.tag_dict[tag_name] = set()
+                else:
+                    self.tag_dict[tag_name] = set(tag_set)
+
+    def parse_tags(self, input_str):
+        tag_values = {}
+        for tag_name, tag_pattern_list in CommitTags.compiled_patterns.items():
+            tag_values[tag_name] = set()
+            for tag_regex in tag_pattern_list:
+                for value in tag_regex.findall(input_str):
+                    tag_values[tag_name].add(value)
+        self.tag_dict = tag_values
+
+    def convert_to_y_tags(self):
+        if self.tag_dict['Z-Bugzilla'] or self.tag_dict['Z-JIRA']:
+            tmp = self.tag_dict['Bugzilla']
+            self.tag_dict['Bugzilla'] = self.tag_dict['Z-Bugzilla']
+            self.tag_dict['Y-Bugzilla'] = tmp
+            self.tag_dict['Z-Bugzilla'] = set()
+
+            tmp = self.tag_dict['JIRA']
+            self.tag_dict['JIRA'] = self.tag_dict['Z-JIRA']
+            self.tag_dict['Y-JIRA'] = tmp
+            self.tag_dict['Z-JIRA'] = set()
+
+    def get_changelog_str(self):
+        chnglog = []
+        tickets = sorted(self.tag_dict['Bugzilla']) + sorted(self.tag_dict['JIRA'])
+        if self.tag_dict['Y-Bugzilla'] or self.tag_dict['Y-JIRA']:
+            tickets = tickets + sorted(self.tag_dict['Y-Bugzilla']) + sorted(self.tag_dict['Y-JIRA'])
+        if tickets:
+            chnglog.append('[' + ' '.join(tickets) + ']')
+        if self.tag_dict['CVE']:
+            chnglog.append('{' + ' '.join(self.tag_dict['CVE']) + '}')
+        return ' '.join(chnglog)
+
+    def get_resolved_tickets(self):
+        ret = set()
+        for ticket in sorted(self.tag_dict['Bugzilla']) + sorted(self.tag_dict['JIRA']):
+            if ticket.isnumeric():
+                ticket = 'rhbz#' + ticket
+            ret.add(ticket)
+        return ret
 
-        # Process Bugzilla and ZStream Bugzilla entries
-        bug_set.update(find_bz_in_line(line, 'Bugzilla'))
-        zbug_set.update(find_bz_in_line(line, 'Z-Bugzilla'))
 
-        # Grab CVE tags if they are present
-        cve_set.update(find_cve_in_line(line))
+def parse_commit(commit):
+    if '^^^NOTES-END^^^' in commit:
+        input_notes, input_commit = commit.split('^^^NOTES-END^^^')
+    else:
+        input_notes = ''
+        input_commit = commit
 
-        # Process Jira issues
-        jira_set.update(find_ji_in_line(line, 'JIRA'))
-        zjira_set.update(find_ji_in_line(line, 'Z-JIRA'))
+    tags = CommitTags(input_commit)
+    if input_notes:
+        notes_tags = CommitTags(input_notes)
+        notes_tags.convert_to_y_tags()
+        tags.override_by(notes_tags)
 
-    return (log_entry, cve_set, bug_set, zbug_set, jira_set, zjira_set)
+    return tags
 
 
 if __name__ == "__main__":
-    all_bzs = set()
-    all_zbzs = set()
-    all_jiras = set()
-    all_zjiras = set()
+    all_resolved = set()
     commits = sys.stdin.read().split('\0')
     for c in commits:
         if not c:
             continue
-        log_item, cves, bugs, zbugs, jiras, zjiras = parse_commit(c)
-        entry = f"{log_item}"
-        if bugs or zbugs or jiras or zjiras:
-            entry += " ["
-            if zbugs:
-                entry += " ".join(sorted(zbugs))
-                all_zbzs.update(zbugs)
-            if bugs:
-                entry += " " if zbugs else ""
-                entry += " ".join(sorted(bugs))
-                all_bzs.update(bugs)
-            if jiras:
-                entry += " " if bugs or zbugs else ""
-                entry += " ".join(sorted(jiras))
-                all_jiras.update(jiras)
-            if zjiras:
-                entry += " " if bugs or zbugs or jiras else ""
-                entry += " ".join(sorted(zjiras))
-                all_zjiras.update(zjiras)
-            entry += "]"
-        if cves:
-            entry += " {" + " ".join(sorted(cves)) + "}"
+        # Escape '%' as it will be used inside the rpm spec changelog
+        entry_pos = c.find('\n')
+        entry = c[:entry_pos].replace("%", "%%")
+
+        tags = parse_commit(c)
+        chnglog = tags.get_changelog_str()
+        if chnglog:
+            entry = entry + ' ' + chnglog
         print(entry)
+        all_resolved = all_resolved.union(tags.get_resolved_tickets())
 
-    # If we are doing Z-Stream work, we are addressing Z-Stream tickets
-    # and not Y-Stream tickets, so we must make sure to list on Resolves
-    # line only the Z-Stream tickets
-    resolved_bzs = set()
-    resolved_jiras = set()
-    if all_zbzs or all_zjiras:
-        resolved_bzs = all_zbzs
-        resolved_jiras = all_zjiras
-    else:
-        resolved_bzs = all_bzs
-        resolved_jiras = all_jiras
-    print("Resolves: ", end="")
-    for i, bzid in enumerate(sorted(resolved_bzs)):
-        if i:
-            print(", ", end="")
-        print(f"rhbz#{bzid}", end="")
-    for j, jid in enumerate(sorted(resolved_jiras)):
-        if j or resolved_bzs:
-           print(", ", end="")
-        print(f"{jid}", end="")
-    print("\n")
-
+    print('Resolves: ' + ', '.join(sorted(all_resolved)) + '\n')

--
https://gitlab.com/cki-project/kernel-ark/-/merge_requests/2928
--
_______________________________________________
kernel mailing list -- kernel@xxxxxxxxxxxxxxxxxxxxxxx
To unsubscribe send an email to kernel-leave@xxxxxxxxxxxxxxxxxxxxxxx
Fedora Code of Conduct: https://docs.fedoraproject.org/en-US/project/code-of-conduct/
List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines
List Archives: https://lists.fedoraproject.org/archives/list/kernel@xxxxxxxxxxxxxxxxxxxxxxx
Do not reply to spam, report it: https://pagure.io/fedora-infrastructure/new_issue




[Index of Archives]     [Fedora General Discussion]     [Older Fedora Users Archive]     [Fedora Advisory Board]     [Fedora Security]     [Fedora Devel Java]     [Fedora Legacy]     [Fedora Desktop]     [ATA RAID]     [Fedora Marketing]     [Fedora Mentors]     [Fedora Package Announce]     [Fedora Package Review]     [Fedora Music]     [Fedora Packaging]     [Centos]     [Fedora SELinux]     [Coolkey]     [Yum Users]     [Tux]     [Yosemite News]     [KDE Users]     [Fedora Art]     [Fedora Docs]     [USB]     [Asterisk PBX]

  Powered by Linux