diff options
Diffstat (limited to 'scripts/parse-git-changelog')
-rwxr-xr-x | scripts/parse-git-changelog | 245 |
1 files changed, 245 insertions, 0 deletions
diff --git a/scripts/parse-git-changelog b/scripts/parse-git-changelog new file mode 100755 index 0000000..d74e83b --- /dev/null +++ b/scripts/parse-git-changelog @@ -0,0 +1,245 @@ +#!/usr/bin/python3 + +from __future__ import print_function +import email +import re +import sys + +def role_is_dd(role): + """ + Check if a role is a DD role + """ + return role.startswith("DD") or role.startswith("DN") + +class DakOutput(object): + """ + Output parsed record for dak + """ + def __init__(self, pathname): + self.out = open(pathname, 'w') + self.out.write("Archive: ftp.debian.org\n") + self.out.write("Uploader: Jonathan McDowell <noodles@earth.li>\n") + self.out.write("Cc: keyring-maint@debian.org\n") + + def close(self): + self.out.close() + + def write(self, state, operation): + if operation['action'] == 'remove': + if 'rt-ticket' in operation: + if not role_is_dd(operation['role']): + self.out.write("\nAction: dm-remove\n" + + "Fingerprint: " + operation['key'] + "\n" + + "Reason: RT #" + operation['rt-ticket'] + + ", keyring commit " + state['commit'] + "\n") + elif operation['action'] == 'replace': + if not role_is_dd(operation['role']): + self.out.write("\nAction: dm-migrate\n" + + "From: " + operation['old-key'] + "\n" + + "To: " + operation['new-key'] + "\n" + + "Reason: RT #" + operation['rt-ticket'] + + ", keyring commit " + state['commit'] + "\n") + elif (operation['action'] == 'add' and + role_is_dd(operation['role']) and + operation['notes'] == 'Move from DM keyring'): + if 'rt-ticket' in operation: + self.out.write("\nAction: dm-remove\n" + + "Fingerprint: " + operation['key'] + "\n" + + "Reason: Moved to DD keyring, RT #" + + operation['rt-ticket'] + ", keyring commit " + + state['commit'] + "\n") + + +class RTOutput(object): + """ + Output parsed records for RT + """ + def __init__(self, pathname): + self.out = open(pathname, 'w') + + def close(self): + self.out.close() + + def write(self, state, operation): + if operation['action'] == 'add': + if 'rt-ticket' in operation: + self.out.write("# Commit " + state['commit'] + "\n") + if role_is_dd(operation['role']): + self.out.write("rt edit ticket/" + operation['rt-ticket'] + + " set queue=DSA\n") + elif operation['role'] == 'DM': + self.out.write("rt correspond -s resolved -m " + + "'This key has now been added to the active DM keyring.' " + + operation['rt-ticket'] + "\n") + else: + self.out.write("rt correspond -s resolved -m " + + "'This key has now been added to the " + + operation['role'] + " keyring.' " + + operation['rt-ticket'] + "\n") + elif operation['action'] == 'remove': + if 'rt-ticket' in operation: + self.out.write("# Commit " + state['commit'] + "\n") + if role_is_dd(operation['role']): + self.out.write("rt edit ticket/" + operation['rt-ticket'] + + " set queue=DSA\n") + else: + self.out.write("rt edit ticket/" + operation['rt-ticket'] + + " set queue=Keyring\n" + + "rt correspond -s resolved -m "+ + "'This key has now been removed from the active DM keyring.' " + + operation['rt-ticket'] + "\n") + elif operation['action'] == 'replace': + self.out.write("# Commit " + state['commit'] + "\n") + if role_is_dd(operation['role']): + self.out.write("rt edit ticket/" + operation['rt-ticket'] + + " set queue=Keyring\n" + + "rt correspond -s resolved -m " + + "'Your key has been replaced in the active keyring and LDAP updated with the new fingerprint.' " + + operation['rt-ticket'] + "\n") + else: + self.out.write("rt edit ticket/" + operation['rt-ticket'] + + " set queue=Keyring\n" + + "rt correspond -s resolved -m "+ + "'Your key has been replaced in the active DM keyring.' " + + operation['rt-ticket'] + "\n") + + +class LDAPOutput(object): + """ + Output parsed records for LDAP + """ + def __init__(self, pathname): + self.out = open(pathname, 'w') + + def close(self): + self.out.close() + + def write(self, state, operation): + if operation['action'] == 'replace': + if role_is_dd(operation['role']): + self.out.write(operation['username'] + " " + operation['old-key'] + " ") + self.out.write(operation['new-key'] + "\n") + + +class Parser(object): + def __init__(self): + self.seenrt = {} + + def do_operation(self, state): + operation = email.message_from_string(state['message']) + + if not 'action' in operation: + print("NOTE : " + state['commit'] + " (" + state['summary'] + ") has no action") + return None + + if operation['role'] == 'role': + # At present we don't do anything with role keys + return None + + if 'rt-ticket' in operation and operation['rt-ticket'] in self.seenrt: + print("ERROR: RT " + operation['rt-ticket'] + " used in " + + self.seenrt[operation['rt-ticket']] + " and " + + state['commit']) + else: + self.seenrt[operation['rt-ticket']] = state['commit'] + + if operation['action'] == 'add': + if 'rt-ticket' in operation: + if operation['role'] == 'DM': + try: + bts = operation['BTS'].strip() + bts = re.sub(r'https?://bugs.debian.org/(\d+)', + r'\1-done@bugs.debian.org', bts) + print("NOTE : Mail " + bts + " (new DM).") + except AttributeError: + print('NOTE : DM add for RT ticket %s lacks a BTS ticket.' % operation['RT-Ticket']) + return operation + else: + print("TODO : Add with no RT ticket") + return None + elif operation['action'] == 'remove': + if 'rt-ticket' in operation: + return operation + else: + if 'username' in operation: + username = operation['username'] + elif 'key' in operation: + username = operation['key'] + elif 'old-key' in operation: + username = operation['old-key'] + elif 'subject' in operation: + username = operation['subject'] + print("TODO : Removal for " + username + " without RT ticket.") + return None + elif operation['action'] == 'replace': + if role_is_dd(operation['role']): + if not 'username' in operation: + operation['Username'] = 'FIXME' + return operation + else: + return operation + else: + print("Error: Unknown action " + operation['action']) + return None + + def main(self): + state = {} + opcount = 0 + dak = DakOutput("dak-update") + rt = RTOutput("rt-update") + ldap = LDAPOutput("ldap-update") + + for line in sys.stdin: + line = line.rstrip() + + # Catch the start of a commit + m = re.match("commit (.*)$", line) + if m: + if 'message' in state: + operation = self.do_operation(state) + if operation: + dak.write(state, operation) + rt.write(state, operation) + ldap.write(state, operation) + opcount += 1 + elif 'commit' in state: + if re.match("Import changes sent to keyring", state['summary']): + pass + elif re.match("Update changelog", state['summary']): + pass + else: + print("NOTE : " + state['commit'] + " (" + state['summary'] + ") is not an action.") + state = {} + state['commit'] = m.group(1) + + if not re.match(" ", line): + continue + + line = line[4:] + if not 'inaction' in state: + if not 'summary' in state: + state['summary'] = line + elif re.match("[a-zA-Z]*: ", line): + state['inaction'] = True + state['message'] = line + "\n" + else: + state['message'] += line + "\n" + + # Process the last commit, if applicable + if 'message' in state: + operation = self.do_operation(state) + if operation: + dak.write(state, operation) + rt.write(state, operation) + ldap.write(state, operation) + opcount += 1 + + ldap.close() + rt.close() + dak.close() + + print("Processed " + str(opcount) + " operations.") + +if __name__ == '__main__': + parser = Parser() + parser.main() |