Package buildbot :: Module interfaces
[frames] | no frames]

Source Code for Module buildbot.interfaces

   1  # This file is part of Buildbot.  Buildbot is free software: you can 
   2  # redistribute it and/or modify it under the terms of the GNU General Public 
   3  # License as published by the Free Software Foundation, version 2. 
   4  # 
   5  # This program is distributed in the hope that it will be useful, but WITHOUT 
   6  # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
   7  # FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more 
   8  # details. 
   9  # 
  10  # You should have received a copy of the GNU General Public License along with 
  11  # this program; if not, write to the Free Software Foundation, Inc., 51 
  12  # Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 
  13  # 
  14  # Copyright Buildbot Team Members 
  15   
  16  """Interface documentation. 
  17   
  18  Define the interfaces that are implemented by various buildbot classes. 
  19  """ 
  20  # E0211: Method has no argument 
  21  # E0213: Method should have "self" as first argument 
  22  # pylint: disable-msg=E0211,E0213 
  23   
  24  from zope.interface import Interface, Attribute 
  25   
  26  # exceptions that can be raised while trying to start a build 
27 -class NoSlaveError(Exception):
28 pass
29 -class BuilderInUseError(Exception):
30 pass
31 -class BuildSlaveTooOldError(Exception):
32 pass
33 -class LatentBuildSlaveFailedToSubstantiate(Exception):
34 pass
35 36 # other exceptions
37 -class BuildbotNotRunningError(Exception):
38 pass
39
40 -class ParameterError(Exception):
41 pass
42
43 -class IChangeSource(Interface):
44 """Object which feeds Change objects to the changemaster. When files or 45 directories are changed and the version control system provides some 46 kind of notification, this object should turn it into a Change object 47 and pass it through:: 48 49 self.changemaster.addChange(change) 50 """ 51
52 - def describe():
53 """Should return a string which briefly describes this source. This 54 string will be displayed in an HTML status page."""
55
56 -class IScheduler(Interface):
57 """I watch for Changes in the source tree and decide when to trigger 58 Builds. I create BuildSet objects and submit them to the BuildMaster. I 59 am a service, and the BuildMaster is always my parent. 60 61 @ivar properties: properties to be applied to all builds started by this 62 scheduler 63 @type properties: L<buildbot.process.properties.Properties> 64 """ 65
66 - def addChange(change):
67 """A Change has just been dispatched by one of the ChangeSources. 68 Each Scheduler will receive this Change. I may decide to start a 69 build as a result, or I might choose to ignore it."""
70
71 - def listBuilderNames():
72 """Return a list of strings indicating the Builders that this 73 Scheduler might feed."""
74
76 """Return a list of timestamps for any builds that are waiting in the 77 tree-stable-timer queue. This is only relevant for Change-based 78 schedulers, all others can just return an empty list."""
79 # TODO: it might be nice to make this into getPendingBuildSets, which 80 # would let someone subscribe to the buildset being finished. 81 # However, the Scheduler doesn't actually create the buildset until 82 # it gets submitted, so doing this would require some major rework. 83
84 -class IUpstreamScheduler(Interface):
85 """This marks an IScheduler as being eligible for use as the 'upstream=' 86 argument to a buildbot.scheduler.Dependent instance.""" 87
88 - def subscribeToSuccessfulBuilds(target):
89 """Request that the target callbable be invoked after every 90 successful buildset. The target will be called with a single 91 argument: the SourceStamp used by the successful builds."""
92
93 - def listBuilderNames():
94 """Return a list of strings indicating the Builders that this 95 Scheduler might feed."""
96
97 -class IDownstreamScheduler(Interface):
98 """This marks an IScheduler to be listening to other schedulers. 99 On reconfigs, these might get notified to check if their upstream 100 scheduler are stil the same.""" 101
103 """Check if the upstream scheduler is still alive, and if not, 104 get a new upstream object from the master."""
105 106
107 -class ISourceStamp(Interface):
108 """ 109 @cvar branch: branch from which source was drawn 110 @type branch: string or None 111 112 @cvar revision: revision of the source, or None to use CHANGES 113 @type revision: varies depending on VC 114 115 @cvar patch: patch applied to the source, or None if no patch 116 @type patch: None or tuple (level diff) 117 118 @cvar changes: the source step should check out the latest revision 119 in the given changes 120 @type changes: tuple of L{buildbot.changes.changes.Change} instances, 121 all of which are on the same branch 122 123 @cvar project: project this source code represents 124 @type project: string 125 126 @cvar repository: repository from which source was drawn 127 @type repository: string 128 """ 129
130 - def canBeMergedWith(self, other):
131 """ 132 Can this SourceStamp be merged with OTHER? 133 """
134
135 - def mergeWith(self, others):
136 """Generate a SourceStamp for the merger of me and all the other 137 SourceStamps. This is called by a Build when it starts, to figure 138 out what its sourceStamp should be."""
139
140 - def getAbsoluteSourceStamp(self, got_revision):
141 """Get a new SourceStamp object reflecting the actual revision found 142 by a Source step."""
143
144 - def getText(self):
145 """Returns a list of strings to describe the stamp. These are 146 intended to be displayed in a narrow column. If more space is 147 available, the caller should join them together with spaces before 148 presenting them to the user."""
149
150 -class IEmailSender(Interface):
151 """I know how to send email, and can be used by other parts of the 152 Buildbot to contact developers.""" 153 pass
154
155 -class IEmailLookup(Interface):
156 - def getAddress(user):
157 """Turn a User-name string into a valid email address. Either return 158 a string (with an @ in it), None (to indicate that the user cannot 159 be reached by email), or a Deferred which will fire with the same."""
160
161 -class IStatus(Interface):
162 """I am an object, obtainable from the buildmaster, which can provide 163 status information.""" 164
165 - def getProjectName():
166 """Return the name of the project that this Buildbot is working 167 for."""
168 - def getProjectURL():
169 """Return the URL of this Buildbot's project."""
170 - def getBuildbotURL():
171 """Return the URL of the top-most Buildbot status page, or None if 172 this Buildbot does not provide a web status page."""
173 - def getURLForThing(thing):
174 """Return the URL of a page which provides information on 'thing', 175 which should be an object that implements one of the status 176 interfaces defined in L{buildbot.interfaces}. Returns None if no 177 suitable page is available (or if no Waterfall is running)."""
178
179 - def getChangeSources():
180 """Return a list of IChangeSource objects."""
181
182 - def getChange(number):
183 """Return an IChange object."""
184
185 - def getSchedulers():
186 """Return a list of ISchedulerStatus objects for all 187 currently-registered Schedulers."""
188
189 - def getBuilderNames(categories=None):
190 """Return a list of the names of all current Builders."""
191 - def getBuilder(name):
192 """Return the IBuilderStatus object for a given named Builder. Raises 193 KeyError if there is no Builder by that name."""
194
195 - def getSlaveNames():
196 """Return a list of buildslave names, suitable for passing to 197 getSlave()."""
198 - def getSlave(name):
199 """Return the ISlaveStatus object for a given named buildslave."""
200
201 - def getBuildSets():
202 """Return a list of active (non-finished) IBuildSetStatus objects."""
203
204 - def generateFinishedBuilds(builders=[], branches=[], 205 num_builds=None, finished_before=None, 206 max_search=200):
207 """Return a generator that will produce IBuildStatus objects each 208 time you invoke its .next() method, starting with the most recent 209 finished build and working backwards. 210 211 @param builders: this is a list of Builder names, and the generator 212 will only produce builds that ran on the given 213 Builders. If the list is empty, produce builds from 214 all Builders. 215 216 @param branches: this is a list of branch names, and the generator 217 will only produce builds that used the given 218 branches. If the list is empty, produce builds from 219 all branches. 220 221 @param num_builds: the generator will stop after providing this many 222 builds. The default of None means to produce as 223 many builds as possible. 224 225 @type finished_before: int: a timestamp, seconds since the epoch 226 @param finished_before: if provided, do not produce any builds that 227 finished after the given timestamp. 228 229 @type max_search: int 230 @param max_search: this method may have to examine a lot of builds 231 to find some that match the search parameters, 232 especially if there aren't any matching builds. 233 This argument imposes a hard limit on the number 234 of builds that will be examined within any given 235 Builder. 236 """
237
238 - def subscribe(receiver):
239 """Register an IStatusReceiver to receive new status events. The 240 receiver will immediately be sent a set of 'builderAdded' messages 241 for all current builders. It will receive further 'builderAdded' and 242 'builderRemoved' messages as the config file is reloaded and builders 243 come and go. It will also receive 'buildsetSubmitted' messages for 244 all outstanding BuildSets (and each new BuildSet that gets 245 submitted). No additional messages will be sent unless the receiver 246 asks for them by calling .subscribe on the IBuilderStatus objects 247 which accompany the addedBuilder message."""
248
249 - def unsubscribe(receiver):
250 """Unregister an IStatusReceiver. No further status messgaes will be 251 delivered."""
252
253 -class IBuildSetStatus(Interface):
254 """I represent a set of Builds, each run on a separate Builder but all 255 using the same source tree.""" 256
257 - def getSourceStamp():
258 """Return a SourceStamp object which can be used to re-create 259 the source tree that this build used. 260 261 This method will return None if the source information is no longer 262 available.""" 263 pass
264 - def getReason():
265 pass
266 - def getID():
267 """Return the BuildSet's ID string, if any. The 'try' feature uses a 268 random string as a BuildSetID to relate submitted jobs with the 269 resulting BuildSet."""
270 - def getResponsibleUsers():
271 pass # not implemented
272 - def getInterestedUsers():
273 pass # not implemented
274 - def getBuilderNames():
275 """Return a list of the names of all Builders on which this set will 276 do builds."""
277 - def getBuildRequests():
278 """Return a list of IBuildRequestStatus objects that represent my 279 component Builds. This list might correspond to the Builders named by 280 getBuilderNames(), but if builder categories are used, or 'Builder 281 Aliases' are implemented, then they may not."""
282 - def isFinished():
283 pass
284 - def waitUntilSuccess():
285 """Return a Deferred that fires (with this IBuildSetStatus object) 286 when the outcome of the BuildSet is known, i.e., upon the first 287 failure, or after all builds complete successfully."""
288 - def waitUntilFinished():
289 """Return a Deferred that fires (with this IBuildSetStatus object) 290 when all builds have finished."""
291 - def getResults():
292 """Return SUCCESS/FAILURE, or None if the buildset is not finished 293 yet"""
294 295
296 -class IBuildRequestStatus(Interface):
297 """I represent a request to build a particular set of source code on a 298 particular Builder. These requests may be merged by the time they are 299 finally turned into a Build.""" 300
301 - def getSourceStamp():
302 """Return a SourceStamp object which can be used to re-create 303 the source tree that this build used. This method will 304 return an absolute SourceStamp if possible, and its results 305 may change as the build progresses. Specifically, a "HEAD" 306 build may later be more accurately specified by an absolute 307 SourceStamp with the specific revision information. 308 309 This method will return None if the source information is no longer 310 available.""" 311 pass
312 - def getBuilderName():
313 pass
314 - def getBuilds():
315 """Return a list of IBuildStatus objects for each Build that has been 316 started in an attempt to satify this BuildRequest."""
317
318 - def subscribe(observer):
319 """Register a callable that will be invoked (with a single 320 IBuildStatus object) for each Build that is created to satisfy this 321 request. There may be multiple Builds created in an attempt to handle 322 the request: they may be interrupted by the user or abandoned due to 323 a lost slave. The last Build (the one which actually gets to run to 324 completion) is said to 'satisfy' the BuildRequest. The observer will 325 be called once for each of these Builds, both old and new."""
326 - def unsubscribe(observer):
327 """Unregister the callable that was registered with subscribe()."""
328 - def getSubmitTime():
329 """Return the time when this request was submitted"""
330 - def setSubmitTime(t):
331 """Sets the time when this request was submitted"""
332 333
334 -class ISlaveStatus(Interface):
335 - def getName():
336 """Return the name of the build slave."""
337
338 - def getAdmin():
339 """Return a string with the slave admin's contact data."""
340
341 - def getHost():
342 """Return a string with the slave host info."""
343
344 - def isConnected():
345 """Return True if the slave is currently online, False if not."""
346
347 - def lastMessageReceived():
348 """Return a timestamp (seconds since epoch) indicating when the most 349 recent message was received from the buildslave."""
350
351 -class ISchedulerStatus(Interface):
352 - def getName():
353 """Return the name of this Scheduler (a string)."""
354
355 - def getPendingBuildsets():
356 """Return an IBuildSet for all BuildSets that are pending. These 357 BuildSets are waiting for their tree-stable-timers to expire."""
358 # TODO: this is not implemented anywhere 359 360
361 -class IBuilderStatus(Interface):
362 - def getName():
363 """Return the name of this Builder (a string)."""
364
365 - def getCategory():
366 """Return the category of this builder (a string)."""
367
368 - def getState():
369 # TODO: this isn't nearly as meaningful as it used to be 370 """Return a tuple (state, builds) for this Builder. 'state' is the 371 so-called 'big-status', indicating overall status (as opposed to 372 which step is currently running). It is a string, one of 'offline', 373 'idle', or 'building'. 'builds' is a list of IBuildStatus objects 374 (possibly empty) representing the currently active builds."""
375
376 - def getSlaves():
377 """Return a list of ISlaveStatus objects for the buildslaves that are 378 used by this builder."""
379
380 - def getPendingBuilds():
381 """Return an IBuildRequestStatus object for all upcoming builds 382 (those which are ready to go but which are waiting for a buildslave 383 to be available."""
384
385 - def getCurrentBuilds():
386 """Return a list containing an IBuildStatus object for each build 387 currently in progress."""
388 # again, we could probably provide an object for 'waiting' and 389 # 'interlocked' too, but things like the Change list might still be 390 # subject to change 391
392 - def getLastFinishedBuild():
393 """Return the IBuildStatus object representing the last finished 394 build, which may be None if the builder has not yet finished any 395 builds."""
396
397 - def getBuild(number):
398 """Return an IBuildStatus object for a historical build. Each build 399 is numbered (starting at 0 when the Builder is first added), 400 getBuild(n) will retrieve the Nth such build. getBuild(-n) will 401 retrieve a recent build, with -1 being the most recent build 402 started. If the Builder is idle, this will be the same as 403 getLastFinishedBuild(). If the Builder is active, it will be an 404 unfinished build. This method will return None if the build is no 405 longer available. Older builds are likely to have less information 406 stored: Logs are the first to go, then Steps."""
407
408 - def getEvent(number):
409 """Return an IStatusEvent object for a recent Event. Builders 410 connecting and disconnecting are events, as are ping attempts. 411 getEvent(-1) will return the most recent event. Events are numbered, 412 but it probably doesn't make sense to ever do getEvent(+n)."""
413
414 - def generateFinishedBuilds(branches=[], 415 num_builds=None, 416 max_buildnum=None, finished_before=None, 417 max_search=200, 418 ):
419 """Return a generator that will produce IBuildStatus objects each 420 time you invoke its .next() method, starting with the most recent 421 finished build, then the previous build, and so on back to the oldest 422 build available. 423 424 @param branches: this is a list of branch names, and the generator 425 will only produce builds that involve the given 426 branches. If the list is empty, the generator will 427 produce all builds regardless of what branch they 428 used. 429 430 @param num_builds: if provided, the generator will stop after 431 providing this many builds. The default of None 432 means to produce as many builds as possible. 433 434 @param max_buildnum: if provided, the generator will start by 435 providing the build with this number, or the 436 highest-numbered preceding build (i.e. the 437 generator will not produce any build numbered 438 *higher* than max_buildnum). The default of None 439 means to start with the most recent finished 440 build. -1 means the same as None. -2 means to 441 start with the next-most-recent completed build, 442 etc. 443 444 @type finished_before: int: a timestamp, seconds since the epoch 445 @param finished_before: if provided, do not produce any builds that 446 finished after the given timestamp. 447 448 @type max_search: int 449 @param max_search: this method may have to examine a lot of builds 450 to find some that match the search parameters, 451 especially if there aren't any matching builds. 452 This argument imposes a hard limit on the number 453 of builds that will be examined. 454 """
455
456 - def subscribe(receiver):
457 """Register an IStatusReceiver to receive new status events. The 458 receiver will be given builderChangedState, buildStarted, and 459 buildFinished messages."""
460
461 - def unsubscribe(receiver):
462 """Unregister an IStatusReceiver. No further status messgaes will be 463 delivered."""
464
465 -class IEventSource(Interface):
466 - def eventGenerator(branches=[], categories=[], committers=[], minTime=0):
467 """This function creates a generator which will yield all of this 468 object's status events, starting with the most recent and progressing 469 backwards in time. These events provide the IStatusEvent interface. 470 At the moment they are all instances of buildbot.status.builder.Event 471 or buildbot.status.builder.BuildStepStatus . 472 473 @param branches: a list of branch names. The generator should only 474 return events that are associated with these branches. If the list is 475 empty, events for all branches should be returned (i.e. an empty list 476 means 'accept all' rather than 'accept none'). 477 478 @param categories: a list of category names. The generator 479 should only return events that are categorized within the 480 given category. If the list is empty, events for all 481 categories should be returned. 482 483 @param comitters: a list of committers. The generator should only 484 return events caused by one of the listed committers. If the list is 485 empty or None, events from every committers should be returned. 486 487 @param minTime: a timestamp. Do not generate events occuring prior to 488 this timestamp. 489 """
490
491 -class IBuildStatus(Interface):
492 """I represent the status of a single Build/BuildRequest. It could be 493 in-progress or finished.""" 494
495 - def getBuilder():
496 """ 497 Return the BuilderStatus that owns this build. 498 499 @rtype: implementor of L{IBuilderStatus} 500 """
501
502 - def isFinished():
503 """Return a boolean. True means the build has finished, False means 504 it is still running."""
505
506 - def waitUntilFinished():
507 """Return a Deferred that will fire when the build finishes. If the 508 build has already finished, this deferred will fire right away. The 509 callback is given this IBuildStatus instance as an argument."""
510
511 - def getProperty(propname):
512 """Return the value of the build property with the given name. Raises 513 KeyError if there is no such property on this build."""
514
515 - def getReason():
516 """Return a string that indicates why the build was run. 'changes', 517 'forced', and 'periodic' are the most likely values. 'try' will be 518 added in the future."""
519
520 - def getSourceStamp():
521 """Return a SourceStamp object which can be used to re-create 522 the source tree that this build used. 523 524 This method will return None if the source information is no longer 525 available."""
526 # TODO: it should be possible to expire the patch but still remember 527 # that the build was r123+something. 528
529 - def getChanges():
530 """Return a list of Change objects which represent which source 531 changes went into the build."""
532
533 - def getResponsibleUsers():
534 """Return a list of Users who are to blame for the changes that went 535 into this build. If anything breaks (at least anything that wasn't 536 already broken), blame them. Specifically, this is the set of users 537 who were responsible for the Changes that went into this build. Each 538 User is a string, corresponding to their name as known by the VC 539 repository."""
540
541 - def getInterestedUsers():
542 """Return a list of Users who will want to know about the results of 543 this build. This is a superset of getResponsibleUsers(): it adds 544 people who are interested in this build but who did not actually 545 make the Changes that went into it (build sheriffs, code-domain 546 owners)."""
547
548 - def getNumber():
549 """Within each builder, each Build has a number. Return it."""
550
551 - def getPreviousBuild():
552 """Convenience method. Returns None if the previous build is 553 unavailable."""
554
555 - def getSteps():
556 """Return a list of IBuildStepStatus objects. For invariant builds 557 (those which always use the same set of Steps), this should always 558 return the complete list, however some of the steps may not have 559 started yet (step.getTimes()[0] will be None). For variant builds, 560 this may not be complete (asking again later may give you more of 561 them)."""
562
563 - def getTimes():
564 """Returns a tuple of (start, end). 'start' and 'end' are the times 565 (seconds since the epoch) when the Build started and finished. If 566 the build is still running, 'end' will be None."""
567 568 # while the build is running, the following methods make sense. 569 # Afterwards they return None 570
571 - def getETA():
572 """Returns the number of seconds from now in which the build is 573 expected to finish, or None if we can't make a guess. This guess will 574 be refined over time."""
575
576 - def getCurrentStep():
577 """Return an IBuildStepStatus object representing the currently 578 active step."""
579 580 # Once you know the build has finished, the following methods are legal. 581 # Before ths build has finished, they all return None. 582
583 - def getSlavename():
584 """Return the name of the buildslave which handled this build."""
585
586 - def getText():
587 """Returns a list of strings to describe the build. These are 588 intended to be displayed in a narrow column. If more space is 589 available, the caller should join them together with spaces before 590 presenting them to the user."""
591
592 - def getResults():
593 """Return a constant describing the results of the build: one of the 594 constants in buildbot.status.builder: SUCCESS, WARNINGS, 595 FAILURE, SKIPPED or EXCEPTION."""
596
597 - def getLogs():
598 """Return a list of logs that describe the build as a whole. Some 599 steps will contribute their logs, while others are are less important 600 and will only be accessible through the IBuildStepStatus objects. 601 Each log is an object which implements the IStatusLog interface."""
602
603 - def getTestResults():
604 """Return a dictionary that maps test-name tuples to ITestResult 605 objects. This may return an empty or partially-filled dictionary 606 until the build has completed."""
607 608 # subscription interface 609
610 - def subscribe(receiver, updateInterval=None):
611 """Register an IStatusReceiver to receive new status events. The 612 receiver will be given stepStarted and stepFinished messages. If 613 'updateInterval' is non-None, buildETAUpdate messages will be sent 614 every 'updateInterval' seconds."""
615
616 - def unsubscribe(receiver):
617 """Unregister an IStatusReceiver. No further status messgaes will be 618 delivered."""
619
620 -class ITestResult(Interface):
621 """I describe the results of a single unit test.""" 622
623 - def getName():
624 """Returns a tuple of strings which make up the test name. Tests may 625 be arranged in a hierarchy, so looking for common prefixes may be 626 useful."""
627
628 - def getResults():
629 """Returns a constant describing the results of the test: SUCCESS, 630 WARNINGS, FAILURE."""
631
632 - def getText():
633 """Returns a list of short strings which describe the results of the 634 test in slightly more detail. Suggested components include 635 'failure', 'error', 'passed', 'timeout'."""
636
637 - def getLogs():
638 # in flux, it may be possible to provide more structured information 639 # like python Failure instances 640 """Returns a dictionary of test logs. The keys are strings like 641 'stdout', 'log', 'exceptions'. The values are strings."""
642 643
644 -class IBuildStepStatus(Interface):
645 """I hold status for a single BuildStep.""" 646
647 - def getName():
648 """Returns a short string with the name of this step. This string 649 may have spaces in it."""
650
651 - def getBuild():
652 """Returns the IBuildStatus object which contains this step."""
653
654 - def getTimes():
655 """Returns a tuple of (start, end). 'start' and 'end' are the times 656 (seconds since the epoch) when the Step started and finished. If the 657 step has not yet started, 'start' will be None. If the step is still 658 running, 'end' will be None."""
659
660 - def getExpectations():
661 """Returns a list of tuples (name, current, target). Each tuple 662 describes a single axis along which the step's progress can be 663 measured. 'name' is a string which describes the axis itself, like 664 'filesCompiled' or 'tests run' or 'bytes of output'. 'current' is a 665 number with the progress made so far, while 'target' is the value 666 that we expect (based upon past experience) to get to when the build 667 is finished. 668 669 'current' will change over time until the step is finished. It is 670 'None' until the step starts. When the build is finished, 'current' 671 may or may not equal 'target' (which is merely the expectation based 672 upon previous builds)."""
673
674 - def getURLs():
675 """Returns a dictionary of URLs. Each key is a link name (a short 676 string, like 'results' or 'coverage'), and each value is a URL. These 677 links will be displayed along with the LogFiles. 678 """
679
680 - def getLogs():
681 """Returns a list of IStatusLog objects. If the step has not yet 682 finished, this list may be incomplete (asking again later may give 683 you more of them)."""
684 685
686 - def isFinished():
687 """Return a boolean. True means the step has finished, False means it 688 is still running."""
689
690 - def waitUntilFinished():
691 """Return a Deferred that will fire when the step finishes. If the 692 step has already finished, this deferred will fire right away. The 693 callback is given this IBuildStepStatus instance as an argument."""
694 695 # while the step is running, the following methods make sense. 696 # Afterwards they return None 697
698 - def getETA():
699 """Returns the number of seconds from now in which the step is 700 expected to finish, or None if we can't make a guess. This guess will 701 be refined over time."""
702 703 # Once you know the step has finished, the following methods are legal. 704 # Before ths step has finished, they all return None. 705
706 - def getText():
707 """Returns a list of strings which describe the step. These are 708 intended to be displayed in a narrow column. If more space is 709 available, the caller should join them together with spaces before 710 presenting them to the user."""
711
712 - def getResults():
713 """Return a tuple describing the results of the step: (result, 714 strings). 'result' is one of the constants in 715 buildbot.status.builder: SUCCESS, WARNINGS, FAILURE, or SKIPPED. 716 'strings' is an optional list of strings that the step wants to 717 append to the overall build's results. These strings are usually 718 more terse than the ones returned by getText(): in particular, 719 successful Steps do not usually contribute any text to the overall 720 build."""
721 722 # subscription interface 723
724 - def subscribe(receiver, updateInterval=10):
725 """Register an IStatusReceiver to receive new status events. The 726 receiver will be given logStarted and logFinished messages. It will 727 also be given a ETAUpdate message every 'updateInterval' seconds."""
728
729 - def unsubscribe(receiver):
730 """Unregister an IStatusReceiver. No further status messgaes will be 731 delivered."""
732
733 -class IStatusEvent(Interface):
734 """I represent a Builder Event, something non-Build related that can 735 happen to a Builder.""" 736
737 - def getTimes():
738 """Returns a tuple of (start, end) like IBuildStepStatus, but end==0 739 indicates that this is a 'point event', which has no duration. 740 SlaveConnect/Disconnect are point events. Ping is not: it starts 741 when requested and ends when the response (positive or negative) is 742 returned"""
743
744 - def getText():
745 """Returns a list of strings which describe the event. These are 746 intended to be displayed in a narrow column. If more space is 747 available, the caller should join them together with spaces before 748 presenting them to the user."""
749 750 751 LOG_CHANNEL_STDOUT = 0 752 LOG_CHANNEL_STDERR = 1 753 LOG_CHANNEL_HEADER = 2 754
755 -class IStatusLog(Interface):
756 """I represent a single Log, which is a growing list of text items that 757 contains some kind of output for a single BuildStep. I might be finished, 758 in which case this list has stopped growing. 759 760 Each Log has a name, usually something boring like 'log' or 'output'. 761 These names are not guaranteed to be unique, however they are usually 762 chosen to be useful within the scope of a single step (i.e. the Compile 763 step might produce both 'log' and 'warnings'). The name may also have 764 spaces. If you want something more globally meaningful, at least within a 765 given Build, try:: 766 767 '%s.%s' % (log.getStep.getName(), log.getName()) 768 769 The Log can be presented as plain text, or it can be accessed as a list 770 of items, each of which has a channel indicator (header, stdout, stderr) 771 and a text chunk. An HTML display might represent the interleaved 772 channels with different styles, while a straight download-the-text 773 interface would just want to retrieve a big string. 774 775 The 'header' channel is used by ShellCommands to prepend a note about 776 which command is about to be run ('running command FOO in directory 777 DIR'), and append another note giving the exit code of the process. 778 779 Logs can be streaming: if the Log has not yet finished, you can 780 subscribe to receive new chunks as they are added. 781 782 A ShellCommand will have a Log associated with it that gathers stdout 783 and stderr. Logs may also be created by parsing command output or 784 through other synthetic means (grepping for all the warnings in a 785 compile log, or listing all the test cases that are going to be run). 786 Such synthetic Logs are usually finished as soon as they are created.""" 787 788
789 - def getName():
790 """Returns a short string with the name of this log, probably 'log'. 791 """
792
793 - def getStep():
794 """Returns the IBuildStepStatus which owns this log."""
795 # TODO: can there be non-Step logs? 796
797 - def isFinished():
798 """Return a boolean. True means the log has finished and is closed, 799 False means it is still open and new chunks may be added to it."""
800
801 - def waitUntilFinished():
802 """Return a Deferred that will fire when the log is closed. If the 803 log has already finished, this deferred will fire right away. The 804 callback is given this IStatusLog instance as an argument."""
805
806 - def subscribe(receiver, catchup):
807 """Register an IStatusReceiver to receive chunks (with logChunk) as 808 data is added to the Log. If you use this, you will also want to use 809 waitUntilFinished to find out when the listener can be retired. 810 Subscribing to a closed Log is a no-op. 811 812 If 'catchup' is True, the receiver will immediately be sent a series 813 of logChunk messages to bring it up to date with the partially-filled 814 log. This allows a status client to join a Log already in progress 815 without missing any data. If the Log has already finished, it is too 816 late to catch up: just do getText() instead. 817 818 If the Log is very large, the receiver will be called many times with 819 a lot of data. There is no way to throttle this data. If the receiver 820 is planning on sending the data on to somewhere else, over a narrow 821 connection, you can get a throttleable subscription by using 822 C{subscribeConsumer} instead."""
823
824 - def unsubscribe(receiver):
825 """Remove a receiver previously registered with subscribe(). Attempts 826 to remove a receiver which was not previously registered is a no-op. 827 """
828
829 - def subscribeConsumer(consumer):
830 """Register an L{IStatusLogConsumer} to receive all chunks of the 831 logfile, including all the old entries and any that will arrive in 832 the future. The consumer will first have their C{registerProducer} 833 method invoked with a reference to an object that can be told 834 C{pauseProducing}, C{resumeProducing}, and C{stopProducing}. Then the 835 consumer's C{writeChunk} method will be called repeatedly with each 836 (channel, text) tuple in the log, starting with the very first. The 837 consumer will be notified with C{finish} when the log has been 838 exhausted (which can only happen when the log is finished). Note that 839 a small amount of data could be written via C{writeChunk} even after 840 C{pauseProducing} has been called. 841 842 To unsubscribe the consumer, use C{producer.stopProducing}."""
843 844 # once the log has finished, the following methods make sense. They can 845 # be called earlier, but they will only return the contents of the log up 846 # to the point at which they were called. You will lose items that are 847 # added later. Use C{subscribe} or C{subscribeConsumer} to avoid missing 848 # anything. 849
850 - def hasContents():
851 """Returns True if the LogFile still has contents available. Returns 852 False for logs that have been pruned. Clients should test this before 853 offering to show the contents of any log."""
854
855 - def getText():
856 """Return one big string with the contents of the Log. This merges 857 all non-header chunks together."""
858
859 - def readlines(channel=LOG_CHANNEL_STDOUT):
860 """Read lines from one channel of the logfile. This returns an 861 iterator that will provide single lines of text (including the 862 trailing newline). 863 """
864
865 - def getTextWithHeaders():
866 """Return one big string with the contents of the Log. This merges 867 all chunks (including headers) together."""
868
869 - def getChunks():
870 """Generate a list of (channel, text) tuples. 'channel' is a number, 871 0 for stdout, 1 for stderr, 2 for header. (note that stderr is merged 872 into stdout if PTYs are in use)."""
873
874 -class IStatusLogConsumer(Interface):
875 """I am an object which can be passed to IStatusLog.subscribeConsumer(). 876 I represent a target for writing the contents of an IStatusLog. This 877 differs from a regular IStatusReceiver in that it can pause the producer. 878 This makes it more suitable for use in streaming data over network 879 sockets, such as an HTTP request. Note that the consumer can only pause 880 the producer until it has caught up with all the old data. After that 881 point, C{pauseProducing} is ignored and all new output from the log is 882 sent directoy to the consumer.""" 883
884 - def registerProducer(producer, streaming):
885 """A producer is being hooked up to this consumer. The consumer only 886 has to handle a single producer. It should send .pauseProducing and 887 .resumeProducing messages to the producer when it wants to stop or 888 resume the flow of data. 'streaming' will be set to True because the 889 producer is always a PushProducer. 890 """
891
892 - def unregisterProducer():
893 """The previously-registered producer has been removed. No further 894 pauseProducing or resumeProducing calls should be made. The consumer 895 should delete its reference to the Producer so it can be released."""
896
897 - def writeChunk(chunk):
898 """A chunk (i.e. a tuple of (channel, text)) is being written to the 899 consumer."""
900
901 - def finish():
902 """The log has finished sending chunks to the consumer."""
903
904 -class IStatusReceiver(Interface):
905 """I am an object which can receive build status updates. I may be 906 subscribed to an IStatus, an IBuilderStatus, or an IBuildStatus.""" 907
908 - def buildsetSubmitted(buildset):
909 """A new BuildSet has been submitted to the buildmaster. 910 911 @type buildset: implementor of L{IBuildSetStatus} 912 """
913
914 - def requestSubmitted(request):
915 """A new BuildRequest has been submitted to the buildmaster. 916 917 @type request: implementor of L{IBuildRequestStatus} 918 """
919
920 - def requestCancelled(builder, request):
921 """A BuildRequest has been cancelled on the given Builder. 922 923 @type builder: L{buildbot.status.builder.BuilderStatus} 924 @type request: implementor of L{IBuildRequestStatus} 925 """
926
927 - def builderAdded(builderName, builder):
928 """ 929 A new Builder has just been added. This method may return an 930 IStatusReceiver (probably 'self') which will be subscribed to receive 931 builderChangedState and buildStarted/Finished events. 932 933 @type builderName: string 934 @type builder: L{buildbot.status.builder.BuilderStatus} 935 @rtype: implementor of L{IStatusReceiver} 936 """
937
938 - def builderChangedState(builderName, state):
939 """Builder 'builderName' has changed state. The possible values for 940 'state' are 'offline', 'idle', and 'building'."""
941
942 - def buildStarted(builderName, build):
943 """Builder 'builderName' has just started a build. The build is an 944 object which implements IBuildStatus, and can be queried for more 945 information. 946 947 This method may return an IStatusReceiver (it could even return 948 'self'). If it does so, stepStarted and stepFinished methods will be 949 invoked on the object for the steps of this one build. This is a 950 convenient way to subscribe to all build steps without missing any. 951 This receiver will automatically be unsubscribed when the build 952 finishes. 953 954 It can also return a tuple of (IStatusReceiver, interval), in which 955 case buildETAUpdate messages are sent ever 'interval' seconds, in 956 addition to the stepStarted and stepFinished messages."""
957
958 - def buildETAUpdate(build, ETA):
959 """This is a periodic update on the progress this Build has made 960 towards completion."""
961
962 - def changeAdded(change):
963 """A new Change was added to the ChangeMaster. By the time this event 964 is received, all schedulers have already received the change."""
965
966 - def stepStarted(build, step):
967 """A step has just started. 'step' is the IBuildStepStatus which 968 represents the step: it can be queried for more information. 969 970 This method may return an IStatusReceiver (it could even return 971 'self'). If it does so, logStarted and logFinished methods will be 972 invoked on the object for logs created by this one step. This 973 receiver will be automatically unsubscribed when the step finishes. 974 975 Alternatively, the method may return a tuple of an IStatusReceiver 976 and an integer named 'updateInterval'. In addition to 977 logStarted/logFinished messages, it will also receive stepETAUpdate 978 messages about every updateInterval seconds."""
979
980 - def stepTextChanged(build, step, text):
981 """The text for a step has been updated. 982 983 This is called when calling setText() on the step status, and 984 hands in the text list."""
985
986 - def stepText2Changed(build, step, text2):
987 """The text2 for a step has been updated. 988 989 This is called when calling setText2() on the step status, and 990 hands in text2 list."""
991
992 - def stepETAUpdate(build, step, ETA, expectations):
993 """This is a periodic update on the progress this Step has made 994 towards completion. It gets an ETA (in seconds from the present) of 995 when the step ought to be complete, and a list of expectation tuples 996 (as returned by IBuildStepStatus.getExpectations) with more detailed 997 information."""
998
999 - def logStarted(build, step, log):
1000 """A new Log has been started, probably because a step has just 1001 started running a shell command. 'log' is the IStatusLog object 1002 which can be queried for more information. 1003 1004 This method may return an IStatusReceiver (such as 'self'), in which 1005 case the target's logChunk method will be invoked as text is added to 1006 the logfile. This receiver will automatically be unsubsribed when the 1007 log finishes."""
1008
1009 - def logChunk(build, step, log, channel, text):
1010 """Some text has been added to this log. 'channel' is one of 1011 LOG_CHANNEL_STDOUT, LOG_CHANNEL_STDERR, or LOG_CHANNEL_HEADER, as 1012 defined in IStatusLog.getChunks."""
1013
1014 - def logFinished(build, step, log):
1015 """A Log has been closed."""
1016
1017 - def stepFinished(build, step, results):
1018 """A step has just finished. 'results' is the result tuple described 1019 in IBuildStepStatus.getResults."""
1020
1021 - def buildFinished(builderName, build, results):
1022 """ 1023 A build has just finished. 'results' is the result tuple described 1024 in L{IBuildStatus.getResults}. 1025 1026 @type builderName: string 1027 @type build: L{buildbot.status.builder.BuildStatus} 1028 @type results: tuple 1029 """
1030
1031 - def builderRemoved(builderName):
1032 """The Builder has been removed."""
1033
1034 - def slaveConnected(slaveName):
1035 """The slave has connected."""
1036
1037 - def slaveDisconnected(slaveName):
1038 """The slave has disconnected."""
1039
1040 -class IControl(Interface):
1041 - def addChange(change):
1042 """Add a change to all builders. Each Builder will decide for 1043 themselves whether the change is interesting or not, and may initiate 1044 a build as a result."""
1045
1046 - def submitBuildSet(builderNames, ss, reason, props=None, now=False):
1047 """Create a BuildSet, which will eventually cause a build of the 1048 given SourceStamp to be run on all of the named builders. This 1049 returns a BuildSetStatus object, which can be used to keep track of 1050 the builds that are performed. 1051 1052 If now=True, and the builder has no slave attached, NoSlaveError will 1053 be raised instead of queueing the request for later action."""
1054
1055 - def getBuilder(name):
1056 """Retrieve the IBuilderControl object for the given Builder."""
1057
1058 -class IBuilderControl(Interface):
1059 - def submitBuildRequest(ss, reason, props=None, now=False):
1060 """Create a BuildRequest, which will eventually cause a build of the 1061 given SourceStamp to be run on this builder. This returns a 1062 BuildRequestStatus object, which can be used to keep track of the 1063 builds that are performed. 1064 1065 If now=True, and I have no slave attached, NoSlaveError will be 1066 raised instead of queueing the request for later action."""
1067
1068 - def resubmitBuild(buildStatus, reason="<rebuild, no reason given>"):
1069 """Rebuild something we've already built before. This submits a 1070 BuildRequest to our Builder using the same SourceStamp as the earlier 1071 build. This has no effect (but may eventually raise an exception) if 1072 this Build has not yet finished."""
1073
1074 - def getPendingBuilds():
1075 """Return a list of L{IBuildRequestControl} objects for this Builder. 1076 Each one corresponds to a pending build that has not yet started (due 1077 to a scarcity of build slaves). These upcoming builds can be canceled 1078 through the control object."""
1079
1080 - def getBuild(number):
1081 """Attempt to return an IBuildControl object for the given build. 1082 Returns None if no such object is available. This will only work for 1083 the build that is currently in progress: once the build finishes, 1084 there is nothing to control anymore."""
1085
1086 - def ping():
1087 """Attempt to contact the slave and see if it is still alive. This 1088 returns a Deferred which fires with either True (the slave is still 1089 alive) or False (the slave did not respond). As a side effect, adds an 1090 event to this builder's column in the waterfall display containing the 1091 results of the ping. Note that this may not fail for a long time, it is 1092 implemented in terms of the timeout on the underlying TCP connection."""
1093 # TODO: this ought to live in ISlaveControl, maybe with disconnect() 1094 # or something. However the event that is emitted is most useful in 1095 # the Builder column, so it kinda fits here too. 1096
1097 -class IBuildRequestControl(Interface):
1098 - def subscribe(observer):
1099 """Register a callable that will be invoked (with a single 1100 IBuildControl object) for each Build that is created to satisfy this 1101 request. There may be multiple Builds created in an attempt to handle 1102 the request: they may be interrupted by the user or abandoned due to 1103 a lost slave. The last Build (the one which actually gets to run to 1104 completion) is said to 'satisfy' the BuildRequest. The observer will 1105 be called once for each of these Builds, both old and new."""
1106 - def unsubscribe(observer):
1107 """Unregister the callable that was registered with subscribe()."""
1108 - def cancel():
1109 """Remove the build from the pending queue. Has no effect if the 1110 build has already been started."""
1111
1112 -class IBuildControl(Interface):
1113 - def getStatus():
1114 """Return an IBuildStatus object for the Build that I control."""
1115 - def stopBuild(reason="<no reason given>"):
1116 """Halt the build. This has no effect if the build has already 1117 finished."""
1118
1119 -class ILogFile(Interface):
1120 """This is the internal interface to a LogFile, used by the BuildStep to 1121 write data into the log. 1122 """
1123 - def addStdout(data):
1124 pass
1125 - def addStderr(data):
1126 pass
1127 - def addHeader(data):
1128 pass
1129 - def finish():
1130 """The process that is feeding the log file has finished, and no 1131 further data will be added. This closes the logfile."""
1132
1133 -class ILogObserver(Interface):
1134 """Objects which provide this interface can be used in a BuildStep to 1135 watch the output of a LogFile and parse it incrementally. 1136 """ 1137 1138 # internal methods
1139 - def setStep(step):
1140 pass
1141 - def setLog(log):
1142 pass
1143 1144 # methods called by the LogFile
1145 - def logChunk(build, step, log, channel, text):
1146 pass
1147
1148 -class IBuildSlave(Interface):
1149 # this is a marker interface for the BuildSlave class 1150 pass
1151
1152 -class ILatentBuildSlave(IBuildSlave):
1153 """A build slave that is not always running, but can run when requested. 1154 """ 1155 substantiated = Attribute('Substantiated', 1156 'Whether the latent build slave is currently ' 1157 'substantiated with a real instance.') 1158
1159 - def substantiate():
1160 """Request that the slave substantiate with a real instance. 1161 1162 Returns a deferred that will callback when a real instance has 1163 attached."""
1164 1165 # there is an insubstantiate too, but that is not used externally ATM. 1166
1167 - def buildStarted(sb):
1168 """Inform the latent build slave that a build has started. 1169 1170 ``sb`` is a LatentSlaveBuilder as defined in buildslave.py. The sb 1171 is the one for whom the build started. 1172 """
1173
1174 - def buildFinished(sb):
1175 """Inform the latent build slave that a build has finished. 1176 1177 ``sb`` is a LatentSlaveBuilder as defined in buildslave.py. The sb 1178 is the one for whom the build finished. 1179 """
1180