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