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