Merge lp:~negronjl/charm-tools/review_queue into lp:~charmers/charm-tools/trunk

Proposed by Juan L. Negron
Status: Merged
Approved by: Clint Byrum
Approved revision: 138
Merge reported by: Juan L. Negron
Merged at revision: not available
Proposed branch: lp:~negronjl/charm-tools/review_queue
Merge into: lp:~charmers/charm-tools/trunk
Diff against target: 127 lines (+123/-0)
1 file modified
scripts/review-queue (+123/-0)
To merge this branch: bzr merge lp:~negronjl/charm-tools/review_queue
Reviewer Review Type Date Requested Status
Juan L. Negron (community) Needs Resubmitting
Clint Byrum (community) Needs Fixing
Review via email: mp+106481@code.launchpad.net

Description of the change

To make charm review more convenient, I made a simple script that polls the current review queue.

-Juan

To post a comment you must log in.
Revision history for this message
Clint Byrum (clint-fewbar) wrote :

Hi Juan!

Can you change the script name to review-queue. Underscore is not common in the juju ecosystem and I'd like to remain consistent.

charm review-queue

Seems more consistent with that.

Also this goes really slow, obviously because we're waiting for launchpad. I'd recommend adding a cache to the launchpadlib. Could you add some logging, something like:

Querying launchpad...

Just so we know what is taking 4 seconds. (Perhaps a --quiet to get rid of it)

Also you can speed it up on subsequent runs by almost 1s by passing launchpadlib_dir='~/.cache/launchpadlib' to Launchpad.login_anonymously. It will just skip querying a few of the objects like the team records and such.

=== modified file 'scripts/review_queue'
--- scripts/review_queue 2012-05-18 23:25:43 +0000
+++ scripts/review_queue 2012-05-20 00:42:11 +0000
@@ -71,7 +71,7 @@

 def charm_review_queue():
- lp = Launchpad.login_anonymously('charm-tools', 'production', version='devel')
+ lp = Launchpad.login_anonymously('charm-tools', 'production', version='devel', launchpadlib_dir='~/.cache/launchpadlib')
  charm = lp.distributions['charms']
  bugs = charm.searchTasks(tags=['new-formula', 'new-charm'], tags_combinator="Any", status=['New', 'Confirmed', 'Triaged', 'In Progress', 'Fix Committed'])
  charmers = lp.people['charmers']

Otherwise I think this is *awesome*!

(as a side note, I got bored and tried this out with a thread per request to launchpad.. that drops it to about 3.3s.. basically only waiting for the bug search.) I've pushed that to lp:~clint-fewbar/charm-tools/review_queue_threaded)

review: Needs Fixing
138. By Juan L. Negron

Adressed suggestions by Clint. Added some logging to let the user know what's going on. Added launchpad_lib directory .

Revision history for this message
Juan L. Negron (negronjl) wrote :

Hi Clint:

Thank you for the suggestions. I have addressed the launchpad_lib and
logging suggestions. Would you review the changes?

I didn't see much of an improvement on my system adding threads so I didn't
do those changes ( ... and you have them done already so no need for me to
do that ).

Thanks,

Juan

On Sun, May 20, 2012 at 1:18 PM, Clint Byrum <email address hidden> wrote:

