[Qa-jenkins-scm] [jenkins.debian.net] 01/01: Rewrite email2irc in python, and run it in dry-mode next to the shell version for now
Mattia Rizzolo
mattia at debian.org
Fri Apr 6 12:13:19 UTC 2018
This is an automated email from the git hooks/post-receive script.
mattia pushed a commit to branch master
in repository jenkins.debian.net.
commit 5d189f34f2a7c0912c28cf314ec135296fce3bbb
Author: Mattia Rizzolo <mattia at debian.org>
Date: Fri Apr 6 14:11:54 2018 +0200
Rewrite email2irc in python, and run it in dry-mode next to the shell version for now
It's a step towards #865003
Signed-off-by: Mattia Rizzolo <mattia at debian.org>
---
bin/email2irc.py | 138 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
bin/email2irc.sh | 12 ++++-
2 files changed, 149 insertions(+), 1 deletion(-)
diff --git a/bin/email2irc.py b/bin/email2irc.py
new file mode 100755
index 0000000..5d7eb62
--- /dev/null
+++ b/bin/email2irc.py
@@ -0,0 +1,138 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+#
+# Copyright © 2018 Mattia Rizzolo <mattia at mapreri.org>
+# Based on the email2irc.sh by © 2012-2017 Holger Levsen <holger at layer-acht.org>
+#
+# Released under the GPLv2
+
+import re
+import sys
+import argparse
+import email
+import email.parser
+import email.policy
+from subprocess import run, CalledProcessError
+from email.utils import getaddresses, parseaddr
+
+parser = argparse.ArgumentParser()
+parser.add_argument('-n', '--dry-run', action='store_true')
+parser.add_argument('origin_file', metavar='email',
+ help='file containing the email to be relayed to IRC')
+args = parser.parse_args()
+
+
+def error(*args, **kwargs):
+ print(*args, file=sys.stderr, **kwargs)
+ sys.exit(1)
+
+
+try:
+ with open(args.origin_file, 'rb') as f:
+ ep = email.parser.BytesParser(policy=email.policy.compat32)
+ message = ep.parse(f)
+except FileNotFoundError:
+ error('E: file [{}] not found'.format(args.origin_file))
+
+# From
+origin = parseaddr(message.get('From'))[1]
+if origin is None:
+ error('This email does not contain a "From" header')
+if origin != 'jenkins at jenkins.debian.net':
+ error('E: This email is not from jenkins: {}'.format(message['From']))
+
+# Subject
+subject = message.get('Subject')
+if subject is None:
+ error('E: This email does not contain a "Subject" header')
+subject = subject.replace('\n', ' ')
+
+# X-Jenkins-Job
+jenkins_job = message.get('X-Jenkins-Job')
+if jenkins_job is None:
+ error('E: This email does not originate from a jenkins job')
+
+# Date
+date = message.get('Date')
+if date is None:
+ error('E: This email does not have a "Date" field')
+
+# To
+recipients = [a[1] for a in getaddresses(message.get_all('To', []))]
+if not recipients:
+ error('E: This email does not contain any address in the "To" header')
+channels = []
+for dest in recipients:
+ # look for an address like jenkins+debian-boot at jenkins.debian.net
+ regex = re.compile(r'^jenkins\+(.+)@jenkins\.debian\.net$')
+ m = regex.search(dest)
+ if m:
+ channels.append(m.group(1))
+if not channels:
+ error('E: This email does not contain any IRC channel in its recipients')
+
+# Body
+for part in message.walk():
+ if part.get_content_type() == 'text/plain':
+ # Get only the first line
+ fline = part.get_payload(decode=True).splitlines()[0]
+ fline = fline.decode('utf-8', errors='replace')
+ break
+else:
+ error('E: This email does not contain any text/plain part')
+
+
+# If we got this far, the message is good to go and we got everything we
+# needed.
+
+ircmsg = '{} {}'.format(subject, fline)
+ircmsg = re.sub(r'^Failure', r'Failed ', ircmsg)
+ircmsg = re.sub(r'^Build failed in Jenkins', r'Failed ', ircmsg)
+ircmsg = re.sub(r'^Jenkins build is back to (normal|stable)', r'Fixed ', ircmsg)
+ircmsg = re.sub(r'^Jenkins build became', r'Became', ircmsg)
+ircmsg = re.sub(r'^Jenkins build is unstable', r'Unstable', ircmsg)
+ircmsg = re.sub(r'^Jenkins build is still unstable', r'Still unstable', ircmsg)
+ircmsg = re.sub(r'^Still Failing', r'Still failing', ircmsg)
+ircmsg = re.sub(r' See ', r' ', ircmsg)
+ircmsg = re.sub(r'Changes:', r'', ircmsg)
+ircmsg = re.sub(r'\?page=changes$', r'', ircmsg)
+ircmsg = re.sub(r'/(console|changes)$', r'', ircmsg)
+ircmsg = re.sub(r'display/redirec.*\>$', r'', ircmsg)
+
+print('''
+-----------
+valid email
+-----------
+Date: {date}
+Job: {jenkins_job}
+Channels: {channels}
+Subject: {subject}
+First line: {fline}
+IRC msg: {ircmsg}
+'''.format(date=date, jenkins_job=jenkins_job, channels=channels,
+ subject=subject, fline=fline, ircmsg=ircmsg)
+)
+
+if args.dry_run:
+ print('Running in dry-run mode, not actually notifying kgb')
+ sys.exit()
+
+fail = 0
+for ch in channels:
+ print('Noifying kgb for {}...'.format(ch))
+ try:
+ p = run(['kgb-client', '--conf', '/srv/jenkins/kgb/{}.conf'.format(ch),
+ '--relay-msg', ircmsg], check=True)
+ except CalledProcessError as p:
+ print('E: kgb-client returned an error (code {})'.format(p.returncode),
+ file=sys.stderr)
+ else:
+ print('kgb informed successfully')
+ finally:
+ if p.stderr:
+ print('stderr: [{}]'.format(p.stderr))
+ if p.stdout:
+ print('stdout: [{}]'.format(p.stdout))
+ fail = fail | p.returncode
+
+sys.exit(fail)
diff --git a/bin/email2irc.sh b/bin/email2irc.sh
index d0fbe2e..aeca781 100755
--- a/bin/email2irc.sh
+++ b/bin/email2irc.sh
@@ -24,6 +24,13 @@ debug123() {
fi
}
+rmtmp() {
+ rm -f "$TMPFILE"
+}
+TMPFILE=$(mktemp email2irc-XXXXXXX)
+trap rmtmp INT TERM EXIT
+cat > "$TMPFILE"
+
#
# parse email headers to check if they come from jenkins
#
@@ -94,7 +101,7 @@ while read -r line ; do
debug123 "#6" MY_2ND_LINE $MY_2ND_LINE
fi
fi
-done
+done < "$TMPFILE"
# check that it's a valid job
if [ -z $JENKINS_JOB ] ; then
VALID_MAIL=false
@@ -141,3 +148,6 @@ else
echo -e "----------\nbad luck\n-----------" >> $LOGFILE
fi
+
+# try to run the new script to see how it goes
+/srv/jenkins/bin/email2irc.py -n "$TMPFILE" 2>&1 >> /var/log/jenkins/email-new.log
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/qa/jenkins.debian.net.git
More information about the Qa-jenkins-scm
mailing list