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

Source Code for Module buildbot.interfaces

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