1
2
3 """
4 bts -- manage bugs filed against ftp.debian.org
5
6 @contact: Debian FTP Master <ftpmaster@debian.org>
7 @copyright: 2009 Mike O'Connor <stew@vireo.org>
8 @copyright: 2010 Alexander Reichle-Schmehl <tolimar@debian.org>
9 @license: GNU General Public License version 2 or later
10 """
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 import sys
31 import re
32 import logging
33 log = logging.getLogger()
34
35 import apt_pkg
36 from daklib import utils
37 import debianbts as bts
38
39
41 print("""
42 SYNOPSIS
43 dak bts-categorize [options]
44
45 OPTIONS
46 -s
47 --simulate
48 Don't send email, instead output the lines that would be sent to
49 control@b.d.o.
50
51 -v
52 --verbose
53 Print more informational log messages
54
55 -q
56 --quiet
57 Suppress informational messages
58
59 -h
60 --help
61 Print this documentation.
62 """)
63
64
65 arguments = [('s', 'simulate', 'BtsCategorize::Options::Simulate'),
66 ('v', 'verbose', 'BtsCategorize::Options::Verbose'),
67 ('q', 'quiet', 'BtsCategorize::Options::Quiet'),
68 ('h', 'help', 'BtsCategorize::Options::Help'),
69 ('o', 'option', '', 'ArbItem')]
70
71
73 """
74 classify bugs using usertags based on the bug subject lines
75
76 >>> BugClassifier.rm_re.match( "RM: asdf" ) != None
77 True
78 >>> BugClassifier.rm_re.match( "[dak] Packages.diff/Index broken" ) != None
79 False
80 >>> BugClassifier.dak_re.match( "[dak] Packages.diff/Index broken" ) != None
81 True
82 """
83 rm_re = re.compile("^RM")
84 dak_re = re.compile(r"^\[dak\]")
85 arch_re = re.compile(r"^\[Architectures\]")
86 override_re = re.compile("^override")
87
88 classifiers = {rm_re: 'remove',
89 dak_re: 'dak',
90 arch_re: 'archs',
91 override_re: 'override'}
92
94 """
95 Returns a list of open bugs which have not yet been classified
96 by one of our usertags.
97 """
98
99 tagged_bugs = bts.get_usertag('ftp.debian.org@packages.debian.org')
100 tagged_bugs_ftp = []
101 for tags in tagged_bugs.keys():
102 tagged_bugs_ftp += tagged_bugs[tags]
103
104 return [bug for bug in bts.get_status(bts.get_bugs(package="ftp.debian.org"))
105 if bug.pending == 'pending' and bug.bug_num not in tagged_bugs_ftp]
106
108 """
109 if any of our classifiers match, return a newline terminated
110 command to set an appropriate usertag, otherwise return an
111 empty string
112 """
113 retval = ""
114
115 for classifier in self.classifiers.keys():
116 if classifier.match(bug.subject):
117 retval = "usertag %s %s\n" % (bug.bug_num,
118 self.classifiers[classifier])
119 break
120
121 if retval:
122 log.info(retval)
123 else:
124 log.debug("Unmatched: [%s] %s" % (bug.bug_num, bug.subject))
125
126 return retval
127
128 - def email_text(self):
129 controls = ""
130
131 bc = BugClassifier()
132 try:
133 for bug in bc.unclassified_bugs():
134 controls += bc.classify_bug(bug)
135
136 return controls
137 except:
138 log.error("couldn't retrieve bugs from soap interface: %s" % sys.exc_info()[0])
139 return None
140
141
143 global Cnf
144
145 Subst = {'__COMMANDS__': commands,
146 "__DAK_ADDRESS__": Cnf["Dinstall::MyAdminAddress"]}
147
148 bts_mail_message = utils.TemplateSubst(
149 Subst, Cnf["Dir::Templates"] + "/bts-categorize")
150
151 if simulate:
152 print(bts_mail_message)
153 else:
154 utils.send_mail(bts_mail_message)
155
156
158 """
159 for now, we just dump a list of commands that could be sent for
160 control@b.d.o
161 """
162 global Cnf
163 Cnf = utils.get_conf()
164
165 for arg in arguments:
166 opt = "BtsCategorize::Options::%s" % arg[1]
167 if opt not in Cnf:
168 Cnf[opt] = ""
169
170 packages = apt_pkg.parse_commandline(Cnf, arguments, sys.argv)
171 Options = Cnf.subtree('BtsCategorize::Options')
172
173 if Options["Help"]:
174 usage()
175 sys.exit(0)
176
177 if Options["Quiet"]:
178 level = logging.ERROR
179
180 elif Options["Verbose"]:
181 level = logging.DEBUG
182
183 else:
184 level = logging.INFO
185
186 logging.basicConfig(level=level,
187 format='%(asctime)s %(levelname)s %(message)s',
188 stream=sys.stderr)
189
190 body = BugClassifier().email_text()
191
192 if body:
193 send_email(body, Options["Simulate"])
194
195 else:
196 log.info("nothing to do")
197
198
199 if __name__ == '__main__':
200
201
202 main()
203