← Back to team overview

savoirfairelinux-openerp team mailing list archive

[Merge] lp:~savoirfairelinux-openerp/lp-community-utils/nag_refactor into lp:lp-community-utils

 

Sandy Carter (http://www.savoirfairelinux.com) has proposed merging lp:~savoirfairelinux-openerp/lp-community-utils/nag_refactor into lp:lp-community-utils.

Requested reviews:
  OpenERP Community Reviewer/Maintainer (openerp-community-reviewer)

For more details, see:
https://code.launchpad.net/~savoirfairelinux-openerp/lp-community-utils/nag_refactor/+merge/205257

Cleaned up code of nag
* Put branch analysis code in nag_lib
* Changed Nag to a class
* Removed unused parameters
* Fixed sign/sort issue with age
* General readability improvements

This will allow for other scripts that the general nag script to use some shared functionality
-- 
https://code.launchpad.net/~savoirfairelinux-openerp/lp-community-utils/nag_refactor/+merge/205257
Your team Savoir-faire Linux' OpenERP is subscribed to branch lp:~savoirfairelinux-openerp/lp-community-utils/nag_refactor.
=== added file 'nag_lib.py'
--- nag_lib.py	1970-01-01 00:00:00 +0000
+++ nag_lib.py	2014-02-06 20:34:22 +0000
@@ -0,0 +1,147 @@
+# Copyright 2012 Canonical Ltd.
+# Written by:
+#   Zygmunt Krynicki <zygmunt.krynicki@xxxxxxxxxxxxx>
+# Hacked for the OpenERP Community Reviewers version by:
+#   Guewen Baconnier <guewen.baconnier@xxxxxxxxxxxxxx>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 3,
+# as published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+import logging
+import datetime
+
+
+class DefaultPolicy:
+
+    def __init__(self):
+        pass
+
+    mps_need_commit_message = False
+    min_review_age = 0
+    max_bug_new_age = 7
+
+
+class UTC(datetime.tzinfo):
+
+    def dst(self, foo):
+        return datetime.timedelta(0, 0)
+
+    def utcoffset(self, foo):
+        return datetime.timedelta(0, 0)
+
+
+# Nag:
+# Indication that we want to nag the 'person'...
+# ...with the specified 'action'
+# ...about a particular 'subject'
+class Nag():
+    def __init__(self, person, action, subject, sort_class, sort_priority, 
+                 age, project_name, proposal):
+        self.person = person
+        self.action = action
+        self.subject = subject
+        self.sort_class = sort_class
+        self.sort_priority = sort_priority
+        self.age = age
+        self.project_name = project_name
+        self.proposal = proposal
+
+UTC = UTC()
+SORT_CLASS_BUG, SORT_CLASS_MERGE = range(2)
+
+
+def gen_merge_proposal_nags(policy, project):
+    # XXX: cannnot use utcnow as launchpad returns tz-aware objects here
+    now = datetime.datetime.now(tz=UTC)
+    logging.debug("Looking for merge proposals in project %r", project)
+    # NOTE: Workaround for project.getMergeProposals() crashing on timeouts
+    try:
+        merge_proposals = project.getMergeProposals(status='Needs review')
+    except AttributeError:
+        logging.warning("The project %s has no code to look at", project)
+        return
+    for proposal in merge_proposals:
+        logging.debug("Looking at merge proposal %r", proposal)
+        # Skip everything that is still not requested for review
+        if proposal.date_review_requested is None:
+            continue
+        # Skip everything that is already merged
+        if proposal.date_merged is not None:
+            continue
+        review_age = now - proposal.date_review_requested
+        # Nag about missing commit message on merge requests
+        if policy.mps_need_commit_message and proposal.commit_message is None:
+            yield Nag(
+                person=proposal.registrant.display_name,
+                action="set a commit message on merge request",
+                subject=proposal.web_link,
+                sort_class=SORT_CLASS_MERGE,
+                sort_priority=None,  # TODO: get from max(linked bugs)
+                age=review_age.days,
+                project_name=project.name,
+                proposal=proposal,
+            )
+        # Nag about aging merge requests
+        if review_age.days >= policy.min_review_age:
+            yield Nag(
+                person='Someone',
+                action="review the merge request",
+                subject=proposal.web_link,
+                sort_class=SORT_CLASS_MERGE,
+                sort_priority=None,  # TODO: get from max(linked bugs)
+                age=review_age.days,
+                project_name=project.name,
+                proposal=proposal,
+            )
+
+
+def gen_project_nags(lp, policy, project_name):
+    # TODO: Detect project groups and redirect the nag to all projects
+    # underneath that project
+    # Access the project that we care about
+    logging.debug("Accessing project %r", project_name)
+    project = lp.projects[project_name]
+    # Re-yield all the merge proposal nags
+    # NOTE: change to yield from in py3k3
+    for nag in gen_merge_proposal_nags(policy, project):
+        yield nag
+
+
+def gen_bug_nags(policy, project):
+    now = datetime.datetime.now(tz=UTC)
+    new_threshold = now - datetime.timedelta(days=policy.max_bug_new_age)
+    # Nag about bugs that are "New" for too long
+    logging.debug("Looking at 'new' bugs that are 8 days or older")
+    aging_new_bugs = project.searchTasks(status='New',
+                                         created_before=new_threshold)
+    for bug_task in aging_new_bugs:
+        yield Nag(
+            person='everyone',
+            action='triage the bug',
+            subject=bug_task.web_link,
+            sort_class=SORT_CLASS_BUG,
+            sort_priority=None,  # TODO: convert from importance name
+            age=None,
+            project_name=project.name,
+            proposal=None)
+
+
+def parse_projects_file(filename):
+    """ Parse a file containing name of the projects
+    A line per project
+    """
+    with open(filename, mode='rU') as project_file:
+        content = project_file.read()
+
+    return [name.strip() for name in content.splitlines()]

=== modified file 'openerp-nag'
--- openerp-nag	2013-09-22 14:36:16 +0000
+++ openerp-nag	2014-02-06 20:34:22 +0000
@@ -42,26 +42,18 @@
 from __future__ import unicode_literals, print_function
 
 import argparse
-import collections
-import datetime
 import logging
 
 from launchpadlib.launchpad import Launchpad
-
+from nag_lib import (
+    parse_projects_file,
+    gen_project_nags,
+    DefaultPolicy,
+)
 
 consumer_name = 'OpenERP Community Reviewers Nagging Scripts'
 
 
-# Nag:
-# Indication that we want to nag the 'person'...
-# ...with the specified 'action'
-# ...about a particular 'subject'
-Nag = collections.namedtuple(
-    "Nag", "person action subject sort_class sort_priority sort_age project_name")
-
-SORT_CLASS_BUG, SORT_CLASS_MERGE = range(2)
-
-
 def show_lp_object(obj):
     print(obj)
     print("attributes:", obj.lp_attributes)
@@ -75,109 +67,7 @@
     print("-" * 80)
 
 
-class DefaultPolicy:
-
-    mps_need_commit_message = False
-
-    max_review_age = 0
-
-    max_bug_new_age = 7
-
-
-class UTC(datetime.tzinfo):
-
-    def dst(self, foo):
-        return datetime.timedelta(0, 0)
-
-    def utcoffset(self, foo):
-        return datetime.timedelta(0, 0)
-
-
-UTC = UTC()
-
-
-def gen_project_nags(lp, policy, project_name):
-    # TODO: Detect project groups and redirect the nag to all projects
-    # underneath that project
-    # Access the project that we care about
-    logging.debug("Accessing project %r", project_name)
-    project = lp.projects[project_name]
-    # Re-yield all the merge proposal nags
-    # NOTE: change to yield from in py3k3
-    for nag in gen_merge_proposal_nags(lp, policy, project):
-        yield nag
-
-
-def gen_merge_proposal_nags(lp, policy, project):
-    # XXX: cannnot use utcnow as launchpad returns tz-aware objects here
-    now = datetime.datetime.now(tz=UTC)
-    logging.debug("Looking for merge proposals in project %r", project)
-    # NOTE: Workaround for project.getMergeProposals() crashing on timeouts
-    try:
-        merge_proposals = project.getMergeProposals(status='Needs review')
-    except AttributeError:
-        logging.warning("The project %s has no code to look at", project)
-        return
-    for proposal in merge_proposals:
-        logging.debug("Looking at merge proposal %r", proposal)
-        # Skip everything that is still not requested for review
-        if proposal.date_review_requested is None:
-            continue
-        # Skip everything that is already merged
-        if proposal.date_merged is not None:
-            continue
-        # Nag about missing commit message on merge requests
-        if policy.mps_need_commit_message and proposal.commit_message is None:
-            yield Nag(
-                person=proposal.registrant.display_name,
-                action="set a commit message on merge request",
-                subject=proposal.web_link,
-                sort_class=SORT_CLASS_MERGE,
-                sort_priority=None,  # TODO: get from max(linked bugs)
-                sort_age=(proposal.date_review_requested - now).days,
-                project_name=project.name
-            )
-        # Nag about aging merge requests
-        if (now - proposal.date_review_requested).days >= policy.max_review_age:
-            yield Nag(
-                person='Someone',
-                action="review the merge request",
-                subject=proposal.web_link,
-                sort_class=SORT_CLASS_MERGE,
-                sort_priority=None,  # TODO: get from max(linked bugs)
-                sort_age=(proposal.date_review_requested - now).days,
-                project_name=project.name
-            )
-
-
-def gen_bug_nags(lp, policy, project):
-    now = datetime.datetime.now(tz=UTC)
-    new_threshold = now - datetime.timedelta(days=policy.max_bug_new_age)
-    # Nag about bugs that are "New" for too long
-    logging.debug("Looking at 'new' bugs that are 8 days or older")
-    aging_new_bugs = project.searchTasks(status='New',
-                                         created_before=new_threshold)
-    for bug_task in aging_new_bugs:
-        yield Nag(
-            person='everyone',
-            action='triage the bug',
-            subject=bug_task.web_link,
-            sort_class=SORT_CLASS_BUG,
-            sort_priority=None,  # TODO: convert from importance name
-            sort_age=None)
-
-
-def parse_projects_file(filename):
-    """ Parse a file containing name of the projects
-    A line per project
-    """
-    with open(filename, mode='rU') as project_file:
-        content = project_file.read()
-
-    return [name.strip() for name in content.splitlines()]
-
-
-def main():
+def parse_args():
     parser = argparse.ArgumentParser()
     group = parser.add_argument_group(title="debugging")
     group.add_argument(
@@ -189,15 +79,13 @@
     group.add_argument(
         '-f', '--projects-file',
         dest='projects_file',
-        help="File containing a list of Launchpad projects to track.\n"
-             "One project name per line")
+        help="""\
+File containing a list of Launchpad projects to track.
+One project name per line""")
     group.add_argument(
         '--anonymous', action='store_true',
         help="Access Launchpad anonymously")
     group.add_argument(
-        '--authenticated', action='store_false', dest='anonymous',
-        help="Access launchpad as youself")
-    group.add_argument(
         '--staging', action='store_const', const='staging',
         dest='service_root', help="Use staging launchpad instance")
     group.add_argument(
@@ -205,6 +93,16 @@
         dest='service_root', help="Use production launchpad instance")
     parser.set_defaults(anonymous=True, service_root='production')
     args = parser.parse_args()
+    if not args.project and not args.projects_file:
+        parser.print_usage()
+        parser.exit(2, """\
+No project specified using option --project or --projects-file
+""")
+    return args
+
+
+def main():
+    args = parse_args()
     # Get the policy
     policy = DefaultPolicy
     # Reconfigure logging
@@ -216,11 +114,6 @@
     else:
         lp = Launchpad.login_with(consumer_name, args.service_root)
 
-    if not args.project and not args.projects_file:
-        parser.print_usage()
-        parser.exit(2, "No project specified using option "
-                       "--project or --projects-file\n")
-
     project_names = args.project
     if args.projects_file:
         project_names.extend(parse_projects_file(args.projects_file))
@@ -231,19 +124,20 @@
         logging.info("Looking for things to nag about under %s", project_name)
         nags.extend(gen_project_nags(lp, policy, project_name))
     nags.sort(key=lambda nag: (nag.sort_class, nag.sort_priority,
-                               nag.sort_age))
+                               -nag.age))
     print("=" * 80)
     print("Done thinking, here's the nag list".center(80))
     print("=" * 80)
     for index1, nag in enumerate(nags, 1):
         print("{index1:-2}: [age {age}] {person} should {action} {subject} "
               "on the project {project}".format(
-                  index1=index1, age=(nag.sort_age and -nag.sort_age), person=nag.person,
-                  action=nag.action, subject=nag.subject, project=nag.project_name))
+                  index1=index1, age=nag.age, person=nag.person, 
+                  action=nag.action, subject=nag.subject,
+                  project=nag.project_name))
 
 
 if __name__ == "__main__":
     try:
-        main()
+        exit(main())
     except KeyboardInterrupt:
-        pass
+        exit()


Follow ups