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