openerp-community-reviewer team mailing list archive
-
openerp-community-reviewer team
-
Mailing list archive
-
Message #03591
[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 OpenERP Community Reviewer/Maintainer is requested to review the proposed merge of lp:~savoirfairelinux-openerp/lp-community-utils/nag_refactor into lp:lp-community-utils.
=== 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