1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 import traceback
17 import re
18 from twisted.internet import defer
19 try:
20 import email.utils as email_utils
21 email_utils = email_utils
22 except ImportError:
23
24 import email.Utils as email_utils
25
26 from buildbot.process.properties import Properties
27 from buildbot.schedulers import base
28
30 name = ""
31 label = ""
32 type = ""
33 default = ""
34 required = False
35 multiple = False
36 regex = None
37 debug=True
38
39 - def __init__(self, name, label=None, regex=None, **kw):
47
48 - def update_from_post(self, master, properties, changes, req):
49 args = req.args.get(self.name, [])
50 if len(args) == 0:
51 if self.required:
52 raise ValueError("'%s' needs to be specified" % (self.label))
53 if self.multiple:
54 args = self.default
55 else:
56 args = [self.default]
57 if self.regex:
58 for arg in args:
59 if not self.regex.match(arg):
60 raise ValueError("%s:'%s' does not match pattern '%s'"
61 % (self.label, arg, self.regex.pattern))
62 try:
63 arg = self.parse_from_args(args)
64 except Exception, e:
65
66
67 if self.debug:
68 traceback.print_exc()
69 raise e
70 if arg == None:
71 raise ValueError("need %s: no default provided by config"
72 % (self.name,))
73 properties[self.name] = arg
74
80
83
84
92
93
100
101
102 -class TextParameter(StringParameter):
103 type = "textarea"
104 cols = 80
105 rows = 20
106
107 - def value_to_text(self, value):
109
110
115
116
124
125
127 type = "text"
128 default = ""
129 size = 30
130 need_email = True
131
132 - def __init__(self, name="username", label="Your name:", **kw):
134
136 if self.need_email:
137 e = email_utils.parseaddr(s)
138 if e[0]=='' or e[1] == '':
139 raise ValueError("%s: please fill in email address in the "
140 " form User <email@email.com>" % (self.label,))
141 return s
142
143
145 type = "list"
146 choices = []
147 strict = True
148
150 if self.strict and not s in self.choices:
151 raise ValueError("'%s' does not belongs to list of available choices '%s'"%(s, self.choices))
152 return s
153
154
156 name = "inherit"
157 compatible_builds = None
158
159 - def update_from_post(self, master, properties, changes, req):
160 arg = req.args.get(self.name, [""])[0]
161 splitted_arg = arg.split(" ")[0].split("/")
162 if len(splitted_arg) != 2:
163 raise ValueError("bad build: %s"%(arg))
164 builder, num = splitted_arg
165 builder_status = master.status.getBuilder(builder)
166 if not builder_status:
167 raise ValueError("unknown builder: %s in %s"%(builder, arg))
168 b = builder_status.getBuild(int(num))
169 if not b:
170 raise ValueError("unknown build: %d in %s"%(num, arg))
171 props = {self.name:(arg.split(" ")[0])}
172 for name, value, source in b.getProperties().asList():
173 if source == "Force Build Form":
174 if name == "owner":
175 name = "orig_owner"
176 props[name] = value
177 properties.update(props)
178 changes.extend(b.changes)
179
180
182 type = "anyproperty"
183
184 - def update_from_post(self, master, properties, changes, req):
185 validation = master.config.validation
186 pname = req.args.get("%sname" % self.name, [""])[0]
187 pvalue = req.args.get("%svalue" % self.name, [""])[0]
188 if not pname:
189 return
190 pname_validate = validation['property_name']
191 pval_validate = validation['property_value']
192 if not pname_validate.match(pname) \
193 or not pval_validate.match(pvalue):
194 raise ValueError("bad property name='%s', value='%s'" % (pname, pvalue))
195 properties[pname] = pvalue
196
197
199
200 compare_attrs = ( 'name', 'builderNames', 'branch', 'reason',
201 'revision', 'repository', 'project', 'forcedProperties' )
202
203 - def __init__(self, name, builderNames,
204 branch=StringParameter(name="branch",default=""),
205 reason=StringParameter(name="reason", default="force build"),
206 revision=StringParameter(name="revision",default=""),
207 repository=StringParameter(name="repository",default=""),
208 project=StringParameter(name="project",default=""),
209 username=UserNameParameter(),
210 properties=[
211 AnyPropertyParameter("property1"),
212 AnyPropertyParameter("property2"),
213 AnyPropertyParameter("property3"),
214 AnyPropertyParameter("property4"),
215 ]):
230
233
236
238 """Called by the web UI.
239 Authentication is already done, thus owner is passed as argument
240 We check the parameters, and launch the build, if everything is correct
241 """
242 if not builder_name in self.builderNames:
243
244
245
246 return defer.succeed(None)
247 master = self.master
248 properties = {}
249 changeids = []
250
251
252
253 validation = master.config.validation
254 if self.branch.regex == None:
255 self.branch.regex = validation['branch']
256 if self.revision.regex == None:
257 self.revision.regex = validation['revision']
258
259 for param in self.all_fields:
260 if owner and param==self.username:
261 continue
262 param.update_from_post(master, properties, changeids, req)
263
264 changeids = map(lambda a: type(a)==int and a or a.number, changeids)
265
266 reason = properties[self.reason.name]
267 branch = properties[self.branch.name]
268 revision = properties[self.revision.name]
269 repository = properties[self.repository.name]
270 project = properties[self.project.name]
271 if owner is None:
272 owner = properties[self.username.name]
273
274 std_prop_names = [self.branch.name,
275 self.revision.name, self.repository.name,
276 self.project.name, self.username.name]
277 real_properties = Properties()
278 for pname, pvalue in properties.items():
279 if not pname in std_prop_names:
280 real_properties.setProperty(pname, pvalue, "Force Build Form")
281
282 real_properties.setProperty("owner", owner, "Force Build Form")
283
284 r = ("The web-page 'force build' button was pressed by '%s': %s\n"
285 % (owner, reason))
286
287 d = master.db.sourcestampsets.addSourceStampSet()
288 def add_master_with_setid(sourcestampsetid):
289 master.db.sourcestamps.addSourceStamp(
290 sourcestampsetid = sourcestampsetid,
291 branch=branch,
292 revision=revision, project=project,
293 repository=repository,changeids=changeids)
294 return sourcestampsetid
295
296 d.addCallback(add_master_with_setid)
297 def got_setid(sourcestampsetid):
298 return self.addBuildsetForSourceStamp(builderNames=[builder_name],
299 setid=sourcestampsetid, reason=r,
300 properties=real_properties)
301 d.addCallback(got_setid)
302 return d
303