diff options
author | Paul Eggleton <paul.eggleton@linux.intel.com> | 2018-03-02 09:09:35 +1300 |
---|---|---|
committer | Paul Eggleton <paul.eggleton@linux.intel.com> | 2018-05-04 23:57:53 +1200 |
commit | 227b9c65af14ab7edfa788b3b33b141a21df78c3 (patch) | |
tree | f2ff3c740996edcd5c7c6e6415683677e79481f3 | |
parent | 735353ebd1171aa6e276654586e57c56f17842d5 (diff) | |
download | openembedded-core-contrib-227b9c65af14ab7edfa788b3b33b141a21df78c3.tar.gz |
rrs_upstream_email: rework
* Use maintenance plans to get layerbranches
* Use from/to/subject and admin contact from maintenance plan
* Use an actual template to render the email (and drop tabulate
dependency)
* Improve grammar in the email text
* Use a single line to represent the most recent commit
Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com>
-rw-r--r-- | requirements.txt | 1 | ||||
-rwxr-xr-x | rrs/tools/rrs_upstream_email.py | 191 | ||||
-rw-r--r-- | settings.py | 5 | ||||
-rw-r--r-- | templates/rrs/report_email.txt | 26 |
4 files changed, 124 insertions, 99 deletions
diff --git a/requirements.txt b/requirements.txt index 5aae2477db..5ca7cf6e9f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -27,4 +27,3 @@ smmap==0.9.0 smmap2==2.0.3 Unidecode==0.4.19 vine==1.1.4 -tabulate==0.7.3 diff --git a/rrs/tools/rrs_upstream_email.py b/rrs/tools/rrs_upstream_email.py index 0dae3629ec..411cf50dda 100755 --- a/rrs/tools/rrs_upstream_email.py +++ b/rrs/tools/rrs_upstream_email.py @@ -3,7 +3,7 @@ # Send email to maintainers about the current status of the recipes. # -# Copyright (C) 2015 Intel Corporation +# Copyright (C) 2015, 2018 Intel Corporation # Author: Aníbal Limón <anibal.limon@linux.intel.com> # # Licensed under the MIT license, see COPYING.MIT for details @@ -12,7 +12,7 @@ import sys import os.path import optparse import logging -from tabulate import tabulate +from collections import namedtuple sys.path.insert(0, os.path.realpath(os.path.join(os.path.dirname(__file__)))) from common import common_setup, get_pv_type, get_logger @@ -21,43 +21,30 @@ from layerindex import utils utils.setup_django() from django.core.mail import EmailMessage +from django.template.loader import get_template +from django.template import Context, Template +from django.core.urlresolvers import reverse +from django.contrib.sites.models import Site import settings from layerindex.models import LayerItem, LayerBranch, Recipe from rrs.models import Maintainer, RecipeMaintainerHistory, RecipeMaintainer, \ - RecipeUpstream, RecipeUpstreamHistory + RecipeUpstream, RecipeUpstreamHistory, MaintenancePlan logger = get_logger('UpstreamEmail', settings) -LAYERBRANCH_NAME = "master" """ Send email with Recipes that need update. """ -def send_email(recipes, repodir, options): - header = """This mail was sent out by Recipe reporting system. - -This message list those recipes which need to be upgraded. If maintainers -believe some of them needn't to upgrade at this time, they can fill -RECIPE_NO_UPDATE_REASON in respective recipe file to ignore this remainder -until newer upstream version was detected. - -Example: -RECIPE_NO_UPDATE_REASON = "Version 2.0 is unstable" - -You can check the detail information at: - -http://recipes.yoctoproject.org/ - -""" - +def send_email(maintplan, recipes, options): upgradable_count = 0 no_upgradable_count = 0 maintainers = Maintainer.objects.all().order_by("name") - table_headers = ['Package', 'Version', 'Upstream version', - 'Maintainer', 'NoUpgradeReason'] - table = [] + RecipeUpgradeLine = namedtuple('RecipeUpgradeLine', ['pn', 'pv', 'pv_upstream', 'maintainer', 'noupgradereason']) + + recipelines = [] for m in maintainers: for recipe in recipes.keys(): recipe_maintainer = recipes[recipe]['maintainer'] @@ -69,50 +56,66 @@ http://recipes.yoctoproject.org/ name_max_len = 20 reason_max_len = 30 - pn = recipe.pn - if len(pn) > pn_max_len: - pn = pn[0:pn_max_len - 3] + "..." - - pv = recipe.pv - if len(pv) > pv_max_len: - pv = pv[0:pv_max_len - 3] + "..." - - pv_up = recipe_upstream.version - if len(pv_up) > pv_max_len: - pv_up = pv_up[0:pv_max_len - 3] + "..." - - name = m.name - if len(name) > name_max_len: - name = name[0:name_max_len - 3] + "..." - - reason = recipe_upstream.no_update_reason - if len(reason) > reason_max_len: - reason = reason[0:reason_max_len - 3] + "..." - - table.append([pn, pv, pv_up, name, reason]) + recipelines.append(RecipeUpgradeLine(recipe.pn, recipe.pv, recipe_upstream.version, m.name, recipe_upstream.no_update_reason)) upgradable_count = upgradable_count + 1 if recipe_upstream.no_update_reason: no_upgradable_count = no_upgradable_count + 1 - body = tabulate(table, table_headers, tablefmt="simple") - - footer = """ -\nUpgradable count: %d\nUpgradable total count: %d\n -The based commit is: - -%s -Any problem, please contact Anibal Limon <anibal.limon@intel.com> -""" % ((upgradable_count - no_upgradable_count), upgradable_count, - utils.runcmd("git log -1", repodir)) - # - subject = options.subject - from_email = options._from - to_email_list = options.to.split(';') - text_content = header + body + footer + commits = [] + fetchdir = settings.LAYER_FETCH_DIR + for item in maintplan.maintenanceplanlayerbranch_set.all(): + layerbranch = item.layerbranch + layer = layerbranch.layer + urldir = layer.get_fetch_dir() + repodir = os.path.join(fetchdir, urldir) + # FIXME this assumes the correct branch is checked out + topcommitdesc = utils.runcmd("git log -1 --oneline", repodir).strip() + commits.append('%s: %s' % (layerbranch.layer.name, topcommitdesc)) + + # Render the subject as a template (to allow a bit of flexibility) + subject = options.subject or maintplan.email_subject + subject_template = Template(subject) + current_site = Site.objects.get_current() + d = Context({ + 'maintplan': maintplan, + 'site': current_site, + }) + subject_content = subject_template.render(d) + + from_email = options._from or maintplan.email_from + if options.to: + to_email_list = options.to.split(';') + elif maintplan.email_to: + to_email_list = maintplan.email_to.split(';') + else: + to_email_list = [] + + if not subject: + logger.error('No subject specified in maintenance plan %s and none specified on command line' % maintplan.name) + sys.exit(1) + if not from_email: + logger.error('No sender email address specified in maintenance plan %s and none specified on command line' % maintplan.name) + sys.exit(1) + if not to_email_list: + logger.error('No recipient email address specified in maintenance plan %s and none specified on command line' % maintplan.name) + sys.exit(1) - msg = EmailMessage(subject, text_content, from_email, to_email_list) + plaintext = get_template('rrs/report_email.txt') + site_url = 'http://' + current_site.domain + reverse('rrs_frontpage') + d = Context({ + 'maintplan': maintplan, + 'site': current_site, + 'site_url': site_url, + 'upgradable_count': (upgradable_count - no_upgradable_count), + 'total_upgradable_count': upgradable_count, + 'commits': commits, + 'recipelines': recipelines, + }) + text_content = plaintext.render(d) + + msg = EmailMessage(subject_content, text_content, from_email, to_email_list) msg.send() def main(): @@ -120,14 +123,12 @@ def main(): usage = """ %prog [options]""") - parser.add_option("-l", "--layername", - action="store", dest="layername", default=settings.CORE_LAYER_NAME) parser.add_option("-s", "--subject", - action="store", dest="subject", default=settings.RRS_EMAIL_SUBJECT) + action="store", dest="subject", help='Override email subject') parser.add_option("-f", "--from", - action="store", dest="_from", default=settings.RRS_EMAIL_FROM) + action="store", dest="_from", help='Override sender address') parser.add_option("-t", "--to", - action="store", dest="to", default=settings.RRS_EMAIL_TO) + action="store", dest="to", help='Override recipient address') parser.add_option("-d", "--debug", help = "Enable debug output", action="store_const", const=logging.DEBUG, dest="loglevel", default=logging.INFO) @@ -137,36 +138,40 @@ def main(): options, args = parser.parse_args(sys.argv) - recipes = {} - layer = LayerItem.objects.filter(name = options.layername)[0] - # get recipes for send email - layerbranch = layer.get_layerbranch(LAYERBRANCH_NAME) - recipe_upstream_history = RecipeUpstreamHistory.get_last() - if recipe_upstream_history is None: - logger.warn('I don\'t have Upstream information yet, run update.py script') - sys.exit(1) - - recipe_maintainer_history = RecipeMaintainerHistory.get_last() - if recipe_maintainer_history is None: - logger.warn('I don\'t have Maintainership information yet,' + - ' run rrs_maintainer_history.py script') + maintplans = MaintenancePlan.objects.filter(email_enabled=True) + if not maintplans.exists(): + logger.error('No maintenance plans with email enabled were found') sys.exit(1) - for recipe in Recipe.objects.filter(layerbranch = layerbranch): - recipe_upstream_query = RecipeUpstream.objects.filter(recipe = - recipe, history = recipe_upstream_history) - if recipe_upstream_query and recipe_upstream_query[0].status == 'N': - recipes[recipe] = {} - - recipe_maintainer = RecipeMaintainer.objects.filter(recipe = - recipe, history = recipe_maintainer_history)[0] - recipes[recipe]['maintainer'] = recipe_maintainer - recipes[recipe]['upstream'] = recipe_upstream_query[0] - - repodir = os.path.join(settings.LAYER_FETCH_DIR, layer.get_fetch_dir()) - - send_email(recipes, repodir, options) + for maintplan in maintplans: + recipes = {} + for item in maintplan.maintenanceplanlayerbranch_set.all(): + layerbranch = item.layerbranch + + recipe_upstream_history = RecipeUpstreamHistory.get_last() + if recipe_upstream_history is None: + logger.warn('I don\'t have Upstream information yet, run update.py script') + sys.exit(1) + + recipe_maintainer_history = RecipeMaintainerHistory.get_last() + if recipe_maintainer_history is None: + logger.warn('I don\'t have Maintainership information yet,' + + ' run rrs_maintainer_history.py script') + sys.exit(1) + + for recipe in layerbranch.recipe_set.all(): + recipe_upstream_query = RecipeUpstream.objects.filter(recipe = + recipe, history = recipe_upstream_history) + if recipe_upstream_query and recipe_upstream_query[0].status == 'N': + recipes[recipe] = {} + + recipe_maintainer = RecipeMaintainer.objects.filter(recipe = + recipe, history = recipe_maintainer_history)[0] + recipes[recipe]['maintainer'] = recipe_maintainer + recipes[recipe]['upstream'] = recipe_upstream_query[0] + + send_email(maintplan, recipes, options) if __name__ == "__main__": main() diff --git a/settings.py b/settings.py index 65a947e05f..c3075a5e70 100644 --- a/settings.py +++ b/settings.py @@ -234,10 +234,5 @@ RABBIT_BACKEND = 'rpc://' # Used for fetching repo PARALLEL_JOBS = "4" -# Settings for Recipe reporting system -RRS_EMAIL_SUBJECT = '[Recipe reporting system] Upgradable recipe name list' -RRS_EMAIL_FROM = 'recipe-report@yoctoproject.org' -RRS_EMAIL_TO = 'list@example.com' - # Full path to directory where rrs tools stores logs TOOLS_LOG_DIR = "" diff --git a/templates/rrs/report_email.txt b/templates/rrs/report_email.txt new file mode 100644 index 0000000000..02976fc440 --- /dev/null +++ b/templates/rrs/report_email.txt @@ -0,0 +1,26 @@ +This is an automated message from the Recipe Reporting System. + +Listed below are recipes which need to be upgraded based on the versions +available upstream. If a maintainer believes some of them cannot be upgraded +at this time, they can set RECIPE_NO_UPDATE_REASON in the recipe file(s) as +a reminder of why not. + +Example: +RECIPE_NO_UPDATE_REASON = "Version 2.0 is unstable" + +For further details please visit: + + {{ site_url }} + +Package Version Upstream version Maintainer No upgrade reason +-------------------- --------------- -------------------- -------------------- ------------------------------ +{% for line in recipelines %}{{ line.pn|truncatechars:20|ljust:20 }} {{ line.pv|truncatechars:15|ljust:15 }} {{ line.pv_upstream|truncatechars:20|ljust:20 }} {{ line.maintainer|truncatechars:20|ljust:20 }} {{ line.noupgradereason|truncatechars:30 }} +{% endfor %} +Upgradable count: {{ upgradable_count }} +Upgradable total count: {{ total_upgradable_count }} + +Based upon current {{ commits|length|pluralize:"commit,commits" }}: + +{% for commit in commits %} {{ commit }} +{% endfor %} +{% if maintplan.admin %}If there are any problems with the above, please contact: {{ maintplan.admin.first_name }} {{ maintplan.admin.last_name }} <{{ maintplan.admin.email }}>{% endif %} |