summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/management/__init__.py0
-rw-r--r--packages/management/commands/__init__.py0
-rw-r--r--packages/management/commands/signoff_report.py110
-rw-r--r--templates/packages/signoff_report.txt27
4 files changed, 137 insertions, 0 deletions
diff --git a/packages/management/__init__.py b/packages/management/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/packages/management/__init__.py
diff --git a/packages/management/commands/__init__.py b/packages/management/commands/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/packages/management/commands/__init__.py
diff --git a/packages/management/commands/signoff_report.py b/packages/management/commands/signoff_report.py
new file mode 100644
index 00000000..17e58f39
--- /dev/null
+++ b/packages/management/commands/signoff_report.py
@@ -0,0 +1,110 @@
+# -*- coding: utf-8 -*-
+"""
+signoff_report command
+
+Send an email summarizing the state of outstanding signoffs for the given
+repository.
+
+Usage: ./manage.py signoff_report <email> <repository>
+"""
+
+from django.core.urlresolvers import reverse
+from django.core.management.base import BaseCommand, CommandError
+from django.contrib.auth.models import User
+from django.contrib.sites.models import Site
+from django.db.models import Count
+from django.template import loader, Context
+
+from collections import namedtuple
+from datetime import datetime, timedelta
+import logging
+from operator import attrgetter
+import sys
+
+from main.models import Package, Repo
+from packages.models import Signoff
+from packages.utils import get_signoff_groups
+
+logging.basicConfig(
+ level=logging.INFO,
+ format='%(asctime)s -> %(levelname)s: %(message)s',
+ datefmt='%Y-%m-%d %H:%M:%S',
+ stream=sys.stderr)
+logger = logging.getLogger()
+
+class Command(BaseCommand):
+ args = "<email> <repository>"
+ help = "Send a signoff report for the given repository."
+
+ def handle(self, *args, **options):
+ v = int(options.get('verbosity', None))
+ if v == 0:
+ logger.level = logging.ERROR
+ elif v == 1:
+ logger.level = logging.INFO
+ elif v == 2:
+ logger.level = logging.DEBUG
+
+ if len(args) != 2:
+ raise CommandError("email and repository must be provided")
+
+ return generate_report(args[0], args[1])
+
+def generate_report(email, repo_name):
+ repo = Repo.objects.get(name__iexact=repo_name)
+ # Collect all existing signoffs for these packages
+ signoff_groups = sorted(get_signoff_groups([repo]),
+ key=attrgetter('target_repo', 'arch', 'pkgbase'))
+ complete = []
+ incomplete = []
+ new = []
+ old = []
+
+ new_hours = 24
+ old_days = 14
+ now = datetime.utcnow()
+ new_cutoff = now - timedelta(hours=new_hours)
+ old_cutoff = now - timedelta(days=old_days)
+
+ for group in signoff_groups:
+ if group.approved():
+ complete.append(group)
+ else:
+ incomplete.append(group)
+ if group.package.last_update > new_cutoff:
+ new.append(group)
+ if group.package.last_update < old_cutoff:
+ old.append(group)
+
+ old.sort(key=attrgetter('last_update'))
+
+ proto = 'https'
+ domain = Site.objects.get_current().domain
+ signoffs_url = '%s://%s%s' % (proto, domain, reverse('package-signoffs'))
+
+ # and the fun bit
+ Leader = namedtuple('Leader', ['user', 'count'])
+ leaders = Signoff.objects.filter(created__gt=new_cutoff,
+ revoked__isnull=True).values_list('user').annotate(
+ signoff_count=Count('pk')).order_by('-signoff_count')[:5]
+ users = User.objects.in_bulk([l[0] for l in leaders])
+ leaders = (Leader(users[l[0]], l[1]) for l in leaders)
+
+ subject = 'Signoff report for [%s]' % repo.name.lower()
+ t = loader.get_template('packages/signoff_report.txt')
+ c = Context({
+ 'repo': repo,
+ 'signoffs_url': signoffs_url,
+ 'incomplete': incomplete,
+ 'complete': complete,
+ 'new': new,
+ 'new_hours': new_hours,
+ 'old': old,
+ 'old_days': old_days,
+ 'leaders': leaders,
+ })
+ from_addr = 'Arch Website Notification <nobody@archlinux.org>'
+ #send_mail(subject, t.render(c), from_addr, email)
+ print t.render(c)
+
+# vim: set ts=4 sw=4 et:
diff --git a/templates/packages/signoff_report.txt b/templates/packages/signoff_report.txt
new file mode 100644
index 00000000..84e3fc6b
--- /dev/null
+++ b/templates/packages/signoff_report.txt
@@ -0,0 +1,27 @@
+=== {% autoescape off %}Signoff report for [{{ repo|lower }}] ===
+{{ signoffs_url }}
+
+== New packages in [{{ repo|lower}}] in last {{ new_hours }} hours ({{ new|length }} total) ==
+{% for group in new %}
+* {{ group.pkgbase }}-{{ group.version }} ({{ group.arch }}){% endfor %}
+
+{% regroup incomplete by target_repo as by_repo %}{% for target_repo in by_repo %}
+== Incomplete signoffs for [{{ target_repo.grouper|lower }}] ({{ target_repo.list|length }} total) ==
+{% for group in target_repo.list %}
+* {{ group.pkgbase }}-{{ group.version }} ({{ group.arch }})
+ {{ group.completed }}/{{ group.required }} signoffs{% endfor %}
+{% endfor %}
+
+== Completed signoffs ({{ complete|length }} total) ==
+{% for group in complete %}
+* {{ group.pkgbase }}-{{ group.version }} ({{ group.arch }}){% endfor %}
+
+
+== All packages in [{{ repo|lower }}] for more than {{ old_days }} days ({{ old|length }} total) ==
+{% for group in old %}
+* {{ group.pkgbase }}-{{ group.version }} ({{ group.arch }}), since {{ group.last_update|date }}{% endfor %}
+{% endautoescape %}
+
+== Top five in signoffs in last {{ new_hours }} hours ==
+{% for leader in leaders %}
+{{ forloop.counter }}. {{ leader.user }} - {{ leader.count }} signoffs{% endfor %}