]> andersk Git - jira-zephyrbot.git/blob - jirabot.py
6198303a2da4efc7fec85f03de4ac05d86fda409
[jira-zephyrbot.git] / jirabot.py
1 #!/usr/bin/python
2 import cStringIO
3 import calendar
4 import feedparser
5 import formatter
6 import htmllib
7 import mechanize
8 import os
9 import random
10 import string
11 import time
12 import traceback
13 import urlparse
14 import zephyr
15
16 zephyr_sender = 'jira'
17 zephyr_class = 'andersk-test'
18 time_file = 'jirabot.time'
19
20 def jira_init():
21     b = mechanize.Browser()
22     b.set_handle_robots(False)
23     b.add_client_certificate("https://idp.mit.edu:9443", "cert.pem", "cert.pem")
24     b.addheaders = [("Accept-Language", "en-us,en;q=0.5"),]
25     return b
26
27 def jira_login(b):
28     b.open("https://jira.mit.edu/jira/secure/Dashboard.jspa")
29     try:
30         b.follow_link(text="MIT Touchstone")
31     except mechanize.LinkNotFoundError:
32         return
33     if (urlparse.urlparse(b.geturl())[1] == "jira.mit.edu"):
34         return
35     b.select_form("wayfForm1")
36     b.submit()
37     b.select_form(predicate=lambda f: any(c.name == 'login_certificate'
38                                           for c in f.controls))
39     b.submit()
40     b.select_form(nr=0)
41     b.submit()
42
43 def feed_to_zephyrs(thing, rss, parse):
44     zephyrs = []
45     try:
46         feed = feedparser.parse(rss)
47         for e in feed.entries:
48             global old_time, new_time
49             t = int(calendar.timegm(e.date_parsed))
50             if t <= old_time:
51                 continue
52             if t > new_time:
53                 new_time = t
54             try:
55                 z = parse(e)
56             except:
57                 z = zerror("Error parsing " + thing + ":\n" + e.id + "\n" + traceback.format_exc())
58             zephyrs.append((t, z))
59     except:
60         zephyrs.append((0, zerror("Error parsing " + thing + "s feed:\n" + traceback.format_exc())))
61     return zephyrs
62
63 def parse_issue(e):
64     issue = urlparse.urlparse(e.id)[2].rsplit('/', 1)[1]
65     url = e.id
66     msg = e.id + "\nThis issue was updated."
67
68     return zephyr.ZNotice(
69         sender=zephyr_sender,
70         auth=False,
71         opcode='auto',
72         cls=zephyr_class,
73         instance=issue,
74         fields=[e.title, msg],
75     )
76
77 def parse_comment(e):
78     url = urlparse.urlunsplit(urlparse.urlparse(e.id)[0:3] + (None,None))
79     issue = url.rsplit('/', 1)[1]
80
81     s = cStringIO.StringIO()
82     parser = htmllib.HTMLParser(formatter.AbstractFormatter(formatter.DumbWriter(s)))
83     parser.feed(e.summary.rsplit('<table>', 1)[0])
84     parser.close()
85     s.seek(0)
86     comment = s.read()
87
88     msg = e.author + " added a comment:\n" + comment.rstrip()
89
90     return zephyr.ZNotice(
91         sender=zephyr_sender,
92         auth=False,
93         opcode='auto',
94         cls=zephyr_class,
95         instance=issue,
96         fields=[e.title, msg],
97     )
98
99 def zerror(msg):
100     return zephyr.ZNotice(
101         sender=zephyr_sender,
102         auth=False,
103         opcode='auto',
104         cls=zephyr_class,
105         instance='jira-error',
106         fields=['Jira bot error', msg]
107     )
108
109 b = jira_init()
110 zephyr.init()
111
112 while True:
113     jira_login(b)
114     b.open("https://jira.mit.edu/jira/sr/jira.issueviews:searchrequest-rss/temp/SearchRequest.xml?&pid=10185&updated%3Aprevious=-1w&sorter/field=updated&sorter/order=DESC&tempMax=1000")
115     issues_rss = b.response().read()
116     b.open("https://jira.mit.edu/jira/sr/jira.issueviews:searchrequest-comments-rss/temp/SearchRequest.xml?&pid=10185&updated%3Aprevious=-1w&sorter/field=updated&sorter/order=DESC&tempMax=1000")
117     comments_rss = b.response().read()
118
119     time_file_new = time_file + '.' + ''.join(random.sample(string.letters, 8))
120
121     try:
122         os.rename(time_file, time_file_new)
123     except OSError:
124         print "warning: could not acquire timestamp lock"
125         time.sleep(17)
126         continue
127
128     old_time = int(open(time_file_new).read())
129     new_time = old_time
130
131     zephyrs = (feed_to_zephyrs('issue', issues_rss, parse_issue) +
132                feed_to_zephyrs('comment', comments_rss, parse_comment))
133
134     open(time_file_new, 'w').write(str(new_time))
135
136     os.rename(time_file_new, time_file)
137
138     zephyrs.sort(key=lambda tz: tz[0])
139     for (t, z) in zephyrs:
140         z.send()
141     time.sleep(60)
This page took 0.138296 seconds and 3 git commands to generate.