~jml/+junk/whip

« back to all changes in this revision

Viewing changes to lpwhip/main.py

  • Committer: Jonathan Lange
  • Date: 2010-12-23 15:11:02 UTC
  • Revision ID: jml@canonical.com-20101223151102-ucquq45ste3kp70k
Actually do interesting stuff.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
 
2
 
 
3
 
def run():
4
 
    print "Hello world!"
 
1
from itertools import chain, imap
 
2
from operator import attrgetter
 
3
import os
 
4
 
 
5
from launchpadlib.launchpad import Launchpad
 
6
from launchpadlib.uris import LPNET_SERVICE_ROOT
 
7
 
 
8
 
 
9
APP_NAME = 'jml-bug-jam'
 
10
CACHE_DIR = os.path.expanduser('~/.launchpadlib/cache')
 
11
SERVICE_ROOT = LPNET_SERVICE_ROOT
 
12
 
 
13
 
 
14
BUG_STATUSES = [
 
15
    "New",
 
16
    "Incomplete",
 
17
    "Invalid",
 
18
    "Won't Fix",
 
19
    "Opinion",
 
20
    "Confirmed",
 
21
    "Triaged",
 
22
    "In Progress",
 
23
    "Fix Committed",
 
24
    'Fix Released',
 
25
    ]
 
26
 
 
27
 
 
28
CLOSED_BUG_STATUSES = [
 
29
    "Opinion",
 
30
    "Invalid",
 
31
    "Won't Fix",
 
32
    'Fix Released',
 
33
    ]
 
34
 
 
35
 
 
36
FIXED_BUG_STATUSES = [
 
37
    'Fix Released',
 
38
    ]
 
39
 
 
40
 
 
41
MP_STATUSES = [
 
42
    'Work in progress',
 
43
    'Needs review',
 
44
    'Approved',
 
45
    'Rejected',
 
46
    'Merged',
 
47
    'Code failed to merge',
 
48
    'Queued',
 
49
    'Superseded',
 
50
    ]
 
51
 
 
52
 
 
53
BRANCH_STATUSES = [
 
54
    'Experimental',
 
55
    'Development',
 
56
    'Mature',
 
57
    'Merged',
 
58
    'Abandoned',
 
59
    ]
 
60
 
 
61
 
 
62
def get_bug_id(bug_task):
 
63
    """Get the bug ID for a bug task."""
 
64
    return int(bug_task.self_link.split('/')[-1])
 
65
 
 
66
 
 
67
def get_launchpad():
 
68
    return Launchpad.login_anonymously(APP_NAME, SERVICE_ROOT, CACHE_DIR)
 
69
 
 
70
 
 
71
def get_assigned_bugs(person):
 
72
    return imap(BugTask, person.searchTasks(assignee=person))
 
73
 
 
74
 
 
75
def get_open_branches(person):
 
76
    return (
 
77
        branch for branch in imap(
 
78
            Branch,
 
79
            person.getBranches(status=['Development', 'Experimental']))
 
80
        if not branch.is_linked and branch.target)
 
81
 
 
82
 
 
83
def get_merge_proposals(person):
 
84
    return imap(
 
85
        MergeProposal,
 
86
        person.getMergeProposals(
 
87
            status=['Work in progress', 'Needs review', 'Approved']))
 
88
 
 
89
 
 
90
def get_requested_reviews(person):
 
91
    return imap(
 
92
        MergeProposal, person.getRequestedReviews(status=['Needs review']))
 
93
 
 
94
 
 
95
class Branch(object):
 
96
 
 
97
    def __init__(self, lp_branch):
 
98
        self._lp_branch = lp_branch
 
99
 
 
100
    @property
 
101
    def target(self):
 
102
        """The project or source package that the branch is against."""
 
103
        if self._lp_branch.project is not None:
 
104
            return Target(self._lp_branch.project)
 
105
        if self._lp_branch.sourcepackage is not None:
 
106
            return Target(self._lp_branch.sourcepackage)
 
107
        return None
 
108
 
 
109
    @property
 
110
    def is_linked(self):
 
111
        """Is the branch linked to something interesting?"""
 
112
        return not self._lp_branch.bzr_identity.endswith(
 
113
            self._lp_branch.unique_name)
 
114
 
 
115
    def __str__(self):
 
116
        return self._lp_branch.bzr_identity
 
117
 
 
118
 
 
119
class MergeProposal(object):
 
120
 
 
121
    def __init__(self, lp_mp):
 
122
        self._lp_mp = lp_mp
 
