ansible/roles/git/hooks/files/post-receive-alternativearch
Pierre-Yves Chibon 6e82268613 git/hooks: Start making the hooks crash less on rhel8/python3
Signed-off-by: Pierre-Yves Chibon <pingou@pingoured.fr>
2020-06-06 21:17:05 +02:00

216 lines
6.1 KiB
Python
Executable file

#! /usr/bin/env python
"""
This is a git hook meant to warn the alternative arches folks about package
that turned off building on alternative arches.
"""
from __future__ import print_function
import os
import smtplib
import subprocess
import sys
from email.mime.text import MIMEText
abspath = os.path.abspath(os.environ['GIT_DIR'])
PATTERNS = ('+ExclusiveArch:', '+ExcludeArch:', '+%ifarch', '+%ifnarch',
'-ExclusiveArch:', '-ExcludeArch:', '-%ifarch', '-%ifnarch')
FROM_EMAIL = 'githook-noreply@fedoraproject.org'
TO_MAIL = 'arch-excludes@lists.fedoraproject.org'
CGIT_URL = 'https://src.fedoraproject.org/cgit/%s/commit/?id=%s'
EMAIL_SEND = True
SMTP_SERVER = 'localhost'
SMTP_PORT = 25
DEBUG = False
TEXT = u"""
The package %(pkg)s has added or updated architecture specific content in its
spec file (ExclusiveArch/ExcludeArch or %%ifarch/%%ifnarch) in commit(s):
%(url)s.
Change:
%(change)s
Thanks.
Full change:
============
%(full_change)s
"""
def read_output(cmd, abspath, input=None, keepends=False, **kw):
""" Read the output from the given command to run """
if input:
stdin = subprocess.PIPE
else:
stdin = None
if DEBUG:
print('command called:', cmd)
procs = subprocess.Popen(
cmd,
stdin=stdin,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
cwd=abspath,
universal_newlines=True,
**kw)
(out, err) = procs.communicate(input)
retcode = procs.wait()
if retcode:
print('ERROR: %s =-- %s' % (cmd, retcode))
print(out)
print(err)
if not keepends:
out = out.rstrip('\n\r')
return out
def read_git_output(args, abspath, input=None, keepends=False, **kw):
"""Read the output of a Git command."""
return read_output(
['git'] + args, abspath, input=input, keepends=keepends, **kw)
def read_git_lines(args, abspath, keepends=False, **kw):
"""Return the lines output by Git command.
Return as single lines, with newlines stripped off."""
return read_git_output(
args, abspath, keepends=keepends, **kw
).splitlines(keepends)
def get_revs_between(oldrev, newrev, abspath, refname):
""" Yield revisions between HEAD and BASE. """
cmd = ['rev-list', '%s...%s' % (oldrev, newrev)]
if set(newrev) == set('0'):
cmd = ['rev-list', '%s' % oldrev]
elif set(oldrev) == set('0') or set(oldrev) == set('^0'):
head = get_default_branch(abspath)
cmd = ['rev-list', '%s' % newrev, '^%s' % head]
if head in refname:
cmd = ['rev-list', '%s' % newrev]
return read_git_lines(cmd, abspath)
def get_default_branch(abspath):
""" Return the default branch of a repo. """
cmd = ['rev-parse', '--abbrev-ref', 'HEAD']
out = read_git_lines(cmd, abspath)
if out:
return out[0]
else:
return 'master'
def send_email(text, subject, to_mail): # pragma: no cover
''' Send an email with the specified information.
:arg text: the content of the email to send
:arg subject: the subject of the email
:arg to_mail: a string representing a list of recipient separated by a
coma
'''
if not to_mail:
return
from_email = FROM_EMAIL
if not EMAIL_SEND:
print('******EMAIL******')
print('From: %s' % from_email)
print('To: %s' % to_mail)
print('Subject: %s' % subject)
print('Contents:')
print(text.encode('utf-8'))
print('*****/EMAIL******')
return
smtp = smtplib.SMTP(SMTP_SERVER, SMTP_PORT)
for mailto in to_mail.split(','):
msg = MIMEText(text.encode('utf-8'), 'plain', 'utf-8')
msg['Subject'] = subject
msg['From'] = from_email
# Send the message via our own SMTP server, but don't include the
# envelope header.
msg['To'] = mailto
try:
smtp.sendmail(
from_email,
[mailto],
msg.as_string())
except smtplib.SMTPException as err:
pagure.LOG.exception(err)
smtp.quit()
return msg
def run_as_post_receive_hook():
''' Check what was changed in the commit(s) and warn the alternative-arch
folks if either ExclusiveArch or ExcludesArch are changed.
'''
for line in sys.stdin:
if DEBUG:
print('Received:', line.strip())
(oldrev, newrev, refname) = line.strip().split(' ', 2)
# Skip all the branches that are not master and do not start with an 'f'
# ie: personal branches and epel
if not refname.startswith(('refs/heads/master', 'refs/heads/f')):
continue
new_commits_list = get_revs_between(oldrev, newrev, abspath, refname)
if DEBUG:
print('List of commits:', new_commits_list)
full_change = u''
exclude_arch = {}
for commit in new_commits_list:
if DEBUG:
print('Diff of commit:', commit)
full_change += '\n'
for line in read_git_lines(['show', commit], abspath):
full_change += '%s\n' % line
if DEBUG:
print(line)
if line.strip().startswith(PATTERNS):
exclude_arch[commit] = line.strip()
if DEBUG:
print('Commit %s selected' % commit)
if exclude_arch:
print('* Notifying alternative-arch people')
package = '/'.join(abspath.rsplit(os.path.sep, 2)[-2:])
if DEBUG:
print('Package:', package)
links = []
diffs = exclude_arch.values()
for commit in exclude_arch:
links.append(
CGIT_URL % (package, commit)
)
send_email(
text=TEXT % dict(
pkg=package, url='\n'.join(links), change="\n".join(diffs),
full_change=full_change
),
subject='Architecture specific change in %s' % package,
to_mail=TO_MAIL
)
if __name__ == '__main__':
run_as_post_receive_hook()