~rockstar/laika/more-cleanup

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#!/usr/bin/env python
#
# laika prints a summary of the Launchpad bugs you touched this week
#
# man's best friend guides you through Launchpad
# 'Laika died within hours after launch' => an aptly named tool ;)
# http://en.wikipedia.org/wiki/Laika
#
# Copyright 2010 Alex Chiang <achiang@canonical.com>
#
# This program is distributed under the terms of the
# GNU General Public License version 2.

import datetime
from optparse import OptionParser
import os
import re
import sys

from launchpadlib.launchpad import Launchpad

UTCNOW = datetime.datetime.utcnow()


class Report(object):
    '''An activity report for a specified Launchpad user.

    In order of decreasing importance, search and display activity on
    bugs assigned to me, then on bugs that I actually commented upon,
    and finally bugs that I just opened, but did nothing further with.

    Avoids duplication of activity. So if the status was changed on
    a bug assigned to you and you also commented on it, only report the
    status change.
    '''

    bugs = {}

    def __init__(self, user, window):
        cachedir = "/home/" + user + "/.launchpadlib/cache/"
        self.launchpad = Launchpad.login_with('laika', 'production', cachedir)

        self.user = self.launchpad.people[user]
        self.window = window

    def print_header(self, header):
        print "==", header, "=="

    def in_window(self, date):
        '''Timezones do not exist, all datetime objects have to be naive.

        Time zone aware means broken.
        http://www.enricozini.org/2009/debian/using-python-datetime/
        '''
        win = datetime.timedelta(self.window)
        date = date.replace(tzinfo=None)
        delta = UTCNOW - date
        return delta <= win

    def print_bugid(self, task):
        '''Using this interface adds the bug to global bug list.'''
        ago = ""
        self.bugs[task.bug.id] = 1
        delta = UTCNOW - task.bug.date_last_updated.replace(tzinfo=None)
        if delta.days > 0:
            ago = "%d day%s" % (delta.days, "s" if delta.days > 1 else "")

        hours = delta.seconds / 3600
        if hours > 0:
            ago += ", " if ago else ""
            ago += "%d hour%s" % (hours, "s" if hours > 1 else "")

        minutes = (delta.seconds - (hours * 3600)) / 60
        if minutes > 0:
            ago += ", " if ago else ""
            ago += "%d minute%s" % (minutes, "s" if minutes > 1 else "")

        print task.title
        print "https://launchpad.net/bugs/" + str(task.bug.id)
        print "last updated", ago, "ago"

    def print_assignments(self):
        statuses = ['closed', 'fix_released', 'fix_committed',
                'in_progress', 'triaged', 'confirmed', 'created']

        tasks = self.user.searchTasks(assignee=self.user)
        self.print_header("Assigned Bugs")

        for t in tasks:
            if self.bugs.has_key(t.bug.id):
                continue
            updates = []
            for s in statuses:
                attr = 'date_' + s
                date = getattr(t, attr)
                if not date:
                    continue
                if self.in_window(date):
                    updates.append(
                        "\t" + s + ": " + re.sub("\s.*$", "", str(date)))

            if updates:
                self.print_bugid(t)
                for u in updates:
                    print u
                print
        print

    def print_comments(self):
        tasks = self.user.searchTasks(bug_commenter=self.user)
        self.print_header("Commented Bugs")
        for t in tasks:
            if self.bugs.has_key(t.bug.id):
                continue
            for m in t.bug.messages:
                if m.owner_link != self.user.self_link:
                    continue
                if self.in_window(m.date_created):
                    self.print_bugid(t)
                    print
                    break
        print

    def print_reported(self):
        tasks = self.user.searchTasks(bug_reporter=self.user)
        self.print_header("Reported Bugs")
        for t in tasks:
            if self.bugs.has_key(t.bug.id):
                continue
            if self.in_window(t.bug.date_created):
                self.print_bugid(t)
                print

    def render(self):
        self.print_assignments()
        self.print_comments()
        self.print_reported()


def main():

    parser = OptionParser()
    parser.add_option('-u', '--user', dest='user',
        default=os.getenv('USER'),
        help='Specify the Launchpad user id.  '
             'Defaults to authenticated token owner.')
    parser.add_option('-w', '--window', dest='window', type='int',
        default=8,
        help='Number af days of past activity to look for.  '
             'Defaults to 8 days')

    options, arguments = parser.parse_args()

    report = Report(options.user, options.window)
    report.render()

if __name__ == "__main__":
    main()