123
 
 
124
    @property
 
125
    def source_branch(self):
 
126
        return Branch(self._lp_mp.source_branch)
 
127
 
 
128
    @property
 
129
    def target_branch(self):
 
130
        return Branch(self._lp_mp.target_branch)
 
131
 
 
132
    @property
 
133
    def target(self):
 
134
        return self.target_branch.target
 
135
 
 
136
    @property
 
137
    def status(self):
 
138
        return self._lp_mp.queue_status
 
139
 
 
140
    def __str__(self):
 
141
        return '%s => %s' % (self.source_branch, self.target_branch)
 
142
 
 
143
 
 
144
class BugTask(object):
 
145
 
 
146
    def __init__(self, lp_bugtask):
 
147
        self._lp_bugtask = lp_bugtask
 
148
 
 
149
    @property
 
150
    def bug_id(self):
 
151
        return get_bug_id(self._lp_bugtask)
 
152
 
 
153
    @property
 
154
    def target(self):
 
155
        return Target(self._lp_bugtask.target)
 
156
 
 
157
    def __str__(self):
 
158
        return '%s (%s)' % (self._lp_bugtask.title, self._lp_bugtask.status)
 
159
 
 
160
 
 
161
class Target(object):
 
162
 
 
163
    def __init__(self, lp_target):
 
164
        self._lp_target = lp_target
 
165
 
 
166
    def __str__(self):
 
167
        return self.name
 
168
 
 
169
    @property
 
170
    def name(self):
 
171
        return self._lp_target.name
 
172
 
 
173
 
 
174
class Dashboard(object):
 
175
 
 
176
    # AXES:
 
177
    # - person
 
178
    # - target
 
179
    # - type of item
 
180
    # - status of item
 
181
 
 
182
    def __init__(self, person, assigned_bugs, open_branches, merge_proposals,
 
183
                 requested_reviews):
 
184
        self._person = person
 
185
        self._assigned_bugs = assigned_bugs
 
186
        self._open_branches = open_branches
 
187
        self._merge_proposals = merge_proposals
 
188
        self._requested_reviews = requested_reviews
 
189
 
 
190
    @classmethod
 
191
    def load(cls, person):
 
192
        return cls(
 
193
            person,
 
194
            get_assigned_bugs(person),
 
195
            get_open_branches(person),
 
196
            get_merge_proposals(person),
 
197
            get_requested_reviews(person),
 
198
            )
 
199
 
 
200
    @property
 
201
    def all_inventory(self):
 
202
        return chain(
 
203
            self._assigned_bugs, self._open_branches, self._merge_proposals,
 
204
            self._requested_reviews)
 
205
 
 
206
    def grouped_by_target(self, ordered=False):
 
207
        targets = {}
 
208
        inventory = {'bugs': self._assigned_bugs,
 
209
                     'branches': self._open_branches,
 
210
                     'merge-proposals': self._merge_proposals,
 
211
                     'requested-reviews': self._requested_reviews}
 
212
        for name, items in inventory.iteritems():
 
213
            for item in items:
 
214
                target_name = item.target.name
 
215
                if target_name not in targets:
 
216
                    targets[target_name] = {}
 
217
                if name not in targets[target_name]:
 
218
                    targets[target_name][name] = []
 
219
                targets[target_name][name].append(item)
 
220
        if ordered:
 
221
            targets = sorted((k, sorted(v.items())) for k, v in targets.items())
 
222
        return targets
 
223
 
 
224
    def summary_by_target(self):
 
225
        targets = self.grouped_by_target(ordered=True)
 
226
        for name, items in targets:
 
227
            items = ['%s=%s' % (k, len(v)) for k, v in items]
 
228
            print '%s: %s' % (name, ', '.join(items))
 
229
 
 
230
    def full_by_target(self):
 
231
        targets = self.grouped_by_target(ordered=True)
 
232
        for name, items in targets:
 
233
            print '= %s =' % (name,)
 
234
            print
 
235
            for item_type, item_values in items:
 
236
                print '== %s ==' % (item_type,)
 
237
                print
 
238
                for item in item_values:
 
239
                    print ' * %s' % (item,)
 
240
                print
 
241
 
 
242
    def dump(self):
 
243
        self.summary_by_target()
 
244
 
 
245
 
 
246
def run(args):
 
247
    username = args[1]
 
248
    lp = get_launchpad()
 
249
    person = lp.people[username]
 
250
    dashboard = Dashboard.load(person)
 
251
    dashboard.dump()
 
252
    return 0