> Review: Needs Fixing
>
> Hi Juan!
>
> Can you change the script name to review-queue. Underscore is not common
> in the juju ecosystem and I'd like to remain consistent.
>
> charm review-queue
>
> Seems more consistent with that.
>
> Also this goes really slow, obviously because we're waiting for launchpad.
> I'd recommend adding a cache to the launchpadlib. Could you add some
> logging, something like:
>
> Querying launchpad...
>
> Just so we know what is taking 4 seconds. (Perhaps a --quiet to get rid of
> it)
>
> Also you can speed it up on subsequent runs by almost 1s by passing
> launchpadlib_dir='~/.cache/launchpadlib' to Launchpad.login_anonymously. It
> will just skip querying a few of the objects like the team records and such.
>
> === modified file 'scripts/review_queue'
> --- scripts/review_queue 2012-05-18 23:25:43 +0000
> +++ scripts/review_queue 2012-05-20 00:42:11 +0000
> @@ -71,7 +71,7 @@
>
>
> def charm_review_queue():
> - lp = Launchpad.login_anonymously('charm-tools', 'production',
> version='devel')
> + lp = Launchpad.login_anonymously('charm-tools', 'production',
> version='devel', launchpadlib_dir='~/.cache/launchpadlib')
> charm = lp.distributions['charms']
> bugs = charm.searchTasks(tags=['new-formula', 'new-charm'],
> tags_combinator="Any", status=['New', 'Confirmed', 'Triaged', 'In
> Progress', 'Fix Committed'])
> charmers = lp.people['charmers']
>
>
> Otherwise I think this is *awesome*!
>
> (as a side note, I got bored and tried this out with a thread per request
> to launchpad.. that drops it to about 3.3s.. basically only waiting for the
> bug search.) I've pushed that to
> lp:~clint-fewbar/charm-tools/review_queue_threaded)
> --
> https://code.launchpad.net/~negronjl/charm-tools/review_queue/+merge/106481
> You are the owner of lp:~negronjl/charm-tools/review_queue.
>

Revision history for this message
Juan L. Negron (negronjl) wrote :

Resubmitting the merge proposal

review: Needs Resubmitting

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'scripts/review-queue'
2--- scripts/review-queue 1970-01-01 00:00:00 +0000
3+++ scripts/review-queue 2012-05-21 03:49:17 +0000
4@@ -0,0 +1,123 @@
5+#!/usr/bin/env python
6+
7+from launchpadlib.launchpad import Launchpad
8+from operator import itemgetter
9+import datetime
10+
11+def calculate_age(from_date = None):
12+ if not from_date:
13+ return None
14+
15+
16+def format_as_table(data,
17+ keys,
18+ header=None,
19+ sort_by_key=None,
20+ sort_order_reverse=False):
21+ """Takes a list of dictionaries, formats the data, and returns
22+ the formatted data as a text table.
23+
24+ Required Parameters:
25+ data - Data to process (list of dictionaries). (Type: List)
26+ keys - List of keys in the dictionary. (Type: List)
27+
28+ Optional Parameters:
29+ header - The table header. (Type: List)
30+ sort_by_key - The key to sort by. (Type: String)
31+ sort_order_reverse - Default sort order is ascending, if
32+ True sort order will change to descending. (Type: Boolean)
33+ """
34+ # Sort the data if a sort key is specified (default sort order
35+ # is ascending)
36+ if sort_by_key:
37+ data = sorted(data,
38+ key=itemgetter(sort_by_key),
39+ reverse=sort_order_reverse)
40+
41+ # If header is not empty, add header to data
42+ if header:
43+ # Get the length of each header and create a divider based
44+ # on that length
45+ header_divider = []
46+ for name in header:
47+ header_divider.append('-' * len(name))
48+
49+ # Create a list of dictionary from the keys and the header and
50+ # insert it at the beginning of the list. Do the same for the
51+ # divider and insert below the header.
52+ header_divider = dict(zip(keys, header_divider))
53+ data.insert(0, header_divider)
54+ header = dict(zip(keys, header))
55+ data.insert(0, header)
56+
57+ column_widths = []
58+ for key in keys:
59+ column_widths.append(max(len(str(column[key])) for column in data))
60+
61+ # Create a tuple pair of key and the associated column width for it
62+ key_width_pair = zip(keys, column_widths)
63+
64+ format = ('%-*s ' * len(keys)).strip() + '\n'
65+ formatted_data = ''
66+ for element in data:
67+ data_to_format = []
68+ # Create a tuple that will be used for the formatting in
69+ # width, value format
70+ for pair in key_width_pair:
71+ data_to_format.append(pair[1])
72+ data_to_format.append(element[pair[0]])
73+ formatted_data += format % tuple(data_to_format)
74+ return formatted_data
75+
76+
77+def charm_review_queue():
78+ print "Connecting to launchpad..."
79+ lp = Launchpad.login_anonymously('charm-tools', 'production', version='devel', launchpadlib_dir='~/.cache/launchpadlib')
80+ charm = lp.distributions['charms']
81+ print "Querying launchpad for bugs ..."
82+ bugs = charm.searchTasks(tags=['new-formula', 'new-charm'], tags_combinator="Any", status=['New', 'Confirmed', 'Triaged', 'In Progress', 'Fix Committed'])
83+ charmers = lp.people['charmers']
84+ print "Querying launchpad for proposals ..."
85+ proposals = charmers.getRequestedReviews(status="Needs review")
86+ queue = list()
87+ max_summary_length = 50
88+ for bug in bugs.entries:
89+ entry_summary = bug['title'].split('"')[1].strip()
90+ entry_age = datetime.datetime.utcnow() - datetime.datetime.strptime(bug['date_created'].split('+')[0], "%Y-%m-%dT%H:%M:%S.%f")
91+ entry = {
92+ 'date_created' : bug['date_created'].split("T")[0],
93+ 'age' : str(entry_age).split('.')[0],
94+ 'summary' : (entry_summary[:max_summary_length] + '...') if len(entry_summary) > max_summary_length else entry_summary,
95+ 'item' : bug['web_link'],
96+ 'status' : bug['status'],
97+ }
98+ queue.append(entry)
99+ for proposal in proposals.entries:
100+ proposal_summary = proposal['description']
101+ proposal_age = datetime.datetime.utcnow() - datetime.datetime.strptime(proposal['date_created'].split('+')[0], "%Y-%m-%dT%H:%M:%S.%f")
102+ if proposal_summary is None:
103+ proposal_summary = "Proposal"
104+ entry = {
105+ 'date_created' : proposal['date_created'].split("T")[0],
106+ 'age' : str(proposal_age).split('.')[0],
107+ 'summary' : (proposal_summary[:max_summary_length] + '...') if len(proposal_summary) > max_summary_length else proposal_summary,
108+ 'item' : proposal['web_link'],
109+ 'status' : proposal['queue_status'],
110+ }
111+ queue.append(entry)
112+ return(sorted(queue, key=lambda k: k['date_created']))
113+
114+def main():
115+ review_queue = charm_review_queue()
116+ keys = ['date_created', 'age', 'summary', 'item', 'status' ]
117+ headers = ['Date Created', 'Age', 'Summary', 'Item', 'Status']
118+ if type(review_queue) == type([]) and len(review_queue) > 0:
119+ print format_as_table(review_queue,
120+ keys,
121+ header = headers,
122+ sort_by_key = 'date_created',
123+ sort_order_reverse = False)
124+
125+
126+if __name__ == "__main__":
127+ main()

Subscribers

People subscribed via source and target branches