| #!/usr/bin/env python |
| # -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- |
| # |
| # This file is part of the LibreOffice project. |
| # |
| # This Source Code Form is subject to the terms of the Mozilla Public |
| # License, v. 2.0. If a copy of the MPL was not distributed with this |
| # file, You can obtain one at http://mozilla.org/MPL/2.0/. |
| # |
| |
| import argparse |
| import datetime |
| import time |
| import email |
| import email.mime.text |
| import json |
| import os |
| import subprocess |
| import sh |
| import smtplib |
| import sys |
| |
| def get_daily_query(status, project): |
| return 'project:%s branch:master status:%s -age:%dh' % (project, status, args['age']) |
| |
| def get_digest(query): |
| digest = '' |
| freshers = '' |
| do_module = [] |
| about = '' |
| |
| # we want first time contributors on new changes for core |
| do_fresh = (query.split(':')[1].split(' ')[0] == 'core' and |
| query.split(':')[3].split(' ')[0] == 'open' and |
| query.split(':')[3].split(' ')[1] == '-age' ) |
| |
| if do_fresh: |
| all_users = init_freshers() |
| do_module = ['--files', '--patch-sets'] |
| |
| for line in subprocess.check_output(['ssh', args['gerrit'], 'gerrit', 'query'] + do_module + |
| ['--format=JSON','--', "'" + query +"'"]).strip().splitlines(): |
| change = json.loads(line) |
| if 'url' in change.keys(): |
| if do_fresh: # we are in new changes |
| fpaths = (set([fileobj['file'] for pset in change['patchSets'] |
| for fileobj in pset['files']])) |
| fpaths.remove('/COMMIT_MSG') |
| # we assume gerrit replies with no leading slash |
| # if no subfolder, module is "build" |
| about = '\n about module ' + ', '.join(sorted(set([p.split('/')[0] |
| if '/' in p else 'build' for p in fpaths]))) |
| |
| if do_fresh and change['owner']['name'].encode('utf8') not in all_users: |
| freshers += '+ %s\n in %s from %s%s\n' % (change['subject'][:73], |
| change['url'], change['owner']['name'], about) |
| else: |
| digest += '+ %s\n in %s from %s%s\n' % (change['subject'][:73], |
| change['url'], change['owner']['name'], about) |
| if freshers != '': |
| digest = ('~~~~ First time contributors doing great things! ~~~~\n' + freshers + |
| "~~~~ End of freshness ~~~~\n\n" + digest ) |
| if digest == '': |
| digest = 'None' |
| return digest |
| |
| |
| def init_freshers(): |
| repo_dir='/var/tmp/core.git' |
| if not os.path.exists(repo_dir):os.makedirs(repo_dir) |
| os.chdir(repo_dir) |
| |
| if not os.path.exists(os.path.join(repo_dir,'config')): |
| subprocess.call(['git','clone','--bare','git://gerrit.libreoffice.org/core',repo_dir]) |
| else: |
| subprocess.call(['git','fetch','origin']) |
| return subprocess.check_output(['git','shortlog','-s','master']) |
| |
| |
| def get_project_body(project): |
| none = True |
| |
| body = ('* Open changes on master for project %s changed in the last %d hours:\n\n' |
| % (project, args['age'])) |
| dig = get_digest(get_daily_query('open', project)) |
| if dig != 'None': none = False |
| body += dig |
| |
| body += ('\n\n* Merged changes on master for project %s changed in the last %d hours:\n\n' |
| % (project, args['age'])) |
| dig = get_digest(get_daily_query('merged', project)) |
| if dig != 'None': none = False |
| body += dig |
| |
| body += ('\n\n* Abandoned changes on master for project %s changed in the last %d hours:\n\n' |
| % (project, args['age'])) |
| dig = get_digest(get_daily_query('abandoned', project)) |
| if dig != 'None': none = False |
| body += dig |
| |
| body += '\n\n* Open changes needing tweaks, but being untouched for more than a week:\n\n' |
| dig = get_digest('project:%s branch:master status:open (label:Code-Review<=-1 OR label:Verified<=-1) age:1w' % project) |
| if dig != 'None': none = False |
| body += dig |
| |
| if none: return "" |
| else: return body |
| |
| def send_message_for_project(project): |
| now = datetime.datetime.now() |
| nothing = 'Nothing moved in the project for the last %d hours' % args['age'] |
| body = 'Moin!\n\n' |
| |
| if project == 'submodules': |
| dict = get_project_body('dictionaries') |
| tran = get_project_body('translations') |
| help = get_project_body('help') |
| |
| if dict + tran + help == "": return 'Nothing' |
| |
| body += '\n\n~~~~~~ Project dictionaries ~~~~~~\n\n' |
| body += dict if bool(dict) else nothing |
| body += '\n\n~~~~~~ Project translations ~~~~~~\n\n' |
| body += tran if bool(tran) else nothing |
| body += '\n\n~~~~~~ Project help ~~~~~~\n\n' |
| body += help if bool(help) else nothing |
| else: |
| proj = get_project_body(project) |
| if proj == "": return 'Nothing' |
| body += proj |
| |
| body += ''' |
| |
| Best, |
| |
| Your friendly LibreOffice Gerrit Digest Mailer |
| |
| Note: The bot generating this message can be found and improved here: |
| https://gerrit.libreoffice.org/gitweb?p=dev-tools.git;a=blob;f=gerritbot/send-daily-digest''' |
| msg = email.mime.text.MIMEText(body, 'plain', 'UTF-8') |
| msg['From'] = msg_from |
| msg['To'] = msg_to[0] |
| msg['Cc'] = ', '.join(msg_to[1:]) # Works only if at least 2 items in tuple |
| msg['Date'] = email.utils.formatdate(time.mktime((now.timetuple()))) |
| msg['Subject'] = 'LibreOffice Gerrit News for %s on %s' % (project, now.date().isoformat()) |
| msg['Reply-To'] = msg_to[0] |
| msg['X-Mailer'] = 'LibreOfficeGerritDigestMailer 1.1' |
| |
| server.sendmail(msg_from, msg_to, str(msg)) |
| |
| return project |
| |
| if __name__ == '__main__': |
| parser = argparse.ArgumentParser('gerrit daily digest generator') |
| parser.add_argument('-g', '--gerrit', help='(i. e. logerrit or gerrit.libreoffice.org, use the alias in your ~/.ssh(config with your public key)', required=True) |
| parser.add_argument('-r', '--repo', help='(A single project from gerrit (core, ...) or "submodules" (... of core) or "all" (core + dev-tools + submodules)', required=False, default='all') |
| parser.add_argument('-a', '--age', help='(A number expressed in hours.)', required=False, default=25) |
| args=vars(parser.parse_args()) |
| msg_from = 'gerrit@libreoffice.org' |
| msg_to = ['libreoffice@lists.freedesktop.org', 'qa@fr.libreoffice.org'] |
| server = smtplib.SMTP('localhost') |
| |
| if args['repo'] == 'all': |
| send_message_for_project('core') |
| send_message_for_project('submodules') |
| send_message_for_project('dev-tools') |
| else: |
| send_message_for_project(args['repo']) |
| server.quit() |
| |
| # vim: set et sw=4 ts=4: |