1 from twisted
.python
import log
2 from twisted
.web
import xmlrpc
3 from buildbot
.status
.builder
import Results
4 from itertools
import count
6 class XMLRPCServer(xmlrpc
.XMLRPC
):
8 xmlrpc
.XMLRPC
.__init
__(self
)
10 def render(self
, req
):
11 # extract the IStatus and IControl objects for later use, since they
12 # come from the request object. They'll be the same each time, but
13 # they aren't available until the first request arrives.
14 self
.status
= req
.site
.buildbot_service
.getStatus()
15 self
.control
= req
.site
.buildbot_service
.getControl()
16 return xmlrpc
.XMLRPC
.render(self
, req
)
18 def xmlrpc_getAllBuilders(self
):
19 """Return a list of all builder names
21 log
.msg("getAllBuilders")
22 return self
.status
.getBuilderNames()
24 def xmlrpc_getLastBuildResults(self
, builder_name
):
25 """Return the result of the last build for the given builder
27 builder
= self
.status
.getBuilder(builder_name
)
28 lastbuild
= builder
.getBuild(-1)
29 return Results
[lastbuild
.getResults()]
31 def xmlrpc_getAllLastBuilds(self
, num_builds
):
32 """Return the last N completed builds for all builders.
34 'num_builds' is the number of builds to return
38 for name
in self
.status
.getBuilderNames():
39 all_builds
.extend(self
.xmlrpc_getLastBuilds(name
, num_builds
))
42 def xmlrpc_getLastBuilds(self
, builder_name
, num_builds
):
43 """Return the last N completed builds for the given builder.
44 'builder_name' is the name of the builder to query
45 'num_builds' is the number of builds to return
47 Each build is returned in the same form as xmlrpc_getAllBuildsInInterval
49 log
.msg("getLastBuilds: %s - %d" % (builder_name
, num_builds
))
50 builder
= self
.status
.getBuilder(builder_name
)
52 for build_number
in range(1, num_builds
+1):
53 build
= builder
.getBuild(-build_number
)
56 if not build
.isFinished():
58 (build_start
, build_end
) = build
.getTimes()
60 ss
= build
.getSourceStamp()
65 revision
= build
.getProperty("got_revision")
68 revision
= str(revision
)
70 result
= Results
[build
.getResults()]
71 if result
== 'failure':
72 fail_names
= result
= build
.getText()[1:]
74 for s
in build
.getSteps():
75 if s
.getName() in fail_names
:
76 reasons
.append(s
.getText())
78 result
= build
.getText()
80 answer
= (builder_name
,
86 Results
[build
.getResults()],
90 all_builds
.append((build_end
, answer
))
92 # now we've gotten all the builds we're interested in. Sort them by
94 all_builds
.sort(lambda a
,b
: cmp(a
[0], b
[0]))
95 # and remove the timestamps
96 all_builds
= [t
[1] for t
in all_builds
]
98 log
.msg("ready to go: %s" % (all_builds
,))
103 def xmlrpc_getAllBuildsInInterval(self
, start
, stop
):
104 """Return a list of builds that have completed after the 'start'
105 timestamp and before the 'stop' timestamp. This looks at all
108 The timestamps are integers, interpreted as standard unix timestamps
109 (seconds since epoch).
111 Each Build is returned as a tuple in the form::
112 (buildername, buildnumber, build_end, branchname, revision,
115 The buildnumber is an integer. 'build_end' is an integer (seconds
116 since epoch) specifying when the build finished.
118 The branchname is a string, which may be an empty string to indicate
119 None (i.e. the default branch). The revision is a string whose
120 meaning is specific to the VC system in use, and comes from the
121 'got_revision' build property. The results are expressed as a string,
122 one of ('success', 'warnings', 'failure', 'exception'). The text is a
123 list of short strings that ought to be joined by spaces and include
124 slightly more data about the results of the build.
126 #log.msg("start: %s %s %s" % (start, type(start), start.__class__))
127 log
.msg("getAllBuildsInInterval: %d - %d" % (start
, stop
))
130 for builder_name
in self
.status
.getBuilderNames():
131 builder
= self
.status
.getBuilder(builder_name
)
132 for build_number
in count(1):
133 build
= builder
.getBuild(-build_number
)
136 if not build
.isFinished():
138 (build_start
, build_end
) = build
.getTimes()
139 # in reality, builds are mostly ordered by start time. For
140 # the purposes of this method, we pretend that they are
141 # strictly ordered by end time, so that we can stop searching
142 # when we start seeing builds that are outside the window.
144 continue # keep looking
145 if build_end
< start
:
148 ss
= build
.getSourceStamp()
153 revision
= build
.getProperty("got_revision")
156 revision
= str(revision
)
158 answer
= (builder_name
,
163 Results
[build
.getResults()],
166 all_builds
.append((build_end
, answer
))
167 # we've gotten all the builds that we care about from this
168 # particular builder, so now we can continue on the next builder
170 # now we've gotten all the builds we're interested in. Sort them by
172 all_builds
.sort(lambda a
,b
: cmp(a
[0], b
[0]))
173 # and remove the timestamps
174 all_builds
= [t
[1] for t
in all_builds
]
176 log
.msg("ready to go: %s" % (all_builds
,))
180 def xmlrpc_getBuild(self
, builder_name
, build_number
):
181 """Return information about a specific build.
184 builder
= self
.status
.getBuilder(builder_name
)
185 build
= builder
.getBuild(build_number
)
187 info
['builder_name'] = builder
.getName()
188 info
['url'] = self
.status
.getURLForThing(build
) or ''
189 info
['reason'] = build
.getReason()
190 info
['slavename'] = build
.getSlavename()
191 info
['results'] = build
.getResults()
192 info
['text'] = build
.getText()
194 # Added to help out requests for build -N
195 info
['number'] = build
.number
196 ss
= build
.getSourceStamp()
200 info
['branch'] = str(branch
)
202 revision
= str(build
.getProperty("got_revision"))
205 info
['revision'] = str(revision
)
206 info
['start'], info
['end'] = build
.getTimes()
211 for s
in build
.getSteps():
213 stepinfo
['name'] = s
.getName()
214 stepinfo
['start'], stepinfo
['end'] = s
.getTimes()
215 stepinfo
['results'] = s
.getResults()
216 stepinfo
['text'] = s
.getText()
217 info_steps
.append(stepinfo
)
218 if info
['text'][0] == 'failed' and stepinfo
['name'] in info
['text']:
219 info
['reasons'].append(stepinfo
['text'])
220 step_names
[stepinfo
['name']] = stepinfo
221 info
['steps'] = info_steps
224 info
['full_error'] = {}
225 for l
in build
.getLogs():
227 name
= l
.getStep().getName()
228 loginfo
['name'] = name
+ "/" + l
.getName()
229 #loginfo['text'] = l.getText()
230 loginfo
['text'] = "HUGE"
231 if step_names
.get(name
):
232 if step_names
[name
]['text'][-1] == 'failed':
233 info
['full_error'][name
] = l
.getText()
234 info_logs
.append(loginfo
)
235 info
['logs'] = info_logs